【发布时间】: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 代码是 处理与顶点着色器相同的大值)。
【问题讨论】:
-
为了感兴趣,这里是gamedev.net上的整个线程:gamedev.net/topic/…
标签: javascript html three.js webgl shader