6

有什么区别,如何让 WebGL 的 sin 产生与 Math.sin 相同的结果?

编辑: 我的顶点着色器中有一些代码(这不是所有代码),它计算球体周围的斐波那契点,并且应该将顶点放置在这个新点上:

attribute float index;

   float inc = 3.141592653589793238462643383279 * (3.0 - sqrt(5.0));
   float off = 2.0 / 2500000;
   float yy = index * off - 1.0 + (off / 2.0);
   float rr = sqrt(1.0 - yy * yy);
   float phi = index* inc;
   vec3 fibPoint = vec3(cos(phi) * rr, yy, sin(phi) * rr);

这不起作用,它给了我这样尴尬的顶点位置:http: //i.imgur.com/Z1crisy.png

如果我使用 JavaScript 的 Math.sin 和 Math.cos 在 CPU 上计算 cos(phi) 和 sin(phi) 并将它们作为属性放入,如下所示:

attribute float index;
attribute float sinphi;
attribute float cosphi;

   float inc = 3.141592653589793238462643383279 * (3.0 - sqrt(5.0));
   float off = 2.0 / 2500000;
   float yy = index * off - 1.0 + (off / 2.0);
   float rr = sqrt(1.0 - yy * yy);
   float phi = index* inc;
   vec3 fibPoint = vec3(cosphi * rr, yy, sinphi * rr);

我得到一个像这样的精细斐波那契分布:http: //i.imgur.com/DeRoXkL.png

关于为什么的任何想法,显然 GLSL 和 Javascript 之间的 cos/sin 函数似乎存在一些差异?Phi 可以变成相当大的数字,例如“5476389.695241543”这样的大数。也许这对于 GLSL 的精度来说太大了?

编辑2:

vertexShader: [
    "attribute float index;",
    "attribute float cosphi;",
    "attribute float sinphi;",
    "attribute float displacementType;",
    "uniform vec3 faceCorner;",
    "uniform vec3 faceNormal;",
    "uniform vec3 faceCenter;",
    "varying vec2 vTexCoord;",

    "void main()",
    "{",

          "vTexCoord = uv;",

          // find fibonacci distribution of points on sphere
          "float inc = 3.141592653589793238462643383279 * 0.7639320225002102;",
          "float off = 0.0000008;",

          "float yy = index* off - 1.0 + (off / 2.0);",
          "float rr = sqrt(1.0 - yy * yy);",
          "float phi = index* inc;",
          "vec3 fibPoint = vec3(cos(phi) * rr * -1.0, yy, sin(phi) * rr * -1.0);",

          // intersecting face
          "vec3 normalizedFaceNormal = normalize(faceNormal);",
          "float planeConstant = - dot(faceCorner, normalizedFaceNormal);", 
          "float denominator = dot(normalizedFaceNormal, fibPoint);",
          "float distanceToPlane = - planeConstant / denominator;",

          "vec3 intersectPoint = normalize(fibPoint) * distanceToPlane;",
          "intersectPoint = faceCenter;",

          // displacement
          "float buildingRadius = 3.0;",                
          "vec3 newPosition = position;",
          "vec3 cornerVec = normalize(faceCorner - intersectPoint) * buildingRadius;",

            // ground vertices
           "if(displacementType == 0.0){",
                "newPosition = intersectPoint + cornerVec;",
           "} else if(displacementType == 1.0){",
                "newPosition = cross(cornerVec, normalizedFaceNormal);",    
                "newPosition = intersectPoint + newPosition;",
            "} else if(displacementType == 2.0){",
                "newPosition = intersectPoint - cornerVec;",
           "} else if(displacementType == 3.0){",
                "newPosition = cross(normalizedFaceNormal, cornerVec);",    
                "newPosition = intersectPoint + newPosition;",

           "} else {",
                  // roof vertices
               "vec3 corner0 = intersectPoint + cornerVec;",
               "vec3 corner1 = intersectPoint + cross(cornerVec, normalizedFaceNormal);",

                "float UVdistance = length(corner0 - corner1);",
                "float buildingHeight = UVdistance * 2.0;",

                "vec3 roofCentroid = intersectPoint + normalizedFaceNormal * (-buildingHeight);",

                "if(displacementType == 4.0){",
                    "newPosition = roofCentroid + cornerVec;",
                "} else if(displacementType == 5.0){",
                    "newPosition = cross(cornerVec, normalizedFaceNormal);",
                    "newPosition = roofCentroid + newPosition;",
                "} else if(displacementType == 6.0){",
                    "newPosition = roofCentroid - cornerVec;",
                "} else {",
                    "newPosition = cross(normalizedFaceNormal, cornerVec);",    
                    "newPosition = roofCentroid + newPosition;",
                "}",
            "}",

            "gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition.xyz, 1.0);",
    "}"
].join("\n"),

所以这个给出了错误的顶点位置,如果我将“cos(phi)”和“sin(phi)”更改为 cosphi 和 sinphi,它们是由 javascript 的 Math.sin(phi) 和 Math 在 CPU 上计算的属性.cos(phi),那么代码就可以工作了。建筑物/立方体是完整的,因此位移工作和相交工作,因为建筑物/立方体被放置在球体的表面,具有正确的距离到平面。

Cornstalks 在 gamedev.net 上的回答:

大数字是个问题。如果您的顶点着色器使用 32 位浮点数,则只会为您提供 6 位十进制数字的精度。5476389.695241543 到 6 位小数的精度是 5476380.000000(截断 6 位之后的所有内容)。Pi 仅约为 3.14,并且由于 sin/cos 是周期性的,因此使用大数字不会比使用较小数字带来任何好处(因为大数字只是环绕)。但是,您的数字非常大,以至于它们环绕得如此之多,以至于它们甚至不能精确地映射到 [-pi, pi](或 [0, 2pi])范围。基本上,环绕会丢弃所有“高”位,只保留相关的低位,但不幸的是,你所有的低位都是垃圾,因为你将所有 6 个精度数字都花在了被丢弃的数字上,

简而言之,是的,这些巨大的数字会杀死你。

但是,在 JavaScript 中,所有浮点数都是 64 位的,这为您提供了 15 位十进制数字的精度。这意味着在 JavaScript 中您实际上可以正确表示 5476389.69524154,因此您的三角计算实际上是准确的(假设您的 JavaScript 代码正在处理与顶点着色器相同的大值)。

4

1 回答 1

0

没有区别 sin 表示正弦函数

确保您使用的是弧度

转换你可以使用

var angleInRadians = angleInDegrees * Math.PI / 180;
于 2013-07-06T00:18:53.843 回答