Warble Effect의 정의는 "작고 빠른 요동", 또는 불규칙하게 흔들리는 듯한 시각적 움직임.
원리는 Vertex 좌표를 animation을 적용하는 것이다.
렌더 코드에서는
애니메이션 변수를 유니폼으로 전달해 준다.
셰이더에서 애니메이션을 할때는 time 값을 대부분 사용한다.
void ObjLoader::Render()
{
...
glUseProgram(program->ProgramID);
TransformObj->TransformPushMatrix();
// 현재 모델의 MVP 행렬 계산해서 전달
glUniformMatrix4fv(MVP, 1, GL_FALSE, (float*)TransformObj->TransformGetModelViewProjectionMatrix());
glUniformMatrix4fv(MV, 1, GL_FALSE, (float*)TransformObj->TransformGetModelViewMatrix());
// Normal 계산용 정규 행렬 생성 (MV의 상위 3x3 추출)
glm::mat4 matrix = *(TransformObj->TransformGetModelViewMatrix());
glm::mat3 normalMat = glm::mat3(glm::vec3(matrix[0]), glm::vec3(matrix[1]), glm::vec3(matrix[2]));
glUniformMatrix3fv(NormalMatrix, 1, GL_FALSE, (float*)&normalMat);
TransformObj->TransformPopMatrix();
// ⏱시간 기반 애니메이션용 타이머 유니폼 설정
timeUpdate = clock(); // 현재 시간
float speed = 3;
GL_CHECK(glUniform1f(timer, timeUpdate / CLOCKS_PER_SEC * speed));
GL_CHECK(glBindVertexArray(OBJ_VAO_Id));
GL_CHECK(glDrawArrays(GL_TRIANGLES, 0, IndexCount));
GL_CHECK(glBindVertexArray(0));
}
Vertex Shader
position.y += sin(position.x + Time) * AMPLITUDE;
sin 값의 리턴 값은 -1 ~1 이기 때문에 AMPLITUDE 를 곱하면
position.y 값의 범위는 -AMPLITUDE ~ +AMPLITUDE가 된다.
x 값에 따른 y 의 변화량은 sin 그래프와 동일하게 되므로 좌 -> 우로 출렁거리는 애니메이션이 된다.
#version 300 es
// Wobble 셰이더를 위한 상수 정의
#define AMPLITUDE 1.2 // 흔들림의 최대 진폭
// 정점 속성 입력
layout(location = 0) in vec4 VertexPosition; // 모델의 정점 좌표
layout(location = 1) in vec3 Normal; // 정점 노멀 벡터
// 행렬 유니폼 (변환용)
uniform mat4 ModelViewProjectionMatrix; // 모델-뷰-투영 행렬
uniform mat4 ModelViewMatrix; // 모델-뷰 행렬
uniform mat3 NormalMatrix; // 노멀 변환용 행렬
// 시간 유니폼 (애니메이션용)
uniform float Time;
// 프래그먼트 셰이더에 넘겨줄 출력값
out vec3 normalByView; // 뷰 공간에서의 정점 노멀
out vec3 positionByView; // 뷰 공간에서의 정점 위치
// 흔들림(wobble) 효과 적용 함수
vec4 wabbleEffect() {
vec4 position = VertexPosition;
// x 위치 + 시간에 따라 y를 흔들어줌 (사인 곡선 기반)
position.y += sin(position.x + Time) * AMPLITUDE;
// 흔들린 정점 위치를 MVP 행렬로 변환 후 반환
return ModelViewProjectionMatrix * position;
}
void main()
{
// 뷰 공간에서 노멀 벡터 계산 (라이팅 계산에 사용)
normalByView = normalize(NormalMatrix * Normal);
// 뷰 공간 위치 계산 (프래그먼트 셰이더에서 사용 가능)
positionByView = vec3(ModelViewMatrix * VertexPosition);
// 흔들림 효과 적용 후 최종 위치 설정
gl_Position = wabbleEffect();
}
Fragment Shader
warble 이펙트는 버텍스 위치만 변경하기 때문에, chapter 5에서 진행한 phong shader shader 그대로 사용한다.
#version 300 es
precision mediump float;
uniform vec3 MaterialAmbient;
uniform vec3 MaterialSpecular;
uniform vec3 MaterialDiffuse;
uniform vec3 LightAmbient;
uniform vec3 LightSpecular;
uniform vec3 LightDiffuse;
uniform vec3 LightPosition;
uniform float ShininessFactor;
in vec3 normalByView;
in vec3 positionByView;
layout(location = 0) out vec4 outColor;
vec3 PhongShading()
{
vec3 normalDir = normalize ( normalByView );
vec3 normalPosition = normalize( positionByView );
vec3 nLight = normalize( LightPosition - positionByView );
// Diffuse Intensity
float cosAngle = max( 0.0, dot( normalDir, nLight ));
//sin(pos.y);
// Specular Intensity
vec3 V = -normalPosition;
vec3 R = reflect( -nLight, normalDir );
float sIntensity = pow( max( 0.0, dot( R, V ) ), ShininessFactor );
// ADS color as result of Material & Light interaction
vec3 ambient = MaterialAmbient * LightAmbient;
vec3 diffuse = MaterialDiffuse * LightDiffuse;
vec3 specular = MaterialSpecular * LightSpecular;
return ambient + ( cosAngle * diffuse ) + ( sIntensity * specular );
}
void main() {
outColor = vec4(PhongShading(), 1.0);
}
position.x 기준으로 애니메이션을 하지 않고 distance로 애니메이션을 하게 되면,
원점 기준으로 radius 가 작은 정점에서 -> 먼 정점 방향으로 출렁거리는 애니메이션을 볼 수 있다.
vec4 rippleEffect() {
vec4 position = VertexPosition;
float distance = length(position);
position.y = sin(2.0 * PI * distance * PREQUENCY + Time) * RIPPLE_AMPLITUDE;
return ModelViewProjectionMatrix * position;
}
'Opengles 3.0 with Android' 카테고리의 다른 글
Chapter 6.3 Pattern Effect - Brick Style (0) | 2025.04.22 |
---|---|
Chapter 6.1 Pattern Effect - Circle (0) | 2025.04.16 |
Chapter 5.2 Multi Light (0) | 2025.04.15 |
Chapter 5.1 Phong Shader (0) | 2025.03.24 |
Chapter 5.0 Vertex lighting (0) | 2025.03.24 |