OpenGL ES 2.0 Practice 5 : Simple Texture
OpenGL ES 2.0 Practice 5 : Simple Texture
두 개의 Triangle 에 Texture를 맵핑합니다. Texture 맵핑을 위해 Texture Binding, Texture Coordinate 설정, Shader 코드에 sampler 를 추가 합니다.
첫번째 Texture 초기화 코드 입니다.
private void initTexture(Bitmap image) {
int name[] = new int[1];
GLES20.glGenTextures(1, name, 0);
if ( name[0] > 0 ) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, name[0]);
// setting parameters
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// use gl utils to load texture by Bitmap
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, image, 0);
// texture binding to 0
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
mTextureName = name[0];
}
else {
Log.e(TAG, "Fail to bind texture");
}
}
Texture 초기화 시 Image 데이터는 Bitmap을 이용하여 로딩 합니다.
다음은 Vertex(Position) 별 Texture mapping 정보(Texture Coordinate)를 설정합니다.
public SimpleTexture(Context context) {
// create shader program
mProgram = createProgram(SHADER_TYPE_TEXTURE);
float position[] = {
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
// same direction (z direction)
float normal[] = {
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
};
// texture coordinate
float texCoord[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
mPosition = createFloatBuffer(position);
mNormal = createFloatBuffer(normal);
mTexCoord = createFloatBuffer(texCoord);
// init matrix value
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.setIdentityM(mViewMatrix, 0);
Matrix.translateM(mViewMatrix, 0, 0.0f, 0.0f, -2.5f);
Matrix.setIdentityM(mProjMatrix, 0);
// initializing the texture
Bitmap texImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.mountain02);
initTexture(texImage);
texImage.recycle();
}
Shader 코드는 attribute 로 Texture Coordinate를 추가하고 uniform sampler2D 를 추가하여 Binding 된 Texture 와 연결하도록 합니다
// vertex shader, added texture coordinate attribute
"precision mediump float;\n" +
"attribute vec3 aPosition;\n" +
"attribute vec3 aNormal;\n" +
"attribute vec2 aTexCoord;\n" +
"uniform mat4 uProjMatrix;\n" +
"uniform mat4 uViewMatrix;\n" +
"uniform mat4 uModelMatrix;\n" +
"uniform vec3 uLightColor;\n" +
"uniform vec3 uLightDir;\n" +
"uniform vec3 uMaterialDiffuse;\n" +
"varying vec3 vColor;\n" +
"varying vec2 vTexCoord;\n" +
"void main() {\n" +
" vTexCoord = aTexCoord;\n" +
" gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition, 1.0);\n" +
" vec3 normal_cameraspace = (uViewMatrix * uModelMatrix * vec4(aNormal, 1.0)).xyz;\n" +
" vec3 lightdir_cameraspace = (uViewMatrix * vec4(uLightDir, 1.0)).xyz;" +
" vec3 n = normalize(normal_cameraspace);\n" +
" vec3 l = normalize(lightdir_cameraspace);\n" +
" float cosTheta = clamp( dot(n, l), 0.0, 1.0);" +
" vColor = uMaterialDiffuse * uLightColor * cosTheta;" +
"}\n"
// fragment shader
"precision mediump float;\n" +
"uniform sampler2D sTexture0;\n" +
"varying vec3 vColor;\n" +
"varying vec2 vTexCoord;\n" +
"void main() {\n" +
" vec4 texColor = texture2D(sTexture0, vTexCoord);\n" +
" gl_FragColor = vec4(vColor, 1.0f) * texColor;\n" +
"}\n"
마지막으로, Shader 코드와 연동하여 Rendering을 수행합니다.
@Override
public void draw() {
GLES20.glUseProgram(mProgram);
// screen clear color
GLES20.glClearColor(0.6f, 0.6f, 0.6f, 1.0f);
// clear screen
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
int aPositionLoc = GLES20.glGetAttribLocation(mProgram, "aPosition");
GLES20.glVertexAttribPointer(aPositionLoc, 3, GLES20.GL_FLOAT, false, 0, mPosition);
int aNormalLoc = GLES20.glGetAttribLocation(mProgram, "aNormal");
GLES20.glVertexAttribPointer(aNormalLoc, 3, GLES20.GL_FLOAT, false, 0, mNormal);
int aTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
GLES20.glVertexAttribPointer(aTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, mTexCoord);
// light color
GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uLightColor"), 0.8f, 0.8f, 0.8f);
// triangle material color
GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uMaterialDiffuse"), 1.0f, 1.0f, 1.0f);
// light dir
GLES20.glUniform3f(GLES20.glGetUniformLocation(mProgram, "uLightDir"), 1.0f, -1.0f, -1.0f);
// triangle model matrix
// no transform (identity matrix)
// y-axis, 1 degree rotation every frames
Matrix.rotateM(mModelMatrix, 0, 1.0f, 0.0f, 1.0f, 0.0f);
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uModelMatrix"), 1, false, mModelMatrix, 0);
// view matrix
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uViewMatrix"), 1, false, mViewMatrix, 0);
// projection matrix
GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(mProgram, "uProjMatrix"), 1, false, mProjMatrix, 0);
GLES20.glEnableVertexAttribArray(aPositionLoc);
GLES20.glEnableVertexAttribArray(aNormalLoc);
GLES20.glEnableVertexAttribArray(aTexCoordLoc);
// active texture 0
GLES20.glUniform1i(GLES20.glGetUniformLocation(mProgram, "sTexture0"), 0);
// binding texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureName);
// rendering
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
// binding texture to 0
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glDisableVertexAttribArray(aPositionLoc);
GLES20.glDisableVertexAttribArray(aNormalLoc);
GLES20.glDisableVertexAttribArray(aTexCoordLoc);
// starting gl command buffer, non-block
GLES20.glFlush();
}
결과 화면 (Nexus 7 2nd, Android 6)