2014-11-30 16 views
0

Android 용 OpenGL ES 2.0을 사용하여 지구 모델을 만들고 있습니다. 저는 구를 그립니다. 매번 버텍스 쉐이더에서 회전시키고 싶습니다. 그릴 때마다 회전 각도를 나타내는 유니폼을 설정했습니다.OpenGL 쉐이더에서 구를 회전

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; 
} 

내가 정점에 rotate() 방법을 사용하여, 구의 중심을 각각의 점을 회전 여기에 내가 새로운 점을 계산하는 방법이다 쉐이더를 사용하면 왜곡 된 지구가 생기고 X 축과 Z 축에서는 더 작게 만들어 지지만 Y는 그렇게 만들지 않습니다 (지구의 매우 얇은 버전을 상상해보십시오). 훨씬 더 혼란스러운 점은 매번 회전 각도에 대한 새로운 값을 전달하더라도 여전히 동일한 정지 이미지를 얻는다는 것입니다. 왜곡 된 경우에도 매번 다른 각도를 사용하기 때문에 매번 다른 방식으로 보일 것입니다. point 이후

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; 

는 회전을 포함 : 난 당신이 u_Matrix에 포함 된 글로벌 회전 축을 중심으로 회전을 결합하는 방법에 문제가있는 생각

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 
    } 
+0

셰이더 밖에서 변환 행렬을 계산하여 전달하는 것이 더 일반적입니다. 모든 정점에 대해이를 다시 계산하여 저장합니다. – Alan

+0

나는 모든 것을 연구하지는 않았지만 원래 좌표에'u_Matrix'를 적용한 다음 결과 좌표 중 두 좌표를 축 회전으로 만 처리 된 좌표로 바꾼 것처럼 보입니다. 당신이하려는 일을 이해한다면, 먼저 축 회전을 적용한 다음 결과에'u_Matrix'를 적용해야합니다. –

답변

2

: 여기 유니폼을 설정하는 방법은 xzgl_Position 인 값이 point 인 경우 결과로 xzu_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; 

이 작업을 완료하려면, 일반적으로 자바에 한 번 회전 행렬을 계산하는 데 훨씬 더 효율적이 될 것입니다 코드를 유니폼으로 설정 한 다음 꼭지점 셰이더에서만 행렬 곱셈을 적용합니다. 지금 가지고있는 코드를 사용하면 GLSL 컴파일러가 실제로 영리하지 않으면 셰이더 코드의 각 버텍스에 대해 cos()sin() 값을 계산합니다. 전체 행렬을 전달하고 싶지 않다면, 적어도 코사인과 사인 값을 각도 대신 쉐이더에 전달해야합니다.