이번 강의에서는 물체에 조명 효과를 주는 방법에 대해 설명하겠다.
소스는 다음 사이트에서 참고했다.
http://insanitydesign.com/wp/projects/nehe-android-ports/
사용하기 편하게 하기 위해 소스 수정을 조금 했는데 원래의 소스는 화면의 특정한 영역을 터치했을 때 light on/off 등의 기능이 동작하도록 했는데 불편한 거 같아 버튼 위젯을 추가해서 기능 수행하도록 했다(그래서 MainActivity.java 의 onCreate 안의 코드도 다르다). 그리고 Normal vector 의 좌표를 수정했다.
조명 효과를 내기 위해서 이해해야 할 필수 내용이 몇 가지가 있다.
1. 광원의 위치 정하기.
2. gl.glEnable(GL10.GL_LIGHT0) 추가하기.
3. Normal vector 방향 정하기.
public void onDrawFrame(GL10 gl) {
if(light) {
gl.glEnable(GL10.GL_LIGHTING);
} else {
gl.glDisable(GL10.GL_LIGHTING);
}
gl.glTranslatef(0.0f, 0.0f, z);
}
1) 광원의 위치 정하기 : 첨부된 소스를 보면 gl.glEnable(GL10.GL_LIGHT0)를 호출해서 GL_LIGHT0 을 광원으로 사용한다고 설정한 후 gl.glEnable(GL10.GL_LIGHTING)를 실행해서 조명 효과를 주도록 돼 있다. 그리고 한 줄 아래 코드가 gl.glTranslatef(0.0f, 0.0f, z)이고 z 는 초기값이 -5.0f 다.
상식적으로 생각해서 우리가 어떤 사물에 빛이 비춘다는 것을 인식하기 위해서는 물체가 우리 눈 앞에 있어야 하고 광원은 우리가 보고 있는 방향으로 물체에 비춰야 한다. 만약 광원이 물체의 뒤쪽에 있다면 빛이 어떻게 비추는 것인지 알 수 없는 것이다. 그래서 광원의 위치 좌표를 다음과 같이 주게 되는 것이다.
private float[] lightPosition = {0.0f, 0.0f, 2.0f, 1.0f}
여기서 z 축의 좌표를 -5.0 이하의 값(-0.5f, -6.0f 등등) 으로 주면 화면에 물체의 모습이 보이지 않게 되는 것이다. z 좌표가 -5.0f 보다 큰 값(-4.0f, -3.0f 등등) 인 경우에는 x, y 좌표를 조정해가면서 광원의 위치에 따라 그림자 효과가 어떻게 나타나는 지 확인할 수 있다. (참고로, 안드로이드 OpenGL ES 에서 모든 좌표값들은 FloatBuffer 로 변환해야 한다)
2) LIGHT 효과 주기 : gl.glEnable(GL10.GL_LIGHT0) 와 gl.glEnable(GL10.GL_LIGHTING)를 추가하면 된다.
3) Normal vector 방향 정하기 : 고등학교 수학 시간에 벡터 배울 때 나왔던 용어 같은데 빛이 비출 때 도형의 각 면이 어떤 방향으로 빛을 받을 것인 지 지정해 주는 것이라 예상된다(정확한 의미는 잘 모르겠음). 우리가 사용하는 도형인 육면체는 각 면이 꼭지점 4개로 이루어져 있는데 참고 자료를 보면 각 꼭지점의 Normal vector 방향을 모두 지정해 줘야 한다고 나와 있다. 완벽한 이해를 하기에는 시간이 걸릴 것 같고 일단은 각 면에 수직 방향으로 좌표를 지정해 줬더니 조명 효과가 제대로 보이기에 이대로 진행하겠다(계속 공부해 나가다 보면 언젠가 이해되는 순간이 있을 것이라 믿는다..).
main.xml 설명
RelativeLayout 을 쓰는 이유는 가로/세로 모드 전환할 때(본인의 시료폰은 Nexusone) 각각 layout 을 따로 만들기 싫어서 이고 이런 경우에는 RelativeLayout 이 쓰기 편하기 때문이다. 각 버튼의 의미는 버튼 title 을 보면 금방 이해가 될 것이다. filter 버튼을 클릭하면 도형의 질감이 약간씩 변하는 것을 확인할 수 있다. 특히 이미지가 작을 때 filter 의 효과가 두드러진다.
첨부 소스를 실행하면 다음과 같이 보인다.
그림 위에 Touch 해서 여러 방향으로 움직이다 보면 move 방향과 반대로 회전하는 경우가 있는데 이유는 짐작이 가지만 본격 프로젝트가 아니기 때문에 굳이 수정하지는 않았다.
lightPosition = {0.0f, 0.0f, 2.0f, 1.0f} 의 좌표 값들을 수정해 가면서 실제로 어떻게 보이는 지 반드시 확인해 보기 바란다.
아래 코드 두 줄이 어떤 역할을 하는 지는 문서상으로는 이해했는데 실제 동작은 이해가 안된다. 두 줄을 막고 실행해도 동일한 결과가 나온다.
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);
[출처] Android OpenGL lesson #9|작성자 이외수와베르나르