Javascript“Math.sin”和WebGL“sin”之间的区别

use*_*496 5 html javascript shader webgl three.js

有什么区别,我如何让 WebGL 的罪产生与 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);
Run Code Online (Sandbox Code Playgroud)

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

如果我改为在 CPU 上使用 javascript 的 Math.sin 和 Math.cos 计算 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);
Run Code Online (Sandbox Code Playgroud)

我得到了这样一个很好的斐波那契分布: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"),
Run Code Online (Sandbox Code Playgroud)

所以这个给出了错误的顶点位置,如果我将“cos(phi)”和“sin(phi)”更改为cosphi和sinphi,它们是在CPU上计算的属性,由javascript的Math.sin(phi)和Math .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 代码正在处理与您的顶点着色器相同的大值)。