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

代わりに、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);

次のような素晴らしいフィボナッチ分布を取得します: http://i.imgur.com/DeRoXkL.png

明らかに、GLSL と Javascript の cos/sin 関数に違いがあるようです。ファイは、「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.sin(phi) によって CPU で計算されます。 .cos(phi) の場合、コードは機能します。建物/立方体は無傷であるため、変位が機能し、建物/立方体が正しい距離ToPlaneで球の表面に配置されるため、交差が機能します。

gamedev.net の Cornstalks による回答:

数が多いことが問題です。頂点シェーダーが 32 ビット浮動小数点数で動作している場合、10 進数で 6 桁の精度しか得られません。5476389.695241543 から 6 桁の精度は 5476380.000000 です (6 桁以降はすべて切り捨てられます)。Pi は 3.14 までしかなく、sin/cos は周期的であるため、大きな数を使用しても、小さな数を使用するよりもメリットはありません (大きな数がラップアラウンドするため)。ただし、数値が非常に大きいため、[-pi、pi] (または [0, 2pi]) の範囲に正確にマッピングすることさえできません。基本的に、ラップアラウンドはすべての「上位」桁を破棄し、関連する下位桁のみを保持しますが、残念ながら、下位桁はすべてがらくたです。

要するに、そうです、それらの膨大な数はあなたを殺します.

ただし、JavaScript では、すべての浮動小数点数が 64 ビットであるため、10 進数で 15 桁の精度が得られます。つまり、JavaScript では 5476389.69524154 を実際に適切に表すことができるため、三角関数の計算は実際には正確です (JavaScript コードが頂点シェーダーと同じ大きな値を処理していると仮定します)。

4

1 に答える 1

0

sin は正弦関数を表すことに違いはありません。

ラジアンを使用していることを確認してください。

変換するには、使用できます

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