헬로, 안드로이드 15 주차 OpenGL 의 3D 그래픽 (2) 강대기동서대학교컴퓨터정보공학부
학습목표 OpenGL ES 에서모델을만드는방법을알아본다. 조명및카메라설정에대해알아본다. 모델을회전시키는방법에대해알아본다. 질감을적용하는방법에대해알아본다. 모델을투명하게하는방법에대해알아본다.
차례 모델만들기 조명, 카메라 액션! 질감적용하기 훔쳐보기 요약 퀴즈 연습문제
모델만들기 프로페셔널한환경에서 3 차원모델은그래픽도구 (3D Max, POV-Ray 등 ) 로만들어서파일에저장하고, 프로그램에서불러들임 본예제에서는간단한정육면체모델을정의해봄 (GLCube) GLRenderer 의 ondrawframe() 에서호출함 GLCube.java 에서 vertices 배열은사각형의모서리를고정소수점모델좌표에의해정의함 육면체의각면은두개의삼각형으로이루어진사각형으로, OpenGL 의그리기모드중일반적인삼각스트립 (triangle strips) 사용 각지점은세개의좌표로 x,y 와화면에서우리의눈쪽을향하는 (norm) z 가있음 gl.gldrawarrays() 를호출하여그림
고정소수점과부동소수점 OpenGL ES 인터페이스는고정소수점과부동소수점인터페이스를지원함 고정소수점메서드는 x 로끝나고, 부동소수점메서드는 f 로끝남 고정소수점은 4 바이트인 2 의 32 승 (65,536) 으로나타내짐 고정소수점 32,768 은부동소수점 0.5f 와대응됨 필수부분은 2 바이트의 Most Significant Bytes (MSB) 안드로이드의 2D 라이브러리들에서정수를사용하는방법과는상당히다름 일부저가기기에선고정소수점이부동소수점보다더빠르므로, 프로그래밍하기수월한부동소수점으로프로그램을작성한후, 나중에필요하면고정소수점으로최적화시키면좋음
조명, 카메라 실제생활에서는수많은광원이있음 태양, 헤드라이트, 횃불, 용암등등 OpenGL 에서는장면에서최대 8 개의광원을정의하게해줌 조명에는빛자체와빛이비춰지는부분이있음 조명의종류로는 ambient 광원이멀리떨어진경우와같이전체적인장면에비춰지는빛 diffuse 형광패널에서나오는것과같이, 부드럽지만방향성이있는조명 specular 반사광과같이주로밝은지점에서오는반짝이는빛. 빛나는물질과결합해사실감을더해주는하이라이트를만듦 예제에서사용된광원은흰색의전방향성빛으로밝은 diffuse 구성요소와흐린주변구성요소를가짐 또한, 빛은금속, 플라스틱, 종이등의다양한재료에따라다르게반사되므로, 육면체의재료를정의하여야함 예제에서는종이로만든듯무딘느낌을주었고, 육면체의오른쪽위모서리에서빛이비치게함
액션! 모델물체을이동시키기위해, GLSurfaceView.Renderer 를구현한 GLRenderer 의 onsurfacecreated() 와 ondrawframe() 변경 onsurfacecreated() 시간초기화 starttime = System.currentTimeMillis(); ondrawframe() 시간에근거하여회전 long elapsed = System.currentTimeMillis() - starttime; gl.glrotatef(elapsed * (30f / 1000f), 0, 1, 0); gl.glrotatef(elapsed * (15f / 1000f), 1, 0, 0); ondrawframe() 에서매프레임마다모델을조금씩회전시킴 안드로이드는여러다양한장치에서운용될수있음 매프레임마다회전각도를기억하여루프를반복할때마다각도를증가시키게되면, 빠른장치에서는빠르게회전하고느린장치에서는느리게회전함 위에서처럼경과된시간에따라이동시키면, 모든장치에서예측가능한움직임을얻을수있음. 다만빠른장치에서는더부드러운움직임을볼수있음
질감적용하기 실생활의모든것들은실은벽돌담이나정원자갈길의거친표면처럼질감이있음 ( 세상에완벽히매끄러운물체가있을까?) 래미네이트하듯이, 사진을물체위에덮어씌우는작업을함으로써, 질감을나타낼수있음 안드로이드 Portable Network Graphics (PNG) 형식의파일을 OpenGL이이해할수있는형식으로변환 (GLCube.loadTexture() ß GLRenderer. onsurfacecreated() 에서호출됨 ) Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resource); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); gl.gltexparameterx(gl10.gl_texture_2d, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.gltexparameterx(gl10.gl_texture_2d, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); bmp.recycle(); GLCube.loadTexture(gl, context, R.drawable.android); // GLRenderer. onsurfacecreated() GLCube() 의생성자에서텍스춰를저장하기위한자바 NIO 버퍼 (mtexturebuffer) 설정 //... ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4); tbb.order(byteorder.nativeorder()); mtexturebuffer = tbb.asintbuffer(); mtexturebuffer.put(texcoords); mtexturebuffer.position(0); GLCube().draw() 에서텍스춰버퍼를로드함 gl.gltexcoordpointer(2, GL10.GL_FIXED, 0, mtexturebuffer); R.drawable.android 는 res/drawable/android.png 파일
GLCube.java (1) class GLCube { private final IntBuffer mvertexbuffer; private final IntBuffer mtexturebuffer; public GLCube() { int one = 65536; int half = one / 2; int vertices[] = { /* FRONT */ -half, -half, half, half, -half, half, -half, half, half, half, half, half, /* BACK */ -half, -half, -half, -half, half, -half, half, -half, -half, half, half, -half, /* LEFT */ -half, -half, half, -half, half, half, -half, -half, -half, -half, half, -half, /* RIGHT */ half, -half, -half, half, half, -half, half, -half, half, half, half, half, /* TOP */ -half, half, half, half, half, half, -half, half, -half, half, half, -half, /* BOTTOM */ -half, -half, half, -half, -half, -half, half, -half, half, half, -half, -half, }; int texcoords[] = { /* FRONT */ 0, one, one, one, 0, 0, one, 0, /* BACK */ one, one, one, 0, 0, one, 0, 0, /* LEFT */ one, one, one, 0, 0, one, 0, 0, /* RIGHT */ one, one, one, 0, 0, one, 0, 0, /* TOP */ one, 0, 0, 0, one, one, 0, one, /* BOTTOM */ 0, 0, 0, one, one, 0, one, one, }; ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(byteorder.nativeorder()); mvertexbuffer = vbb.asintbuffer(); mvertexbuffer.put(vertices); mvertexbuffer.position(0); //... ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4); tbb.order(byteorder.nativeorder()); mtexturebuffer = tbb.asintbuffer(); mtexturebuffer.put(texcoords); mtexturebuffer.position(0); }
GLCube.java (2) public void draw(gl10 gl) { gl.glvertexpointer(3, GL10.GL_FIXED, 0, mvertexbuffer); gl.gltexcoordpointer(2, GL10.GL_FIXED, 0, mtexturebuffer); gl.glcolor4f(1, 1, 1, 1); gl.glnormal3f(0, 0, 1); gl.gldrawarrays(gl10.gl_triangle_strip, 0, 4); gl.glnormal3f(0, 0, -1); gl.gldrawarrays(gl10.gl_triangle_strip, 4, 4); gl.glcolor4f(1, 1, 1, 1); gl.glnormal3f(-1, 0, 0); gl.gldrawarrays(gl10.gl_triangle_strip, 8, 4); gl.glnormal3f(1, 0, 0); gl.gldrawarrays(gl10.gl_triangle_strip, 12, 4); gl.glcolor4f(1, 1, 1, 1); gl.glnormal3f(0, 1, 0); gl.gldrawarrays(gl10.gl_triangle_strip, 16, 4); gl.glnormal3f(0, -1, 0); gl.gldrawarrays(gl10.gl_triangle_strip, 20, 4); } static void loadtexture(gl10 gl, Context context, int resource) { Bitmap bmp = BitmapFactory.decodeResource( context.getresources(), resource); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); gl.gltexparameterx(gl10.gl_texture_2d, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.gltexparameterx(gl10.gl_texture_2d, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); bmp.recycle(); } }
훔쳐보기 화면에디스플레이되는모델객체을부분적으로투명하게만들수있음 GLRenderer.onSurfaceCreated() 에서설정함 boolean SEE_THRU = true; //... if (SEE_THRU) { gl.gldisable(gl10.gl_depth_test); gl.glenable(gl10.gl_blend); gl.glblendfunc(gl10.gl_src_alpha, GL10.GL_ONE); } 전경 ( 前景 ) 의대상뿐만아니라, 가려진부분도보기위해깊이확인을비활성화함 사물의투명도가알파채널에기초하게만드는블렌딩모드를활성화함 알파채널을질감안의 RGB의평균값으로잡았는데, 3D 그래픽에서특히속도가중요한상황에서는색상이얼마나밝은지 (Intensity) 를대략측정하는방법으로간주될수있음
투명하게한후, 실행화면
요약 OpenGL ES 에서모델을만드는방법을알아본다. 조명및카메라설정에대해알아본다. 모델을회전시키는방법에대해알아본다. 질감을적용하는방법에대해알아본다. 모델을투명하게하는방법에대해알아본다.
퀴즈 삼각스트립이란무엇인가? 고정소수점이란무엇인가? 고정소수점메서드의이름은무엇으로끝나고, 부동소수점메서드의이름은무엇으로끝나는가? Ambient, Diffuse, Specular 조명에대해설명하라. 자바 NIO 버퍼에대해설명하라. 물체를회전시키기위해서어떤함수를사용하는가? 물체에질감을적용하기위해서는어떠한일들을해야하는가?
연습문제 나무껍질이미지나, 벽돌이미지와같은, 다른이미지를사용하며질감을나타내보자. 그리고사람얼굴을붙여보자. EditText / Button 이나 Spinner 와같은위젯을붙여서, 정육면체의투명도와회전속도를조절할수있게해보자. 정육면체의투명도나회전속도를사용자의터치이벤트를받아들여조절할수있는지알아보자. 예를들어, 터치하면일단멈추고, 빠르게드래깅하면빠르게돌아가고, 느리게드래깅하면느리게돌아가게할수있을까? OpenAL 에대해알아보라. 안드로이드에서 OpenAL 을지원할계획인가? 만일 OpenAL 을안드로이드에포팅해서사용하려면어떻게해야할까?