您的位置 首页 > 德语词汇

coordinates是什么意思,coordinates的意思翻译、用法、同(重心坐标简明教程)

大家好,关于coordinates是什么意思,coordinates的意思翻译、用法、同很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于重心坐标简明教程的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!

coordinates是什么意思,coordinates的意思翻译、用法、同(重心坐标简明教程)

重心坐标(BarycentricCoordinates)在CG中尤为重要。它们有一些功能,是M?ller-Trumbore提出的下一个射线三角形相交算法的关键,该算法将在下一章中研究。本章最后将讨论如何在CG中使用重心坐标。

NSDT工具推荐:Three.jsAI纹理开发包-YOLO合成数据生成器-GLTF/GLB在线编辑-3D模型格式在线转换-可编程3D场景编辑器-REVIT导出3D模型插件-3D模型语义搜索引擎

图1:重心坐标可以看作是子三角形CAP(u)、ABP(v)和BCP(w)在三角形ABC上的面积,这就是为什么它们也被称为面积坐标。

重心坐标可以用三个标量来表示位于三角形上的任意点的位置。该点的位置包括三角形内的任意位置、三角形的任意三个边上的任意位置、或者三个三角形的顶点本身中的任意一个。为了使用重心坐标计算该点的位置,我们使用以下方程(1):

其中A、B和C是三角形的顶点,u、v和w是重心坐标,三个实数满足u+v+w=1。请注意,从其中两个坐标我们可以找到第三个坐标:w=1-u-v。由此我们可以确定u+v<=1(稍后我们将使用这个简单但重要的属性)。

方程1定义了点P在由顶点A、B和C形成的三角形平面上的位置。如果满足条件0<=u,v,w<=1,则该点位于三角形(A,B,C)内。如果任何一个坐标小于0或大于1,则该点位于三角形之外。如果其中任何一个为零,则P位于连接三角形顶点的直线之一上。

你还可以简单地使用两个坐标(假设u和v)来表示点P在由原点(A)和边AB和AC定义的二维坐标系中的坐标(非常类似于在正交坐标系中表示2D点)由x轴和y轴定义的二维坐标系。在我们的例子中唯一的区别是AB和AC不一定正交,并且该坐标系的原点是A)。可以用方程P=A+u*AB+v*AC定义三角形内的位置,其中u>=0,v>=0,u+v<=1。这个方程可以理解为:

从A开始,向AB方向移动一点,然后向AC方向移动一点,你就会找到P。

现在,如果建立这个方程,你可以写:

该方程与方程1类似,除了当w=1-u-v时,得到公式P=w*A+u*B+v*C而不是P=u*A+v*B+w*C。

重心坐标也称为面积坐标(ArealCoordinates)。尽管不太常用,但该术语表示坐标u、v和w与P定义的三个子三角形的面积、位于三角形上的点以及三角形的顶点(A、B、C)成正比。这三个子三角形分别表示为ABP、BCP和CAP(见图1)。

这引出了用于计算重心坐标的公式:

在本课的其余部分中,我们将假设u使我们沿着边AB移动(如果u=1则P=B),v使我们沿着边AC移动(如果v=1则P=C)。这就是为什么我们会使用子三角形CAP的面积来计算u,使用子三角形ABP的面积来计算v。这是CG编程社区中大多数人遵循的约定如何使用重心坐标来插值顶点数据,你将有一个直观的示例(图3)以更好地理解这一点。

图2:为了计算三角形的面积,我们从计算平行四边形的公式开始(底乘以高度H)。为了计算H,我们将向量AC的长度乘以sin(theta)

计算三角形的面积很简单。如果复制三角形并沿其最长边镜像它,你将得到一个平行四边形。要计算平行四边形的面积,只需计算其底和边,然后将这两个数字乘以sin(theta),其中theta是向量AB和AC所对的角度(图2)。为了创建平行四边形,我们使用了两个三角形,因此一个三角形的面积是平行四边形面积的一半。

有了这个,计算u和v就变得很容易,w是根据u和v计算出来的,如前所述:

为了让事情变得更简单,我们可以利用以下事实以找到交点P:子三角形ABP、BCP和CAP的面积与我们在上一章中计算的叉积的长度成正比。这是叉积的性质之一:叉积的大小可以解释为平行四边形的面积。因此,我们不需要显式计算前面的公式,其中包括了sin(theta)的计算。我们可以简单地使用:

