Graphics 自动生成UV坐标的算法

Graphics 自动生成UV坐标的算法,graphics,3d,uv-mapping,Graphics,3d,Uv Mapping,我正在为我的一个工具编写我自己的uv编辑器,我正在尝试为投影合并尽可能多的算法。我需要使用任意网格,并为每个顶点创建uv坐标 到目前为止,我有平面和最小二乘共形映射 我想合并更多,如三平面、圆柱、球面,但我很难找到执行算法所需的信息。三个平面似乎可以生成颜色,但我需要在UV坐标中获取所有内容 非常感谢您的帮助 您应该从siggraph课程开始,然后查看引用的论文,了解您正在实施的算法的详细信息Tri-Plana 忘了它吧:它不是一个投影算法(一个给你UV坐标的算法),你无法从中获得UV坐标。这是

我正在为我的一个工具编写我自己的uv编辑器,我正在尝试为投影合并尽可能多的算法。我需要使用任意网格,并为每个顶点创建uv坐标

到目前为止,我有平面和最小二乘共形映射

我想合并更多,如三平面、圆柱、球面,但我很难找到执行算法所需的信息。三个平面似乎可以生成颜色,但我需要在UV坐标中获取所有内容


非常感谢您的帮助

您应该从siggraph课程开始,然后查看引用的论文,了解您正在实施的算法的详细信息

Tri-Plana

忘了它吧:它不是一个投影算法(一个给你UV坐标的算法),你无法从中获得UV坐标。这是一种渲染算法,通过混合使用每个X-Y-Z平面投影分别获得的颜色,可以获得颜色

圆柱形、球形

与平面一样,这些都是非常简单的投影算法,直接从XYZ值获得UV值,而不考虑与其他顶点的连接

  • 对于圆柱形:将(x,y,z)转换为(ρ,φ,z),并用作UV坐标u=φ和v=z
  • 对于球形:在(r,θ,φ)中转换(x,y,z),并用作UV坐标u=θ和v=φ
当然,您可以切换X、Y和Z的角色以使用不同的轴进行投影,或者执行一些平移/旋转/缩放以获得更多控制(与您可以控制用于平面投影的平面的大小和方向的方式相同)

立方

首先,您需要确定将网格的每个面指定给哪个“投影面”。我将投影面命名为X、-X、Y、-Y、Z和-Z,如下图所示(其中我假设X、Y和Z轴分别具有红色、绿色和蓝色):

为此,您只需找到法线(nx,ny,nz)的哪个坐标具有最大的绝对值,并将其指定给对应于该轴和符号的面。例如:

  • 如果n=(0.8,0.5,0.3),则相应的面为X(|nx |最大,nx为正)
  • 如果n=(0.3,0.8,0.5),则相应的面为Y(| ny |最大,ny为正)
  • 如果n=(0.3,-0.8,0.5),则相应的面为-Y(| ny |最大,ny为负)
然后,一旦知道将网格的每个面指定给哪个投影面,就可以将相应的平面投影应用于该面周围的顶点以获得临时值(u_temp,v_temp)∈ [0,1]x[0,1]

下一步是转换此值uv_temp∈ [0,1]x[0,1]转换为包含在上面图像a中所示较小正方形中的值uv。例如,如果应用了投影“X”,则需要uv∈ [2/3,3/3]x[2/4,3/4],然后你会做:

u = 2./3. + u_temp/3.;
v = 2./4. + v_temp/4.; 
最后,最后一步是不要忘记复制属于具有不同平面投影(图片上不同颜色之间的边界)的两个面的UV顶点。事实上,网格的某些顶点可以(并且在大多数情况下应该)在UV贴图中的多个位置进行分割,以获得良好的效果。

立方体贴图

基于(rx,ry,rz)向量的标准方法是首先在表中查找一些值。这些值用于每个顶点的(s,t)(或(u,v))纹理坐标

首先找到反射向量 R=2(N点V)N-V,其中V=顶点,N=法线,R反射向量(rx,ry,rz)

一旦为sc、tc和ma赋值,则可使用以下公式计算该面的(s、t)坐标

if((rx >= ry) && (rx  >= rz)) 
{ 
sc = -rz; 
tc = -ry; 
ma = fabs(rx);  //absolute value
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+rx (" << s << "," << t << ")" << endl; 
} 

  if((rx <= ry) && (rx  <= rz)) 
{ 
sc = +rz; 
tc = -ry; 
ma = fabs(rx); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-rx (" << s << "," << t << ")" << endl; 
} 

