代码之家  ›  专栏  ›  技术社区  ›  Dead account

顶点着色和计算光矢量效果

  •  2
  • Dead account  · 技术社区  · 15 年前

    给定一个由三个三维点定义的三角形顶点,如何计算它与给定点之间的角度。

    class Point3D
    {
        double x, y, z;
    }
    
    class Vertex
    {
         Point3D P1, P2, P3;
    }
    
    Point3D LightPoint;
    

    http://www.ianquigley.com/iq/RandomImages/vextor.png

    红灯亮。蓝点-显示曲面法线的三角形。

    3 回复  |  直到 15 年前
        1
  •  5
  •   KeithS    12 年前

    好了,这是。。。

    你有点A,B,和C,每个点都有坐标x,y,和z。你想要法线的长度,就像Matias说的,这样你就可以计算出你的点和法线原点之间的向量与法线本身的夹角。它可能会帮助你意识到你的图像对于我们的计算是有误导性的;法线(蓝线)应该从三角形的一个顶点发出。要把你的点变成一个向量,它必须去某个地方,你只知道顶点的点(虽然你可以在三角形内插值任何点,但整个顶点着色点是不必的)。

    这个系统.Windows.Media.Media3D命名空间有一个Vector3D结构,您可以使用它,而且非常方便,同一命名空间中的Point3D有一个Subtract()函数,该函数返回Vector3D:

    Vector3D vectorAB = pointB.Subtract(pointA);
    Vector3D vectorAC = pointC.Subtract(pointA);
    

    现在,法线是两个向量的叉积。使用以下公式:

    v1 x v2=[y1*z2-y2*z1,z1*x2-z2*x1,x1*y2-x2*y1]

    这是基于矩阵的数学,你不必严格知道如何实现它。矩阵中的三项是法向量的X、Y和Z。幸运的是,如果您使用Media3D名称空间,Vector3D结构有一个CrossProduct()方法,可以为您执行以下操作:

    Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC);
    

    现在,你需要第三个向量,在光点和a之间:

    Vector3D vectorLight = PointA.Subtract(LightPoint);
    

    这是光从你的光源到达A点的方向。

    |v |=平方米(x^2+y^2+z^2)

    v1*v2=x1*x2+y1*y2+z1*z2

    或者,如果您使用的是Media3D,则Vector3D具有Length属性和DotProduct静态方法:

    double lengthLight = vectorLight.Length;
    double lengthNormal = vectorNormal.Length;
    double dotProduct = Vector3D.DotProduct(vectorNormal, vectorLight);
    

    v1*v2=| v1 | | v2 | cos(θ)

    重新排列和替换变量名:

    double theta = arccos(dotProduct/(lengthNormal*lengthLight))
    

    或者,如果你足够聪明,可以使用Media3D对象,那么忘掉所有长度和点积的东西:

    double theta = Vector3D.AngleBetween(vectorNormal, vectorLight);
    

    这个故事的寓意是,除非有充分的理由,否则使用框架提供的内容;使用Media3D名称空间,所有向量代数都消失了,你可以在5行容易阅读的行中找到答案[我编辑了这个,添加了我使用的代码--Ian]:

    Vector3D vectorAB = Point3D.Subtract(pointB, pointA);
    Vector3D vectorAC = Point3D.Subtract(pointC, pointA);
    Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC);
    Vector3D vectorLight = Point3D.Subtract(pointA, LightPoint);
    
    double lengthLight = light.Length;
    double lengthNormal = norm.Length;
    double dotProduct = Vector3D.DotProduct(norm, light);
    double theta = Math.Acos(dotProduct / (lengthNormal * lengthLight));
    
    // Convert to intensity between 0..255 range for 'Color.FromArgb(... 
    //int intensity = (120 + (Math.Cos(theta) * 90));
    
        2
  •  1
  •   Dr. Snoopy    15 年前

    要获得角度,使用法线和光点之间的点积。记住点(a,b)=| a | | b |*cos(θ),所以既然你可以计算两者的长度,你就可以得到θ(它们之间的角度)。

        3
  •  0
  •   Dan Bryant    15 年前

    只有切线相关,但大多数图形系统还允许曲面法线插值,其中每个顶点都有一个关联的法线。然后从顶点法线插值给定U,V处的有效法线。这允许更平滑的着色和更好的“曲率”表示,而不必依赖于大量的三角形。许多系统使用“凹凸贴图”进行类似的操作,在法线中引入扰动,并在不建模单个小面片的情况下获得纹理感。

    现在您可以计算插值法线和光向量之间的角度,正如其他人已经描述的那样。

    另一个关注点是考虑是否有环境光源。如果您可以假设点光源无限远(对于像地球这样的小表面上的直射阳光这样的光源,实际上是真的),那么您就可以省去计算矢量差的所有麻烦,只需假设光源的入射角是恒定的。现在你的点积有一个恒定的光矢量。