Output looks like
Menu
|
Per-Vertex
|
Per-Pixel
|
Directional Lighting, illuminates all objects equally from a given direction, like an area light of infinite size and infinite distance from the scene; there is shading, but cannot be any distance falloffFor detailed theory, you can refer here and here which offers great theoretical part of lightings. I have nothing new to explain.
In this post I’ll try to show coding difference between per-vertex and per-pixel shading.
First we’ll look at shader code and then remaining rendering part
Vertex Shader
Per-Vertex
|
Per-Pixel
|
|
|
In Per-Vertex approach we are calculating color weight based in the object normals and light normal. but in Per-Pixel approach we are transforming normals and passing to Fragment shader. we need to transform the normals as we are transforming position vertices co-ordinates.
For vertex shader, we are taking vertex normals of Sphere along with vertices as input. As usual passing model-view matrix for calculating object vertex position with respective to current projection.
We also need normals for model view matrix for transforming vertex normals, which we will use for calculating lighting brightness. I’ll explain how to calculate this normals later in below sections.
We need two more variable for lighting parameters such as light direction, light color. I assumed ambience color as (r:0.2, g:0,2, b:0,2) for calculations.
A varying variable, v_colorWeight, for passing the calculated result to fragment shader.
Calculations are very simple, we are here transforming normals and calculating the light color weight for modifying objects’s color.
Fragment Shader
Per-Vertex
|
Per-Pixel
|
String strFShaderPV = |
|
in Per-Vertex approach we are combining calculated color weight from vertex shader. but in Per-Pixel approach we taking the normals and performing all the calculations in Fragment Shader.
Let’s look at remaining code part.
Two new classes I have created in common package for Mat3 for 3X3 matrix calculation andMesh class for creating sphere and cube (as of now, will add loading 3DS, OBJ and other file support on the go).
Renderer
in constructor of renderer we are creating a sphere and getting vertex, texture coordinates and index buffers for local reference.public LightRenderer(ES2SurfaceView view)
{sphere = new Mesh();
sphere.Sphere(4, 10);curView = view;normalMat = new Mat3();
cubeBuffer = sphere.getVertexBuffer();normalsBuffer = sphere.getNormalsBuffer();indexBuffer = sphere.getIndecesBuffer();texBuffer = sphere.getTextureBuffer();}
public void onDrawFrame(GL10 gl) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);GLES20.glUseProgram(iProgId);cubeBuffer.position(0);GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, cubeBuffer);
GLES20.glEnableVertexAttribArray(iPosition);texBuffer.position(0);GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 0,texBuffer);
GLES20.glEnableVertexAttribArray(iTexCoords);normalsBuffer.position(0);GLES20.glVertexAttribPointer(iNormals, 3, GLES20.GL_FLOAT, false, 0, normalsBuffer);
GLES20.glEnableVertexAttribArray(iNormals);GLES20.glActiveTexture(GLES20.GL_TEXTURE0);GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, iTexId);GLES20.glUniform1i(iTexLoc, 0);GLES20.glUniform3fv(iLightColor, 1, m_fLightColor, 0);GLES20.glUniform3fv(iLightDirection, 1, m_fLightDir, 0);GLES20.glUniform3fv(iSpecColor, 1, m_fSpecColor, 0);GLES20.glUniform1f(iShine, fShine);Matrix.setIdentityM(m_fModel, 0);Matrix.rotateM(m_fModel, 0, -xAngle, 0, 1, 0);Matrix.rotateM(m_fModel, 0, -yAngle, 1, 0, 0);Matrix.multiplyMM(m_fMVPMatrix, 0, m_fVPMatrix, 0, m_fModel, 0);GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, m_fMVPMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphere.m_nIndeces, GLES20.GL_UNSIGNED_SHORT, indexBuffer);}
If you like to know how to mathematically calculate, refer here.
A Little bit of Android, Creating Options Menu
There are two ways of loading menus. One from coding and other from resource.
Here I have done in code, as we have only two items for menu
We have to override two methods in activity.
- public boolean onCreateOptionsMenu(Menu menu)
- public boolean onOptionsItemSelected(MenuItem item)
public boolean onCreateOptionsMenu(Menu menu) {menu.add(Menu.NONE, 0, Menu.NONE, "Per Vertex");
menu.add(Menu.NONE, 1, Menu.NONE, "Per Pixel");
return super.onCreateOptionsMenu(menu);}
With this we create menu with two items “Per-Pixel” and “Per-Vertex” with ids 0 and 1 respectively.
To handle menu event we have to implement onOptionsItemSelected method.
public boolean onOptionsItemSelected(MenuItem item) {if (item.getItemId() == 0)
{view.LoadProgram(item.getItemId());} else if (item.getItemId() == 1){view.LoadProgram(item.getItemId());} else {
return super.onOptionsItemSelected(item);}return true;}
In this method I’m calling view’s LoadProgram function to switch between Per-Vertex and Per-Pixel shader programs.
That’s it in this post.
thanks for sharing your knowledge!
ReplyDelete