[英]Rotate a sphere in an OpenGL shader
我正在使用适用于Android的OpenGL ES 2.0制作地球模型。 我绘制球体,并且每次在顶点着色器中都想旋转它。 每次绘制时,我都会设置一个表示旋转角度的制服。 这是我计算新分数的方法:
Vertex Shader
:
uniform mat4 u_Matrix;
uniform vec3 u_VectorToLight;
uniform vec3 u_Center;
uniform float u_RotationAngle;
attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;
attribute vec3 a_Normal;
varying vec2 v_TextureCoordinates;
varying vec3 v_VectorToLight;
varying vec3 v_Normal;
vec2 rotate(vec2 c, vec2 p, float a);
void main() {
v_TextureCoordinates = a_TextureCoordinates;
v_VectorToLight = u_VectorToLight;
v_Normal = a_Normal;
vec2 point = rotate(u_Center.xz, a_Position.xz, radians(u_RotationAngle));
gl_Position = a_Position;
gl_Position *= u_Matrix;
gl_Position.x = point.x;
gl_Position.z = point.y;
}
vec2 rotate(vec2 c, vec2 p, float a) {
p.x -= c.x;
p.y -= c.y;
float x1 = p.x * cos(a) - p.y * sin(a);
float y1 = p.x * sin(a) + p.y * cos(a);
p.x = c.x + x1;
p.y = c.y + y1;
return p;
}
Fragment Shader
:
precision mediump float;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;
varying vec3 v_VectorToLight;
varying vec3 v_Normal;
void main() {
gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
vec4 color = gl_FragColor.rgba;
vec3 scaledNormal = v_Normal;
scaledNormal = normalize(scaledNormal);
float diffuse = max(dot(scaledNormal, v_VectorToLight), 0.0);
gl_FragColor.rgb *= diffuse;
float ambient = 0.2;
gl_FragColor.rgb += ambient * color;
}
我使用顶点着色器中的rotation rotate()
方法rotate()
球体的中心旋转每个点,这只会导致地球变形,在X和Z轴上变小,但在Y轴上变小(所以可以想象地球的薄版)。 更令人困惑的是,即使我每次都为旋转角度输入一个新值,我仍然会得到相同的静止图像。 即使它失真了,但由于我每次使用的角度都不一样,因此每次看起来还是有些不同。 这是我设置制服的方法:
public void setUniforms(float[] matrix, Vector vectorToLight, int texture, Point center, float angle) {
glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(uTextureUnitLocation, 0);
glUniform3f(uRadiusLocation, center.x, center.y, center.z);
glUniform3f(uVectorToLightLocation, vectorToLight.x, vectorToLight.y, vectorToLight.z);
glUniform1f(uRotationAngleLocation, angle); // <-- I set the rotation angle
}
我相信如何将围绕轴的旋转与u_Matrix
包含的全局旋转结合起来存在问题:
vec2 point = rotate(u_Center.xz, a_Position.xz, radians(u_RotationAngle));
gl_Position = a_Position;
gl_Position *= u_Matrix;
gl_Position.x = point.x;
gl_Position.z = point.y;
由于point
只包含绕轴旋转,并替换x
和z
的gl_Position
从值point
,产生的x
和z
不必u_Matrix
适用于他们。
您需要首先应用轴旋转,然后将u_Matrix
应用于此变换点:
vec2 point = rotate(u_Center.xz, a_Position.xz, radians(u_RotationAngle));
vec4 rotPoint = a_Position;
rotPoint.x = point.x;
rotPoint.z = point.y;
gl_Position = rotPoint;
gl_Position *= u_Matrix;
为了完成此任务,通常在Java代码中一次计算旋转矩阵,将其设置为统一值,然后仅在顶点着色器中应用矩阵乘法,效率会大大提高。 使用现在的代码,您将为着色器代码中的每个顶点计算一个cos()
和sin()
值,除非GLSL编译器对此非常了解。 如果您不想传递完整的矩阵,我至少会将余弦和正弦值传递给着色器,而不是角度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.