繁体   English   中英

在OpenGL着色器中旋转球体

[英]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只包含绕轴旋转,并替换xzgl_Position从值point ,产生的xz不必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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM