View Full Version : Triangle - Shade

01-29-2014, 06:25 AM
Hello to everyone,

Iím fighting with OpenGLES, with shaders and matrix. I need to display triangles and shade them according to a directional light.

My code is the following.

public void OnDrawFrame (Javax.Microedition.Khronos.Opengles.IGL10 gl)
gl.GlClear((int)GL10.GlColorBufferBit | GL10.GlDepthBufferBit);

// Draw the heightmap.
// Translate the heightmap into the screen.
Matrix.SetIdentityM(mModelMatrix, 0);
Matrix.TranslateM(mModelMatrix, 0, 0.0f, 0.0f, iZoomLevel);

// scaling
Matrix.SetIdentityM(mScaleMatrix, 0);
Matrix.ScaleM(mScaleMatrix, 0, scaleX, scaleY, scaleZ);

// Set a matrix that contains the current rotation.
Matrix.SetIdentityM(mCurrentRotation, 0);
Matrix.RotateM(mCurrentRotation, 0, mAngleX, 0.0f, 1.0f, 0.0f);
Matrix.RotateM(mCurrentRotation, 0, mAngleY, 1.0f, 0.0f, 0.0f);
mAngleX = 0.0f;
mAngleY = 0.0f;

// Multiply the current rotation by the accumulated rotation, and then
// set the accumulated rotation to the result.
Matrix.MultiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.Array.Copy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);

Matrix.MultiplyMM(mTemporaryMatrix, 0, mScaleMatrix, 0, mAccumulatedRotation, 0);
System.Array.Copy(mTemporaryMatrix, 0, mScaleMatrix, 0, 16);

// Rotate the cube taking the overall rotation into account.
Matrix.MultiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mScaleMatrix, 0); //mAccumulatedRotation, 0);
System.Array.Copy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);

// This multiplies the view matrix by the model matrix, and stores
// the result in the MVP matrix
// (which currently contains model * view).
Matrix.MultiplyMM(mMVPMatrix, 0, mVMatrix, 0, mModelMatrix, 0);

Matrix.MultiplyMV(lightDirInEyeSpace, 0, mTemporaryMatrix, 0, lightDirInModelSpace, 0);

// This multiplies the modelview matrix by the projection matrix,
// and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.MultiplyMM(mTemporaryMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
System.Array.Copy(mTemporaryMatrix, 0, mMVPMatrix, 0, 16);

mTriangle1.Draw (mMVPMatrix, mVMatrix, lightDirInEyeSpace);
mTriangle2.Draw (mMVPMatrix, mVMatrix, lightDirInEyeSpace);

public void OnSurfaceCreated (Javax.Microedition.Khronos.Opengles.IGL10 gl, Javax.Microedition.Khronos.Egl.EGLConfig config)
// Set the background clear color to black.
GLES20.GlClearColor(1.0f, 1.0f, 1.0f, 0.0f);

// Enable depth testing

// Position the eye in front of the origin.
float eyeX = 0.0f;
float eyeY = 0.0f;
float eyeZ = -0.5f;

// We are looking toward the distance
float lookX = 0.0f;
float lookY = 0.0f;
float lookZ = -5.0f;

// Set our up vector. This is where our head would be pointing were we
// holding the camera.
float upX = 0.0f;
float upY = 1.0f;
float upZ = 0.0f;

