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

时间:2013-07-06 00:13:57

标签: javascript html5 three.js webgl shader

有什么区别,如何让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);

这不起作用,它给了我这样笨拙的顶点位置: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,它们是在CPU上计算的属性,通过javascript的Math.sin(phi) )和Math.cos(phi),然后代码工作。建筑物/立方体是完整的,因此移位工作和交叉工作,因为建筑物/立方体被放置在球体的表面,具有正确的距离ToPlane。

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代码是   处理与顶点着色器相同的大值。)

1 个答案:

答案 0 :(得分:0)

没有区别sin表示sine function

确保您使用的是radians

转换你可以使用

var angleInRadians = angleInDegrees * Math.PI / 180;