请注意,在数学术语中,双杠符号(||||)表示“长度”(第4课)。换句话说,我们需要计算叉积(C-B)x(P-B)产生的向量的长度。我们知道如何计算两个向量的叉积和向量的长度,因此我们现在拥有计算交点的重心坐标所需的一切:

boolrayTriangleIntersect(\nconstVec3f&orig,constVec3f&dir,\nconstVec3f&v0,constVec3f&v1,constVec3f&v2,\nfloat&t,float&u,float&v)\n{\n//computetheplane'snormal\nVec3fv0v1=v1-v0;\nVec3fv0v2=v2-v0;\n//noneedtonormalize\nVec3fN=v0v1.crossProduct(v0v2);//N\nfloatarea=N.length()/2;//areaofthetriangle\n\n...\n\n//Step2:inside-outsidetest\nVec3fC;//vectorperpendiculartotriangle'splane\n\n//edge0\n...\n\n//edge1\nVec3fedge1=v2-v1;\nVec3fvp1=P-v1;\nC=edge1.crossProduct(vp1);\nu=(C.length()/2)/area;\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside\n\n//edge2\nVec3fedge2=v0-v2;\nVec3fvp2=P-v2;\nC=edge2.crossProduct(vp2);\nv=(C.length()/2)/area;\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside;\n\nreturntrue;//thisrayhitsthetriangle\n}

平面法线不应标准化,因为我们使用向量的长度来计算三角形面积。

重心坐标在着色中最有用。三角形是一个平坦的表面,我们可以将任何附加信息或数据(点、颜色、向量等)与其每个顶点相关联。该信息通常称为顶点数据。例如,假设你希望顶点A为红色,顶点B为绿色,顶点C为蓝色:

图3:重心坐标可用于在命中点位置插入顶点数据。例如,在本例中,我们使用顶点颜色计算P处的颜色。

如果交点与三角形的顶点之一重合,则交点处对象的颜色就是与该顶点关联的颜色。够简单的。问题是当光线与三角形在其他任何地方(无论是在边上还是在三角形内部)相交时会发生什么?如果使用重心坐标通过三角形顶点计算位于三角形上的点的位置,我们可以以相同的方式插入在三角形顶点定义的任何其他数据(例如颜色)。换句话说,重心坐标用于在三角形表面上插入顶点数据(该技术可以应用于任何数据类型、浮点数、颜色等)。该技术对于着色非常有用,例如在交点处插值法线。对象的法线可以在每个面或顶点的基础上定义(我们所说的面法线或顶点法线)。如果它们是按顶点定义的,我们可以使用这种插值技术来模拟三角形表面的平滑阴影,即使三角形“数学上”是平坦的(命中点处的法线是顶点法线的组合,因此如果顶点法线彼此不同,该插值的结果在三角形表面上不是恒定的):

//vertexposition\nVec3ftriVertex[3]={{-3,-3,5},{0,3,5},{3,-3,5}};\n//vertexdata\nVec3ftriColor[3]={{1,0,0},{0,1,0},{0,0,1}};\nif(rayTriangleIntersect(...)){\n//computepixelcolor\n//col=w*col0+u*col1+v*col2wherew=1-u-v\nVec3fPhitColor=u*triColor[0]+v*triColor[1]+(1-u-v)*triColor[2];\n}

重心坐标也用于计算纹理坐标(我们将在纹理课程中研究这一点)。

你会注意到,在我们到目前为止描述的算法版本中,我们使用AB和AP的叉积以及CA和CP的叉积来计算u和v。但是如果查看代码你还会再次注意到,我们已经为内部-外部测试计算了这些叉积。它们被用来计算P是在edge0(ABxAP)和edge2(CAxCP)的右侧还是左侧的结果。当然,第一个优化包括重用这些值的结果。另请注意(等式2):

不需要计算三角形面积,因为三角形ABP和三角形ABC之间的比率与平行四边形ABP(是三角形ABP面积的两倍)和平行四边形ABC(是三角形ABP面积的两倍)之间的比率相同,因此我们也可以避免除以2。代码变为:

boolrayTriangleIntersect(\nconstVec3f&orig,constVec3f&dir,\nconstVec3f&v0,constVec3f&v1,constVec3f&v2,\nfloat&t,float&u,float&v)\n{\n//computetheplane'snormal\nVec3fv0v1=v1-v0;\nVec3fv0v2=v2-v0;\n//noneedtonormalize\nVec3fN=v0v1.crossProduct(v0v2);//N\nfloatarea2=N.length();\n\n//Step1:findingP\n\n//checkiftherayandplaneareparallel.\nfloatNdotRayDirection=N.dotProduct(dir);\nif(fabs(NdotRayDirection)<kEpsilon)//almost0\nreturnfalse;//theyareparallelsotheydon'tintersect!\n\n//computedparameterusingequation2\nfloatd=-N.dotProduct(v0);\n\n//computet(equation3)\nt=-(N.dotProduct(orig)+d)/NdotRayDirection;\n//checkifthetriangleisbehindtheray\nif(t<0)returnfalse;//thetriangleisbehind\n\n//computetheintersectionpointusingequation1\nVec3fP=orig+t*dir;\n\n//Step2:inside-outsidetest\nVec3fC;//vectorperpendiculartotriangle'splane\n\n//edge0\nVec3fedge0=v1-v0;\nVec3fvp0=P-v0;\nC=edge0.crossProduct(vp0);\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside\n\n//edge1\nVec3fedge1=v2-v1;\nVec3fvp1=P-v1;\nC=edge1.crossProduct(vp1);\nu=C.length()/area2;\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside\n\n//edge2\nVec3fedge2=v0-v2;\nVec3fvp2=P-v2;\nC=edge2.crossProduct(vp2);\nv=C.length()/area2;\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside;\n\nreturntrue;//thisrayhitsthetriangle\n}

最后,我们可以证明(方程3):

首先注意N=ABxAC,因此上式可重写为:

我们现在需要证明这个方程是正确的。请记住几何课程中,两个向量的点积向量可以解释为:

其中角度theta是两个向量A和B的夹角,||A||和||B||分别是向量A和B的长度。我们还知道,当两个向量A和B共线(它们指向同一方向)时,对角为0,因此cos(0)=1。我们可以将分子重写为:

由于ABxAP=A并且ABxAC=N=B,那么:

在这种情况下,A和B也是共线的,因为它们是由共面向量构造的。最后,我们可以将结果替换为等式3中的分子和分母:

如果我们将A替换回ABxAP同时将B替换回ABxAC,就得到:

这是我们例程代码的最终版本,其中包括计算重心坐标的优化方法:

boolrayTriangleIntersect(\nconstVec3f&orig,constVec3f&dir,\nconstVec3f&v0,constVec3f&v1,constVec3f&v2,\nfloat&t,float&u,float&v)\n{\n//computetheplane'snormal\nVec3fv0v1=v1-v0;\nVec3fv0v2=v2-v0;\n//noneedtonormalize\nVec3fN=v0v1.crossProduct(v0v2);//N\nfloatdenom=N.dotProduct(N);\n\n//Step1:findingP\n\n//checkiftherayandplaneareparallel.\nfloatNdotRayDirection=N.dotProduct(dir);\nif(fabs(NdotRayDirection)<kEpsilon)//almost0\nreturnfalse;//theyareparallelsotheydon'tintersect!\n\n//computedparameterusingequation2\nfloatd=-N.dotProduct(v0);\n\n//computet(equation3)\nt=-(N.dotProduct(orig)+d)/NdotRayDirection;\n//checkifthetriangleisbehindtheray\nif(t<0)returnfalse;//thetriangleisbehind\n\n//computetheintersectionpointusingequation1\nVec3fP=orig+t*dir;\n\n//Step2:inside-outsidetest\nVec3fC;//vectorperpendiculartotriangle'splane\n\n//edge0\nVec3fedge0=v1-v0;\nVec3fvp0=P-v0;\nC=edge0.crossProduct(vp0);\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside\n\n//edge1\nVec3fedge1=v2-v1;\nVec3fvp1=P-v1;\nC=edge1.crossProduct(vp1);\nif((u=N.dotProduct(C))<0)returnfalse;//Pisontherightside\n\n//edge2\nVec3fedge2=v0-v2;\nVec3fvp2=P-v2;\nC=edge2.crossProduct(vp2);\nif((v=N.dotProduct(C))<0)returnfalse;//Pisontherightside;\n\nu/=denom;\nv/=denom;\n\nreturntrue;//thisrayhitsthetriangle\n}5、源代码

在这个版本的射线-三角形相交方法中,我们实现了第3章中描述的技术来计算命中点坐标,以及本章中描述的方法来计算相交点的重心坐标。当射线击中三角形时,可以选择使用重心坐标插值三种颜色或直接可视化原始坐标(第94/95行)。

...\nconstexprfloatkEpsilon=1e-8;\n\ninline\nfloatdeg2rad(constfloat°)\n{returndeg*M_PI/180;}\n\ninline\nfloatclamp(constfloat&lo,constfloat&hi,constfloat&v)\n{returnstd::max(lo,std::min(hi,v));}\n\nboolrayTriangleIntersect(\nconstVec3f&orig,constVec3f&dir,\nconstVec3f&v0,constVec3f&v1,constVec3f&v2,\nfloat&t,float&u,float&v)\n{\n//computetheplane'snormal\nVec3fv0v1=v1-v0;\nVec3fv0v2=v2-v0;\n//noneedtonormalize\nVec3fN=v0v1.crossProduct(v0v2);//N\nfloatdenom=N.dotProduct(N);\n\n//Step1:findingP\n\n//checkiftherayandplaneareparallel.\nfloatNdotRayDirection=N.dotProduct(dir);\nif(fabs(NdotRayDirection)<kEpsilon)//almost0\nreturnfalse;//theyareparallelsotheydon'tintersect!\n\n//computedparameterusingequation2\nfloatd=-N.dotProduct(v0);\n\n//computet(equation3)\nt=-(N.dotProduct(orig)+d)/NdotRayDirection;\n//checkifthetriangleisbehindtheray\nif(t<0)returnfalse;//thetriangleisbehind\n\n//computetheintersectionpointusingequation1\nVec3fP=orig+t*dir;\n\n//Step2:inside-outsidetest\nVec3fC;//vectorperpendiculartotriangle'splane\n\n//edge0\nVec3fedge0=v1-v0;\nVec3fvp0=P-v0;\nC=edge0.crossProduct(vp0);\nif(N.dotProduct(C)<0)returnfalse;//Pisontherightside\n\n//edge1\nVec3fedge1=v2-v1;\nVec3fvp1=P-v1;\nC=edge1.crossProduct(vp1);\nif((u=N.dotProduct(C))<0)returnfalse;//Pisontherightside\n\n//edge2\nVec3fedge2=v0-v2;\nVec3fvp2=P-v2;\nC=edge2.crossProduct(vp2);\nif((v=N.dotProduct(C))<0)returnfalse;//Pisontherightside;\n\nu/=denom;\nv/=denom;\n\nreturntrue;//thisrayhitsthetriangle\n}\n\nintmain(intargc,char**argv)\n{\nVec3fv0(-1,-1,-5);\nVec3fv1(1,-1,-5);\nVec3fv2(0,1,-5);\n\nconstuint32_twidth=640;\nconstuint32_theight=480;\nVec3fcols[3]={{0.6,0.4,0.1},{0.1,0.5,0.3},{0.1,0.3,0.7}};\nVec3f*framebuffer=newVec3f[width*height];\nVec3f*pix=framebuffer;\nfloatfov=51.52;\nfloatscale=tan(deg2rad(fov*0.5));\nfloatimageAspectRatio=width/(float)height;\nVec3forig(0);\nfor(uint32_tj=0;j<height;++j){\nfor(uint32_ti=0;i<width;++i){\n//computeprimaryray\nfloatx=(2*(i+0.5)/(float)width-1)*imageAspectRatio*scale;\nfloaty=(1-2*(j+0.5)/(float)height)*scale;\nVec3fdir(x,y,-1);\n//cameraToWorld.multDirMatrix(Vec3f(x,y,-1),dir);\ndir.normalize();\nfloatt,u,v;\nif(rayTriangleIntersect(orig,dir,v0,v1,v2,t,u,v)){\n*pix=u*cols[0]+v*cols[1]+(1-u-v)*cols[2];\n//*pix=Vec3f(u,v,1-u-v);\n}\npix++;\n}\n}\n\n//SavetheresulttoaPPMimage(keeptheseflagsifyouareonWindows)\n...\n\nreturn0;\n}

下图显示了程序的输出:

原文链接:重心坐标简明教程-BimAnt

END,本文到此结束,如果可以帮助到大家,还望关注本站哦!

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023