[GLES20] 14. 조명 적용하기 - Spot Light :: OPEN GL ES[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

OPEN GL ES
[1]
등록일:2020-05-07 00:21:56 (0%)
작성자:
제목:[GLES20] 14. 조명 적용하기 - Spot Light
android.3D

 

 

 

 

조명 적용하기 - Spot Light

 

이번장은 기초 조명 과정중 마지막 장이라 할 수 있는 Spot Light 입니다.

 

Spot Light에 대해서는 iPhone 3D Programming 책에서는 다루지 않고 있습니다. (attenuation 감쇠율 부분도 빠져 있음)

이 부분에 대해서는 OpenGL ES 2.0 Programming Guide 책의 "8장 Vertex Shader"을 참고하는 것이 좋습니다.

 

물론 OpenGL ES2.0 책은 독자가 OpenGL 조명에 대해서 어느 정도 이해한 상태에서 설명을 합니다.

그렇기 때문에 OpenGL ES 부터 시작 하는 개발자들은 구현 함수인 spot_light() 함수만 봐서는 이런 수식을 이용하면 되겠구나 할 수는 있지만 실제 동작 시켜 볼수는 없습니다.

 

하지만, 13장 까지 잘 이해하고 따라 오셨다면 14장의 Spot Light도 책내의 spot_light()함수만 보고도 적용하실 수 있을 것이라고 생각합니다.

추가적인 참조 자료로는 바른 생활님의 "[GLSL]23 Spot Light 의 구현" 장과 PowerVR SDK Training Course 내에 있는 "ComplexLighting" 코드를 분석해 보시면 도움이 될 겁니다.

 

여기서는 Spot Light의 수식과 관련된 핵심 부분만 정리하도록 하겠습니다.

 

 

1. Spot Light

 

기본적으로 Spot Light는 다음과 같은 그림으로 설명할 수 있습니다.

 

 

 

1. 광원으로 부터 Spot(지점) 방향으로 향하는 벡터 Spot direction 과 광원의 표면의 정점으로 향하는 Light direction 간의 사잇각을 구한다.

 

2. 그 사잇각이 Spot cutoff angle 보다 작다면 Spot Effect를 계산하고, 크다면 감쇠율을 0.0으로 둔다.

 

3. Spot factor가 Cutoff angle 보다 작다면, 아래와 같은 Spot Effect 수식에 따라서 계산한다.

위의 수식을 완성하기 위해서는 다음과 같은 값들을 본App으로 부터 uniform  형으로 받아와야 합니다.

 

(spotExp의 기본값은 0으로 이 값이 높아지면 spotEffect가 활성화 되는 영역과 그 밖에 감쇠되는 영역이 부드러워 집니다.)

 

13장까지 정리한 것을 기준으로 14장을 보면 Spot Light는 쉽게 해결할 수 있습니다.

 

Spot Light에 대한 구현 코드는 다음과 같습니다.

 

Shaders/PixelLighting.frag

 

 // ambient + diffuse + specular + attenuation + Spot light
vec3 calcLightAmbDifSpecAttSpot()
{

      ......

  if (u_spotCutOffAngle < 180.0) 
  {
    vec3 S = (vec3(u_spotDirection));
    float spot_factor = dot(-L, S);   
// ----------------------------- (1)
  
    if (spot_factor >= cos(radians(u_spotCutOffAngle))) {   
// ------- (2)
      spot_factor = pow(spot_factor, u_spotExponent);       
// ------- (3)
    } else {
      spot_factor = c_zero;     
// ---------------------------------- (4)
    }

    att *= spot_factor;      // -------------------------------------- (5)
 }

      ......

}

 

 

--------------------------------------------------------------------------

 

(1) Spot direction과 Light direction 사잇각 구하기

지점 방향을 나타내는 Spot direction 벡터와 광원 방향을 나타내는 Light Direction 간의 사잇각을 구합니다.

Spot direction은 본App에서 기본값인 (0, 0, -1)로 설정 되어 있으며,

Light Direction은 vertex shader에서 광원과 정점의 벡터 차를 통해서 구한 Positional Light벡터를 이용합니다.

 dot(-L, S)에서 -L인 이유는 광원과 정점의 벡터 차를 구했음으로 그 벡터 방향은 "정점->광원"으로 향합니다.

저희는 "광원->정점" 방향으로 구해야 함으로 -L을 해줘야 합니다.

 

 

(2) Spot factor와 cut off angle 비교

Spot Light는 원뿔형으로 빛이 비춰집니다.

이때 원뿔의 영역을 정하는 기준이 Spot direction을 중심으로 spot cut off angle(절단각)을 통해서 구해 집니다.

즉 이 cut off angle 내에만 Spot Effect를 계산 해주고, 나머지 영역은 감쇠율 값에 0.0을 해줌으로서 빛을 전부 빼줘야 합니다.

이때 cos() 함수가 이용되는데 이는 spot_factor가 -L과 S간의 내적을 통해서 구해 짐으로 그 결과는 cos(theta) 입니다.

그런데 절닥각보다 작아야 한다고 하는데, 비교식은 "크거나 같다" 입니다.

이는 아래와 같이 Cosine함수가 Theta 각도(Range)가 커질수록 그 결과값(치역)은 작아지기 때문에 그렇습니다.

 

결국 내적의 결과인 spot_factor가 cos(CutOffAngle)의 결과 보다 크다면, 그 사잇각은 작다는 것을 의미합니다.

(이 부분은 제가 이렇게 이해 했다는 의미 입니다. -ㅁ-; 혹 다른 의미가 있다면 댓글 달아주세요 ^^;)

 

 

(4) 절단각에서 벗어나는 영역은 감쇠율을 최대치로 높인다.

 

 

(5) 감쇠율에 Spot factor을 곱해줘서 뒤에 오는 주변광, 확산광, 경면광에 적용해 준다.

 

  

<왼쪽은 Vertex Light를 이용한 Spot Light 이며, 오른쪽은 Pixel Light를 이용한 Spot Light>

 

 

 

2. 본App 에서 Spot Light 실행 하기

 

Shader 내의 코드는 수학적 논리가 단순해서 어렸지는 않습니다.

그런데, GLES20 책은 응용 App 단 부분은 생략되어 있기 때문에, 도대체 Spot direction은 왜? (0, 0, -1)을 넣어야 하고,

Spot Exponent는 몇으로 잡아줘야 하는지? Cut Off Angle 절단각은 180도를 넘어가면 어떻게 되는지?

Light direction은 몇으로 잡아야 하는지? 등에 대해서는 책만 봐서는 알수 없습니다.

 

그럼 실제 응용 App에서는 어떻게 호출 해 줘야 하는지 보도록 하겠습니다.

 

Classes/RenderingEngine.CH02.ES2.cpp

 

 

void RenderingEngine::Initialize(int width, int height)

 

{

......

 m_pixelLight.Uniforms.AttenuationFactor = glGetUniformLocation(program, "u_attenuationFactor");
 m_pixelLight.Uniforms.IsAttenuation = glGetUniformLocation(program, "u_computeAttenuation");
 m_pixelLight.Uniforms.LightRadius = glGetUniformLocation(program, "u_lightRadius");
 m_pixelLight.Uniforms.SpotDirection = glGetUniformLocation(program, "u_spotDirection");
 m_pixelLight.Uniforms.SpotExponent = glGetUniformLocation(program, "u_spotExponent");
 m_pixelLight.Uniforms.SpotCutOffAngle = glGetUniformLocation(program, "u_spotCutOffAngle");

......

}

 

-----------------------------------------------------------------------------------

Attenuation과 Spot Factor에 대한 신규 uniform 형들이 추가 되었음으로 이를 초기화 함수에 추가해 줍니다.

-----------------------------------------------------------------------------------

 

 

void RenderingEngine::Render(const vector<Visual>& visuals)
{

......

 

 // --------------------------------------------
 // PixelLight
 bool bIsPixelLight = true;    // -------------------------------------- (1)
 ProgramHandles handler;
 if (bIsPixelLight)
   handler = m_pixelLight;
 else
   handler = m_vertexLight;
 glUseProgram(handler.Program);

 

 

 // Set the light Mode                // -------------------------------------- (2)
 // 0 : MENU_DIFFUSE_MATERIAL -> DIFFUSE_MATERIAL
 // 1 : MENU_DIFFUSE_LIGHT -> DIFFUSE_LIGHT
 // 2 : MENU_AMBIENT_DIFFUSE_LIGHT -> AMBIENT_DIFFUSE_LIGHT
 // 3 : MENU_AMBIENT_DIFFUSE_SPECULAR_LIGHT -> AMBIENT_DIFFUSE_SPECULAR_LIGHT
 // 4 : MENU_AMBIENT_DIFFUSE_SPECULAR_ATT_LIGHT -> AMBIENT_DIFFUSE_SPECULAR_ATT_LIGHT
 // 5 : MENU_AMBIENT_DIFFUSE_SPECULAR_ATT_SPOT_LIGHT -> AMBIENT_DIFFUSE_SPECULAR_ATT_SPOT_LIGHT
 glUniform1i(handler.Uniforms.LightMode, MENU_AMBIENT_DIFFUSE_SPECULAR_ATT_SPOT_LIGHT);
 //glUniform4f(handler.Uniforms.AmbientLight, 0, 0, 0, 0);

 

 // Initialize various state.
 glEnableVertexAttribArray(handler.Attributes.Position);
 glEnableVertexAttribArray(handler.Attributes.Normal);

 

 GLfloat weight = sin(interpolation_z) * 3;//12.0f;//1.5f;    // ------------------- (3)
 //weight = 0.0f;
 //glUniform1f(handler.Uniforms.Interpolation_z, (GLfloat) weight);
 //LOG_PRINT("interpolation_z:%f, cos(%f)", interpolation_z, weight);
 interpolation_z += (2*Pi) * 0.0015f;

 

 // Set the attenuation factor.                                            // -------------------- (4)
 //vec3 attenuationFactor(1.5f, 0.5f, 0.2f);
 vec3 attenuationFactor(1.0f, 0.0f, 0.0f);
 glUniform3fv(handler.Uniforms.AttenuationFactor, 1, attenuationFactor.Pointer());
 glUniform1i(handler.Uniforms.IsAttenuation, 1);
 glUniform1f(handler.Uniforms.LightRadius, 4.0f);

    // Set the light position.
 //vec4 lightPosition(0.f, 0.f, -1.f, 1.0f); // for ortho
 vec4 lightPosition(0.f, 0.f, -6.f, 1.0f);        // --------------------------------- (5)
 
 //lightPosition.x += weight;
 lightPosition.z = max(-6.5f, lightPosition.z+weight*2.f);  // --------------- (6)
 lightPosition.y += weight;
 //LOG_PRINT("lightPosition:(%f, %f, %f) + weight(%f)", lightPosition.x, lightPosition.y, lightPosition.z, weight);
 glUniform4fv(handler.Uniforms.LightPosition, 1, lightPosition.Pointer());

 

 

 // Set the spot direction.
 vec4 spotDirection(0, 0, -1, 1);                                                   // ---------------- (7)
 glUniform4fv(handler.Uniforms.SpotDirection, 1, spotDirection.Pointer());
 glUniform1f(handler.Uniforms.SpotExponent, 0.0f);
 glUniform1f(handler.Uniforms.SpotCutOffAngle, 25.0f);
 //glUniform1f(handler.Uniforms.SpotExponent, 40.0f);
 //glUniform1f(handler.Uniforms.SpotCutOffAngle, 51);

 

......

}

 

-------------------------------------------------------------------

 

(1) : bIsPixelLight  변수 설정합니다.

Pixel Light로 동작할지 Vertex Light로 동작할지 선택할 수 있습니다.

 

 

(2) : Spot Light가 동작하도록 설정합니다. ; MENU_AMBIENT_DIFFUSE_SPECULAR_ATT_SPOT_LIGHT

 

 

(3) : Light Position의 위치를 변경 시켜주기 위한 가중치 값입니다.

이 값은 sin()함수로 동작 함으로 0~1~-1~0 를 반복합니다.

여기에 세 배를 가해 줌으로 0 ~ 3 ~ 0 ~ -3 ~ 0 값이 가중치 값으로 이용합니다.

 

 

(4) : Attenuation factor인 감쇠율 값을 설정 합니다.

기본값인 (1.0, 0.0, 0.0)으로 설정 되어 있지만, 앞장에서 배웠던 광원의 반지름 공식에 의해서 감쇠율이 적용 됩니다.

 

 

(5) : Light Position을 설정 합니다.

Light Position 설정은 (0, 0, -6)으로 시작합니다.

예제는 Camera를 통해서 Z축을 정면으로 보는 상태에서 카메라를 10만큼 뒤로 뺀 상태 입니다. (eye(0, 0, 10))

다시 말하면, 모델 객체는 월드 좌표계를 기준으로 Z축을 기준으로 -10 만큰 뒤에 있는 상태입니다.

그럼으로 광원 위치를 모델 객체(로컬 좌표)에 가까이 다가가게 하기 위해서 -6 만큼 빼주었습니다.

 

 

(6) : (3)번에 계산한 weight값으로 광원 위치를 변경해 줍니다.

y와 z값을 변경해 줍니다.

Z값의 경우, 시작 설정값이 -6인데 모델 객체(로컬 좌표)의 원점은 -10입니다. 그런데 Z값이 -6.5 이하로 더 내려가면,

광원이 모델 객체와 충돌을 일으키는지 광원이 사라져 버립니다. ^^

그래서 Z값의 최대한 멀어지는 위치는 -6.5로 한정 시켰습니다.

 

 

(7) : Spot Direction을 설정 합니다.

기본 값인 (0, 0, -1, 1)로 설정합니다.

w값 1은 vertex positon의 w와 동일하다고 본다고 합니다.

이 예제에서는  w값은 실제 shading 중에 사용되지는 않습니다.

Spot Exponent는 기본값인 0으로 하였으며, 이 값을 높이면 Spot Light 경계지점이 부드러 지네요 ^^;

Spot Cut Off Angle은 25도로 설정 하였으며, 이 값을 높이면 Spot Light 가 커지게 됩니다.

(180도 이상 올리면 Spot Light가 동작하지 않게 됩니다.)

 

----- 여기서 부터는 제 주관적인 관점 이기 때문에 틀릴수도 있습니다. 저도 독학 이어서  ^ㅁ^; -----

여기서 중요한 값은 -1 입니다. 스팟 라이트가 정상적으로 동작하기 위해서는 이 값은 음수여야 합니다.

광원의 위치인 Light Positon은 음수 방향으로 보고 있습니다.

Spot Light도 같은 방향인 음수 방향으로 보고 있어야 L과 S간의 내적을 통해서 구하는 사잇 각이 예각 내에서 구해 지게 됩니다.

만약 Spot Light가 (0, 0, 1) 이면 L과 S의 벡터 방향이 반대가 되어 버려서 내적을 통해서 계산 되는 사잇 각은 예각이 아닌 둔각이 되어 버립니다.

그럼으로 이 부분은 (0, 0, -1)이 되어야 하는것 같습니다.

(아닐수도 있습니다. 어쨋든 양수로 하면 효과가 원하는 바대로 나오지 않습니다.)

 

 

  

 

<Vertex shader로 구현된 Spot Light>

 

 

<Pixel shader로 구현된 Spot Light, Exponent 0>

 

 

<Pixel shader로 구현된 Spot Light, Exponent 36>

 

 

 

3. 결론

 

여기서 설명한 부분들은 iPhone 3D Programming 책과 OpenGL ES 2.0 Programming Guide 책에 이미 나와 있는 내용 입니다.

책을 우선 보시고 여기서의 내용은 레퍼런스로 정도로 이용하시면 될것 같습니다.

 

위의 두 책에서 아쉬운 부분은 그림자 효과에 대해서는 다루지 않았습니다.

그림자 효과에 대해서는 Shader X2:Direct X9 쉐이더 프로그래밍 책에 설명이 나와 있던데,

궁금하신 분은 X2 책을 참고하셔도 좋을 것 같네요.

 

이상으로 조명과 관련한 기초 과정을 마무리 하도록 하겠습니다.

어느새 강좌를 쓰기 시작한지도 한달이 되었습니다.

보통 한달에 4개정도 포스팅 했는데, 14개를 하다니 엄청나게 폭풍 집필^^;을 했네요. 큭

 

앞으로는 속도 조절을 하면서 글을 써야할 것 같네요. -ㅁ-;

 

지금까지 여기서 설명한 방법들은 책을 보고 실행해 봐서 이렇게 되겠구나 하고 생각하는 점들을 정리한 것입니다.

실제 강의를 듣거나 마스터 분한테 사사 받은것이 아니어서 오류가 있을 수도 있습니다. ^^;

혹 논리에 문제가 있거나 정정이 필요한 부분이 있다면 댓글로 지적해 주십시요.

 

다음 장 부터는 조명 기법중 Cartoon 효과를 주는 Toon Shading을 간단하게 정리한 후에 Texture 처리로 넘어가도록 하겠습니다.

 

OGLES20 Template Application ported to mfc and android

http://code.google.com/p/myastro/downloads/list

http://code.google.com/p/myastro/downloads/detail?name=02_ParametricSurface.v.1.2.1.zip&can=2&q=#makechanges

[본문링크] [GLES20] 14. 조명 적용하기 - Spot Light
[1]
코멘트(이글의 트랙백 주소:/cafe/tb_receive.php?no=34937
작성자
비밀번호

 

SSISOCommunity

[이전]

Copyright byCopyright ⓒ2005, SSISO Community All Rights Reserved.