有什么区别,如何让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代码是 处理与顶点着色器相同的大值。)
答案 0 :(得分:0)
没有区别sin表示sine function。
确保您使用的是radians。
转换你可以使用
var angleInRadians = angleInDegrees * Math.PI / 180;