if((ry >= rz) && (ry >= rx)) 
{ 
sc = +rx; 
tc = +rz; 
ma = fabs(ry); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+ry (" << s << "," << t << ")" << endl; 
} 

if((ry <= rz) && (ry <= rx)) 
{ 
sc = +rx; 
tc = -rz; 
ma = fabs(ry); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-ry (" << s << "," << t << ")" << endl; 
} 

if((rz >= ry) && (rz >= rx)) 
{ 
sc = +rx; 
tc = -ry; 
ma = fabs(rz); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+rz (" << s << "," << t << ")" << endl; 
} 

if((rz <= ry) && (rz <= rx)) 
{ 
sc = -rx; 
tc = -ry; 
ma = fabs(rz); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-rz (" << s << "," << t << ")" << endl; 
} 
if((rx>=ry)和&(rx>=rz))
{ 
sc=-rz;
tc=-ry;
ma=fabs(rx);//绝对值
s=((sc/ma)+1)/2;
t=((tc/ma)+1)/2;

如果可能的话,我可以寻找一套更简洁的“伪代码”/算法,简单的。例如,三平面,用于将颜色转换为UV。我看不到这一点。这非常有用!我唯一想知道的另一个是“立方体投影”。你如何知道基于法线,将其分配到哪个面以及UV放置在何处?就像这样:非常感谢,我对法线有这种怀疑,但我不是100%确定。最后一个问题,我将标记为答案,非常感谢你的帮助。当我在笛卡尔坐标系和球面坐标系之间转换时,偶尔会得到一个phi(outphi=atan2(y,x)),其中y和x都是0。如何对此进行更正?笛卡尔球面outrho=sqrt(xx+yy+zz);outphi=atan2(z,(sqrt(xx+yy));outz=atan2(y,x);笛卡尔圆柱outrho=sqrt(xx+y*y);outphi=atan2(y,x);outz=z;在x=y=0的情况下,则表示您位于球体的一个极点,如果z>0,则可以位于顶部水平线的任何位置,如果z设置为=0,则位于底部水平线的任何位置,我得到(有一条清晰的线穿过这些极点).有没有更好的办法演那部分?@MaryEllenBench发生这种事是因为你没有“剪”phi=0的网格。如果球体的赤道由5个U值分别为0、0.2、0.4、0.6和0.8的顶点组成,则链接0.8到0的最后一个面将按向后顺序覆盖整个纹理,从而导致所看到的不连续性。这就是为什么必须复制某些顶点,在这种情况下是phi=0的顶点,因此现在有6个UV顶点,分别位于0、0.2、0.4、0.6、0.8和1。这可能很难实现,但您应该能够自己解决,它肯定超出了SO答案的范围;-)您也可以查看由CGAL guysI实现的,但最终放弃了使用它,bec
if((rx >= ry) && (rx  >= rz)) 
{ 
sc = -rz; 
tc = -ry; 
ma = fabs(rx);  //absolute value
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+rx (" << s << "," << t << ")" << endl; 
} 

  if((rx <= ry) && (rx  <= rz)) 
{ 
sc = +rz; 
tc = -ry; 
ma = fabs(rx); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-rx (" << s << "," << t << ")" << endl; 
} 

if((ry >= rz) && (ry >= rx)) 
{ 
sc = +rx; 
tc = +rz; 
ma = fabs(ry); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+ry (" << s << "," << t << ")" << endl; 
} 

if((ry <= rz) && (ry <= rx)) 
{ 
sc = +rx; 
tc = -rz; 
ma = fabs(ry); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-ry (" << s << "," << t << ")" << endl; 
} 

if((rz >= ry) && (rz >= rx)) 
{ 
sc = +rx; 
tc = -ry; 
ma = fabs(rz); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "+rz (" << s << "," << t << ")" << endl; 
} 

if((rz <= ry) && (rz <= rx)) 
{ 
sc = -rx; 
tc = -ry; 
ma = fabs(rz); 
s = ((sc/ma) + 1) / 2; 
t = ((tc/ma) + 1) / 2; 

cout << "-rz (" << s << "," << t << ")" << endl; 
}