3D그래픽2011. 9. 10. 15:36

OpenGL ES 2.0으로 Phone Shading(또는 Per Fragment Lighting)을 구현하기 위해 얼마나 많은 고생을 했는지 몰르겠다.
어디에도 제대로된 sample은 없었다. 오히려 bump mapping 예제가 더 많았던 것 같다.

그런데, 나도 바보같은 것이 그냥 OpenGL sample을 찾아서 수정하겠다고 맘 먹었으면 오히려 쉬웠을 수도 있는데, 내용을 모르다보니 수정하는것에 막연히 겁을 먹었던 것 같기도 하다.

어쨌든 이런 저런 sample들을 받아 이렇게도 해보고 저렇게도 해보아도 제대로 되지 않았던 Phong shading을, "바로 오늘!" 제대로 구현하기에 이르렀다. 물론 이론에 대한 학습이 선행 되었기에 가능했을런지 모르겠다. : )

개인적으로 느낀 한 가지 팁은,
대부분에 해당 될지는 모르겠지만, 처음부터 texture를 사용해서 테스트 하지 않는게 좋겠다.
왜냐하면 texture의 현란한(?) 색상 때문에 정작 구현하고자 하는것이 제대로 보이는지 확인이 어려운 것 같다.
그냥 원색의 단색, 예를들면 빨강(Red)이나 파랑(Blue)을 이용해서 구현하면 좋은것 같다.

Phong Model for Specular Reflection [출처: www.siggraph.org]

Specular reflection is when the reflection is stronger in one viewing direction, i.e., there is a bright spot, called a specular highlight. This is readily apparent on shiny surfaces. For an ideal reflector, such as a mirror, the angle of incidence equals the angle of specular reflection, as shown below.

So if R is the direction of specular reflection and V is the direction of the viewer (located at the View Reference Point or VRP), then for an ideal reflector the specular reflection is visible only when V and R coincide. For real objects (not perfect reflectors) the specular reflectance can be seen even if V and R don't coincide, i.e., it is visible over a range of α values (or a cone of values). The shinier the surface, the smaller the f range for specular visibility. So a specular reflectance model must have maximum intensity at R, with an intensity which decreases as f(α).

Phong Model (by Phong Bui-Tuong)

This is an empirical model, which is not based on physics, but physical observation. Phong observed that for very shiny surfaces the specular highlight was small and the intensity fell off rapidly, while for duller surfaces it was larger and fell off more slowly. He decided to let the reflected intensity be a function of (cos α)n with n >= 200 for a shiny surface and n small for a dull surface. For a perfect reflector n equals infinity, and for a piece of cardboard n equals 0 or 1. In the diagram below we can see how the function (cos α)n behaves for different values of n.

Specular reflection is also a function of the light incidence angle θ. An example is glass which has almost no specular reflectance for θ = 0 degrees but a very high specular reflectance for θ > 80 degrees. Some substances, such as copper, actually change color with change in the incidence angle, as shown in the following plot of the reflectance curve as a function of the incident angle for copper.

 Image Reference

 
A full specular reflectance function is the Bi-directional Reflectance Distribution Function (BRDF). For glass the BRDF at 0 degrees incidence equals 0 and for light incident at 90 degrees, it equals 1. Since for many materials the BRDF is approximately constant, Phong called this term the specular coefficient (ks) and assumed it was constant. Then, since cos α = V·R, a complete illumination intensity model for reflection including diffuse reflection from ambient light and a point light source, and the Phong model for specular reflection is: 
 

I = ka * Ia + (Ip / (d)) [kd * (N\cdot L) + ks * (V\cdot R)^n]

 
For color there will be versions of the above equation for Red, Green, and Blue components. The coefficient of specular reflection ks is usually not the same as the coefficient of diffuse reflection kd or the ambient reflection ka. The assumption is often made that the specular highlights are determined by the color of the light source, not the material, e.g.,  ksR = ksG = ksB = 1.0 This is true of plastic which is why many computer graphics images appear to be plastic.
 
