【问题标题】:Difference between Javascript "Math.sin" and WebGL"sin"Javascript“Math.sin”和WebGL“sin”之间的区别
【发布时间】:2013-07-04 02:46:48
【问题描述】:

有什么区别,如何让 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) 在 CPU 上计算的属性) 和 Math.cos(phi),那么代码就可以工作了。建筑物/立方体是完好无损的,因此由于建筑物/立方体放置在球体表面,因此位移和相交工作,具有正确的距离ToPlane。

Gamedev.net 上 Cornstalks 的回答:

大数字是个问题。如果您的顶点着色器正在使用 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 代码是 处理与顶点着色器相同的大值)。

【问题讨论】:

标签: javascript html three.js webgl shader


【解决方案1】:

没有区别sin表示sine function

确保您使用的是radians

转换你可以使用

var angleInRadians = angleInDegrees * Math.PI / 180;

【讨论】:

  • 索引从何而来?似乎它为空,您尝试将 inc 与它相乘
  • 索引只是每个顶点的计数器,介于 1 和 2500000 之间,我将它们按 8 分组,所以你在这些图片上看到的一个立方体是具有相同索引的 8 个顶点,索引给出了斐波那契点.而且我不认为它是空的,因为它在第二个代码片段中不是空的,而且它与我输入的索引相同。
  • 是的,我知道,没有必要显示所有代码,这只会让所有人感到困惑。有趣的部分是为什么 vec3 fibPoint 如果我在 CPU 上预先计算 sin 和 cos 并将它们作为一个属性输入时会得到正确的结果,但如果我在着色器中计算 sin 和 cos 会变得完全不同。
  • 如果您有兴趣,我可以向您展示完整的顶点着色器,进行新的编辑
猜你喜欢
  • 1970-01-01
  • 2018-04-25
  • 2013-05-21
  • 2016-03-29
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多