有什么区别,如何让 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 代码正在处理与顶点着色器相同的大值)。