// Set the view matrix. This matrix can be said to represent the camera
// position.
// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination
// of a model and view matrix. In OpenGL 2, we can keep track of these
// matrices separately if we choose.
Matrix.SetLookAtM(mVMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

// Initialize the accumulated rotation matrix
Matrix.SetIdentityM(mAccumulatedRotation, 0);

mTriangle1 = new Triangle ();
mTriangle1.SetVerts(0f,0f,0, 0.5f,0.0f,0, 0.0f,0.5f,0);
mTriangle2 = new Triangle ();
mTriangle2.SetVerts(0f,0f,0, 0.0f, 0.5f,0.0f, 0f,0.0f,0.5f);

My triangle class:

class Triangle
private FloatBuffer vertexBuffer;
private int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mMVMatrixHandle;
private int mLightDirHandle;
private int mNormalHandle;

// number of coordinates per vertex in this array
static int COORDS_PER_VERTEX = 3;
float[] triangleCoords = new float [] { // in counterclockwise order:
-0.5f, -0.5f, 0.0f, // top
0.5f, -0.5f, 0.0f, // bottom left
0.0f, 0.5f, 0.0f // bottom right
private int vertexCount = 3; //triangleCoords.Length / COORDS_PER_VERTEX;
private int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

// Set color with red, green, blue and alpha (opacity) values
float[] color = new float[] {
1.0f };

public Triangle ()
// initialize vertex byte buffer for shape coordinates
// (number of coordinate values * 4 bytes per float)
ByteBuffer bb = ByteBuffer.AllocateDirect ( triangleCoords.Length * 4);
// use the device hardware's native byte order
bb.Order (ByteOrder.NativeOrder ());

// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.AsFloatBuffer ();
// add the coordinates to the FloatBuffer
vertexBuffer.Put (triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.Position (0);

// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.LoadShader (GLES20.GlVertexShader,
int fragmentShader = MyGLRenderer.LoadShader (GLES20.GlFragmentShader,

mProgram = GLES20.GlCreateProgram (); // create empty OpenGL Program
GLES20.GlAttachShader (mProgram, vertexShader); // add the vertex shader to program
GLES20.GlAttachShader (mProgram, fragmentShader); // add the fragment shader to program
GLES20.GlLinkProgram (mProgram); // create OpenGL program executables

public void SetVerts(float v0, float v1, float v2, float v3, float v4, float v5,
float v6, float v7, float v8)
triangleCoords[0] = v0;
triangleCoords[1] = v1;
triangleCoords[2] = v2;
triangleCoords[3] = v3;
triangleCoords[4] = v4;
triangleCoords[5] = v5;
triangleCoords[6] = v6;
triangleCoords[7] = v7;
triangleCoords[8] = v8;

// set the buffer to read the first coordinate

public void Draw (float[] mvpMatrix, float[] mvMatrix, float[] lightDirInEyeSpace)
// Add program to OpenGL environment
GLES20.GlUseProgram (mProgram);

// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.GlGetAttribLocation (mProgram, "vPosition");

// Enable a handle to the triangle vertices
GLES20.GlEnableVertexAttribArray (mPositionHandle);
// Prepare the triangle coordinate data
GLES20.GlVertexAttribPointer (mPositionHandle, COORDS_PER_VERTEX,
GLES20.GlFloat, false,
vertexStride, vertexBuffer);

// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.GlGetUniformLocation (mProgram, "uMVPMatrix");
MyGLRenderer.CheckGlError ("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.GlUniformMatrix4fv (mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.CheckGlError ("glUniformMatrix4fv");


mMVMatrixHandle = GLES20.GlGetUniformLocation (mProgram, "u_MVMatrix");
MyGLRenderer.CheckGlError ("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.GlUniformMatrix4fv(mMVMatrixHandle, 1, false, mvMatrix, 0);
MyGLRenderer.CheckGlError ("glUniformMatrix4fv");

// get handle to shape's transformation matrix
mLightDirHandle = GLES20.GlGetUniformLocation (mProgram, "u_LightDir");
MyGLRenderer.CheckGlError ("glGetUniformLocation");

// Apply the projection and view transformation
GLES20.GlUniform3f(mLightDirHandle, lightDirInEyeSpace[0], lightDirInEyeSpace[1], lightDirInEyeSpace[2] );
MyGLRenderer.CheckGlError ("GlUniform4f");

// get handle to normal
mNormalHandle = GLES20.GlGetUniformLocation (mProgram, "a_Normal");
MyGLRenderer.CheckGlError ("glGetUniformLocation");

// calc normal
float x = (triangleCoords[4] - triangleCoords[1]) * (triangleCoords[8] - triangleCoords[2]) - (triangleCoords[5] - triangleCoords[2]) * (triangleCoords[7] - triangleCoords[1]);
float y = (triangleCoords[5] - triangleCoords[2]) * (triangleCoords[6] - triangleCoords[0]) - (triangleCoords[3] - triangleCoords[0]) * (triangleCoords[8] - triangleCoords[2]);
float z = (triangleCoords[3] - triangleCoords[0]) * (triangleCoords[7] - triangleCoords[1]) - (triangleCoords[4] - triangleCoords[1]) * (triangleCoords[6] - triangleCoords[0]);

// Apply the projection and view transformation
GLES20.GlUniform3f(mNormalHandle, x, y, z );
MyGLRenderer.CheckGlError ("GlUniform3f");


// Draw the triangle
GLES20.GlDrawArrays(GLES20.GlTriangles, 0, vertexCount);
//GLES20.GlDrawElements (GLES20.GlTriangles, drawOrder.Length,
// GLES20.GlUnsignedShort, drawListBuffer);

// Disable vertex array
GLES20.GlDisableVertexAttribArray (mPositionHandle);

My shaders are:

uniform mat4 uMVPMatrix;
uniform mat4 u_MVMatrix;
uniform vec3 u_LightDir;

attribute vec4 vPosition;
uniform vec4 a_Color;
uniform vec3 a_Normal;

varying vec3 v_Color;
vec3 materialColor;

void main()
materialColor = vec3(1,0,0);
vec4 newNormal = u_MVMatrix * vec4(a_Normal, 0.0);
float lightIntensity = max(0.0, dot(newNormal.xyz, u_LightDir));
v_Color = materialColor * lightIntensity;

gl_Position = uMVPMatrix * vPosition;

precision mediump float;

varying vec3 v_Color;

void main()
gl_FragColor = vec4(v_Color, 1.0);
gl_FragColor = v_Color;

Triangles are not displayed with the right shading.

Could you help me ? Thank you in advance.

Keven Corazza

01-29-2014, 07:41 AM
What output did you expect and what you've got instead?

01-29-2014, 08:54 AM
I need a simple thing: I've some triangles that could represent a surface. I need to have a shading in order to understand the shape of the surface otherwise everything seems flat.

In the example there are two triangles one on the plane formed by axis x-y and one on the plane formed by axis y-z.

One triangle is everytime black, the other assume red gradation according to the rotation of the view but the result is not exactly the expected.

I don't know if the problem is in vertex shader or if it caused by something else.

I would like to attach an image but it seems no possible inthis forum.

Thank you in advance.

Keven Corazza

What output did you expect and what you've got instead?

01-29-2014, 10:41 AM
Are your normals normalized?

01-29-2014, 11:35 AM
I've just modified the shader in this way:

+ " vec4 newNormal = u_MVMatrix * vec4(normalize(a_Normal), 0.0); \n"
+ " float lightIntensity = max(0.0, dot(newNormal.xyz, u_VectorToLight)); \n"
+ " v_Color = materialColor * lightIntensity; \n"

Normals are now normalized. But the result doesn't change.

Other ideas ? Matrixes are right ?

Keven Corazza

01-29-2014, 11:40 AM
Using a debugger might be a good idea.
Otherwise, hard to tell at a glance without seeing the output.

01-29-2014, 12:12 PM
Also, make sure that the light direction vector is normalized and that its w component is set to zero prior to multiplying it with matrices.

01-29-2014, 10:29 PM
Do you know where I can find a simple example that do what I need ?

I don't need textures or other complex things. Just view triangle surfaces.

Thank you in advance.