Approximations in the application of the Phong Model

If the point light source is far from the surface then N·L is constant across a planar surface, e.g., across one planar polygon. Similarly if the VRP is far from the surface then V·R is constant across the surface.

● Methods to compute V·R



Implementing Phong Shader (for one Point-Light) [출처: Clockworkcoders Tutorials]

 

varying vec3 N;

varying vec3 v;


void main(void)  

{     

v = vec3(gl_ModelViewMatrix * gl_Vertex);       

N = normalize(gl_NormalMatrix * gl_Normal);

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  

}

[Vertex Shader Source Code]

 

varying vec3 N;

varying vec3 v;

void main (void)

{

vec3 L = normalize(gl_LightSource[0].position.xyz - v);

vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)

vec3 R = normalize(-reflect(L,N));

 

//calculate Ambient Term:

vec4 Iamb = gl_FrontLightProduct[0].ambient;

 

//calculate Diffuse Term:

vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);

Idiff = clamp(Idiff, 0.0, 1.0);

 

// calculate Specular Term:

vec4 Ispec = gl_FrontLightProduct[0].specular * pow(max(dot(R,E),0.0), 0.3 * gl_FrontMaterial.shininess);

Ispec = clamp(Ispec, 0.0, 1.0);


// write Total Color:

gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;

}

 

[Fragment Shader Source Code]
우선 Vertex Shader Source Code에서,
gl_ModelViewMatrix, gl_ModelViewProjectionMatrix, gl_NormalMatrix, gl_Vertex, gl_Normal 은 OpenGL ES 2.0에는 없는 built-in variable 이기 때문에, 따로 uniform 및 attribute로 추가해 주어야 한다.

다음으로 Fragment Shader Source Code에서도,
gl_LightSource, gl_FrontLightProduct, gl_FrontMaterial, gl_FrontLightModelProduct 역시 OpenGL ES 2.0에는 없는 build-in variable 이므로, 따로 uniform으로 추가 해 주어야 한다.

[2011.10.03 추가]
* 처음 Phong Shading 구현에 성공했을 당시(거의 한달 전-_-;)에는, 그 자제가 너무 감격스러워 lighting 이라는 본질에 대해서는 망각하고 있었다. 즉, lighting의 방향에 대해서는 제대로 확인조차 하지 않았던 것이다. 그리고 이런 저런 정리가 어느정도 된 상태에서 확인을 해 보니, 아무리 조명의 위치를 변경해도 항상 제자리에서 꿈쩍도 하지 않았던 것! ㅜ.ㅜ
  한참을 고민해 봐도 모든게 sample code와 다르지 않았고, 급기야 그림을 그리며 directional light와 Phong shading에 대해 공부하기에 이르렀지만, 모든게 정상적이었고 되지 않을 이유가 없었는데... Shader에서 문제(?)가 생기니, 정말 막막하기만 했다.
  Back to Basics! 기본으로 돌아가서 다시 하나하나 점검을 하던 중, 이상한 것을 발견! 그건 바로 light position의 data type이 vec4 로 되어 있었는데, client code에서는 glUniform3f를 사용한 것이었다. 이런 된장! -_-; 주의하자;;

* 여러종류 light 다수를 하나의 shader에 구현하려고 했는데, 그러지 말란다. 실제로도 shader code에 control이 들어가면 성능이 급격히 떨어진다. 아직도 갈 길은 멀었으니...;;

'3D그래픽' 카테고리의 다른 글

GLSurfaceView.Renderer interface  (1) 2011.09.29
Build library with android NDK  (0) 2011.09.16
Bézier, Gouraud, Fresnel 의 발음  (0) 2011.09.08
Transforms (변환 행렬)  (0) 2011.09.06
Goraud shading vs. Phong shading  (0) 2011.09.02
Posted by 세월의돌