Related
I am testing to draw a textured sprite with opengl es 2.0. on android.
Demo works fine when I set ortho projection from - scr_w/2 to +scr_w/2 and - scr_h/ to +scr_h/2 with origin in middle of screen.
However if I translate to what I expect : 480 width (scr_w) and 720 (scr_h) height coordinate system + origin on top left corner of screen.
then Texture rendering goes wrong.
Matrix.orthoM(mProjectionMatrix, 0, 0, scr_w,0, scr_h, -1, 1); //then texture rendering doesn't work ?
I have tried to set Matrix.setLookAtM differently to point from (240,360,5) to (240,360,0)
//Matrix.setLookAtM(mViewMatrix, 0, scr_w/2, scr_h/2, 5, scr_w/2, scr_h/2, 0f, 0f, 1.0f, 0.0f); // then texture rendering doesn't work ?
The Renderer class:
public class SimpleRenderer implements GLSurfaceView.Renderer{
private final Context ctx;
static int scr_w = 480;
static int scr_h = 720;
private final float[] mViewMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
private Sprite spt1;
SimpleRenderer(final Context context)
{
this.ctx = context;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
//Set the background color
GLES20.glClearColor(0.0f, 0.0f, 2.0f, 1.0f);
//Disable depth test
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
// Set alpha blend on
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
spt1 = new Sprite(ctx);
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
Matrix.orthoM(mProjectionMatrix, 0, -scr_w/2, scr_w/2,-scr_h/2, scr_h/2, -1, 1);
// Matrix.orthoM(mProjectionMatrix, 0, 0, scr_w,0, scr_h, -1, 1); // DOESNT WORK ?
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0, 0, 0f, 0f, 1.0f, 0.0f);
//Matrix.setLookAtM(mViewMatrix, 0, scr_w/2, scr_h/2, 5, scr_w/2, scr_h/2, 0f, 0f, 1.0f, 0.0f); // DOESN'T WORK
// Mix the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
public void onDrawFrame(GL10 unused)
{
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
spt1.Draw(mMVPMatrix);
}}
The Sprite Class maybe mess with shader or fragment in 2D coordinates?
public class Sprite
{
//Reference to Activity Context
private final Context mActivityContext;
//Added for Textures
private final FloatBuffer mCubeTextureCoordinates;
private int mTextureUniformHandle;
private int mTextureCoordinateHandle;
private final int mTextureCoordinateDataSize = 2;
private int mTextureDataHandle;
private final String vertexShaderCode =
"attribute vec2 a_TexCoordinate; \n" +
"varying vec2 v_TexCoordinate; \n" +
"uniform mat4 uMVPMatrix; \n" +
"attribute vec4 vPosition; \n" +
"void main() { \n" +
" gl_Position = vPosition * uMVPMatrix; \n" +
" v_TexCoordinate = a_TexCoordinate; \n" +
"} \n";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"gl_FragColor = (vColor * texture2D(u_Texture, v_TexCoordinate));" +
"}";
private final int shaderProgram;
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 2;
static float spriteCoords[] = {
-50f, 50f, // top left
-50f, -50f, // bottom left
50f, -50f, // bottom right
50f, 50f //top right
};
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; //Order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; //Bytes per vertex
float color[] = { 1f, 1f, 1f, 1.0f };
public Sprite(final Context activityContext)
{
mActivityContext = activityContext;
//Initialize Vertex Byte Buffer
ByteBuffer bb = ByteBuffer.allocateDirect(spriteCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(spriteCoords);
vertexBuffer.position(0);
final float[] TextureCoordinate =
{
1f, 0f,
1f, 1f,
0f, 1f,
0f, 0f
};
mCubeTextureCoordinates = ByteBuffer.allocateDirect(TextureCoordinate.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(TextureCoordinate).position(0);
//Initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
//Texture Code
GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
GLES20.glLinkProgram(shaderProgram);
//Load the texture
mTextureDataHandle = loadTexture(mActivityContext, R.drawable.cathead);
}
public void Draw(float[] mvpMatrix)
{
//Add program to OpenGL ES Environment
GLES20.glUseProgram(shaderProgram);
//Get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
//Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
//Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
//Get Handle to Fragment Shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor");
//Set the Color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//Set Texture Handles and bind Texture
mTextureUniformHandle = GLES20.glGetAttribLocation(shaderProgram, "u_Texture");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");
//Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
//Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
//Pass in the texture coordinate information
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
//Get Handle to Shape's Transformation Matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
//Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glEnable(GLES20.GL_BLEND_COLOR);
GLES20.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLES20.glDepthMask(false);
//Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
//Disable Vertex Array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
public static int loadShader(int type, String shaderCode)
{
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
I'm trying to draw a disc in OpenGL-ES 2.0. Based on the second answer to this question How to draw basic circle in OpenGL ES 2.0 Android by user2901066, I'm doing:
String VertexShaderCode ="uniform mat4 uMVPMatrix;\n" +
"attribute vec4 vPosition;\n" +
"void main() {\n" +
"gl_Position = uMVPMatrix * vPosition;\n" +
"}";
String FragmentShaderCode = "precision mediump float;\n" +
"void main() {\n" +
//The problem is here
//"if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)" +
"if (true)\n" +
"gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n" +
"else\n" +
"gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" +
"}";
int vertexShader = this.loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode);
int fragmentShader = this.loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode);
mGlProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mGlProgram, vertexShader);
GLES20.glAttachShader(mGlProgram, fragmentShader);
GLES20.glLinkProgram(mGlProgram);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
protected int PositionHandle;
protected int MVPMatrixHandle;
static final int COORDS_PER_VERTEX = 3;
private final int VertexStride = COORDS_PER_VERTEX * 4;
private float LineCoords[] = new float[4 * 3];
private FloatBuffer VertexBuffer;
private final int VertexCount = 4;
ByteBuffer bb = ByteBuffer.allocateDirect(LineCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
VertexBuffer = bb.asFloatBuffer();
VertexBuffer.put(LineCoords);
VertexBuffer.position(0);
float[] mvpMatrix = {1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f};
LineCoords[0] = -1.0f;
LineCoords[1] = 1.0f;
LineCoords[3] = -1.0f;
LineCoords[4] = -1.0f;
LineCoords[6] = 1.0f;
LineCoords[7] = -1.0f;
LineCoords[9] = 1.0f;
LineCoords[10] = 1.0f;
VertexBuffer.put(LineCoords);
VertexBuffer.position(0);
GLES20.glUseProgram(mGlProgram);
PositionHandle = GLES20.glGetAttribLocation(mGlProgram, "vPosition");
GLES20.glEnableVertexAttribArray(PositionHandle);
GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VertexStride, VertexBuffer);
MVPMatrixHandle = GLES20.glGetUniformLocation(mGlProgram, "uMVPMatrix");
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, VertexCount);
GLES20.glDisableVertexAttribArray(PositionHandle);
My problem is to get the position in the fragment shader in order to apply the right color. How do I do that?
You need a varying variable declared on both shaders:
varying vec2 textureCoord;
then on the vertex shader, put some value to it such as:
textureCoord = gl_Position.xy;
this variable will then be sent to the fragment shader interpolated for each fragment so your fragment shader can use it:
if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)
{
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
} else {
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);
}
This problem bothers me for about a week...
I tried to load stl files and show it on the screen. The file was read properly. Rendering without adding light was pretty good. After I add lighting and shader codes, the model is still there but turns out black.
I followed the example downloaded from link below this article:
http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/
The shader code was completely as the same as the example. The program links fine. The Shaders compile fine, too. I can't find out where the problem is. PLZ help me.
My Renderer:
public class MyGLRenderer implements GLSurfaceView.Renderer {
private Test test;
private Light1 light1;
private float range = 145;
private final float[] mMVMMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
private final float[] mModelMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
protected final static float[] mLightPosInEyeSpace = new float[4];
private final float[] mLightModelMatrix = new float[16];
private final float[] mLightPosInModelSpace = new float[] {0.0f, 0.0f, 0.0f, 1.0f};
private final float[] mLightPosInWorldSpace = new float[4];
private final float[] mTempMatrix = new float[16];
public static final float[] mAccumulatedMatrix = new float[16];
private final float[] mCurrMatrix = new float[16];
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthFunc(GLES20.GL_LEQUAL);
Matrix.setIdentityM(mTempMatrix, 0);
Matrix.setIdentityM(mAccumulatedMatrix, 0);
light1 = new Light1();
test = new Test();
}
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Matrix.setIdentityM(mViewMatrix, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.setIdentityM(mCurrMatrix, 0);
Matrix.setIdentityM(mLightModelMatrix, 0);
Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);
Matrix.rotateM(mCurrMatrix, 0, mAngleY, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mCurrMatrix, 0, mAngleX, 1.0f, 0, 0.0f);
mAngleX = 0.0f;
mAngleY = 0.0f;
Matrix.multiplyMM(mTempMatrix, 0, mCurrMatrix, 0, mAccumulatedMatrix, 0);
System.arraycopy(mTempMatrix, 0, mAccumulatedMatrix, 0, 16);
Matrix.multiplyMM(mTempMatrix, 0, mModelMatrix, 0, mAccumulatedMatrix, 0);
System.arraycopy(mTempMatrix, 0, mModelMatrix, 0, 16);
Matrix.translateM(mModelMatrix, 0, -test.meanX, -test.meanY, -test.meanZ);
Matrix.multiplyMM(mMVMMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVMMatrix, 0);
light1.draw(mMVPMatrix);
test.draw(mMVPMatrix, mMVMMatrix);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.orthoM(mProjectionMatrix, 0, -range*ratio, range*ratio, -range, range, -range, range);
}
public final static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public static volatile float mAngleX;
public static volatile float mAngleY;
public static void setAngleX(float angle) {mAngleX = angle;}
public float getAngleX() {
return mAngleX;
}
public static void setAngleY(float angle) {
mAngleY = angle;
}
public float getAngleY() {
return mAngleY;
}}
My code to draw where the light is:
public class Light1 {
private final String vertexShaderCode =
"uniform mat4 u_MVPMatrix; \n"
+ "attribute vec4 a_Position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_MVPMatrix \n"
+ " * a_Position; \n"
+ " gl_PointSize = 5.0; \n"
+ "} \n";
private final String fragmentShaderCode =
"precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(1.0, \n"
+ " 1.0, 1.0, 1.0); \n"
+ "} \n";
//Light*******************
public static float[] lightLocation = new float[] {150, 150, 0};//*********ok
private final int mProgram;
//Light*******************
public Light1() {
// initialize byte buffer for the draw list
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) {
GLES20.glUseProgram(mProgram);
final int pointMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
final int pointPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
GLES20.glVertexAttrib3f(pointPositionHandle, lightLocation[0], lightLocation[1], lightLocation[2]);
GLES20.glUniformMatrix4fv(pointMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
GLES20.glDisableVertexAttribArray(pointPositionHandle);
}}
My Model Code:
public class Test {
final String vertexShaderCode =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "uniform mat4 u_MVMatrix; \n" // A constant representing the combined model/view matrix.
+ "uniform vec3 u_LightPos; \n" // The position of the light in eye space.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "attribute vec3 a_Normal; \n" // Per-vertex normal information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
// Transform the vertex into eye space.
+ " vec3 modelViewVertex = vec3(u_MVMatrix * a_Position); \n"
// Transform the normal's orientation into eye space.
+ " vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0)); \n"
// Will be used for attenuation.
+ " float distance = length(u_LightPos - modelViewVertex); \n"
// Get a lighting direction vector from the light to the vertex.
+ " vec3 lightVector = normalize(u_LightPos - modelViewVertex); \n"
// Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
// pointing in the same direction then it will get max illumination.
+ " float diffuse = max(dot(modelViewNormal, lightVector), 0.1); \n"
// Attenuate the light based on distance.
+ " diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance))); \n"
// Multiply the color by the illumination level. It will be interpolated across the triangle.
+ " v_Color = a_Color * diffuse; \n"
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
+ " gl_Position = u_MVPMatrix * a_Position; \n"
+ "} \n";
private final String fragmentShaderCode =
"precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// triangle per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ \n"
+ " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private FloatBuffer normalBuffer;
private final int mProgram;
private int mPositionHandle;
private int mNormalHandle;
private int mLightLocationHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mMVMatrixHandle;
final int COORDS_PER_VERTEX = 3;
float[] squareCoords;
float[] coordsNormals;
float color[];
public Test() {
squareCoords = GlassUI10.ReadStlBinary("test.stl");
coordsNormals = VectorCalculate.getNormByPtArray(squareCoords);
color = new float[squareCoords.length/3*4];
for(int i = 0; i < color.length/4 ; i = i+4)
{
color[i+0] =0.3f;
color[i+1] =0.7f;
color[i+2] =0.6f;
color[i+3] =1.3f;
}
System.gc();
Log.v("TestLoaded: ", "Loaded");
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
colorBuffer = ByteBuffer.allocateDirect(color.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
colorBuffer.put(color).position(0);
ByteBuffer nb = ByteBuffer.allocateDirect(coordsNormals.length * 4);
nb.order(ByteOrder.nativeOrder());
normalBuffer = nb.asFloatBuffer();
normalBuffer.put(coordsNormals);
normalBuffer.position(0);
// initialize byte buffer for the draw list
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);//*********ok
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);//*********ok
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glBindAttribLocation(mProgram, 0, "a_Position");
GLES20.glBindAttribLocation(mProgram, 1, "a_Color");
GLES20.glBindAttribLocation(mProgram, 2, "a_Normal");
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix, float[] mvMatrix) {
GLES20.glUseProgram(mProgram);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVMatrix");
mLightLocationHandle = GLES20.glGetUniformLocation(mProgram, "u_LightPos");
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
mColorHandle = GLES20.glGetUniformLocation(mProgram, "a_Color");
mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_Normal");
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
colorBuffer.position(0);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
normalBuffer.position(0);
GLES20.glVertexAttribPointer(mNormalHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, normalBuffer);
GLES20.glEnableVertexAttribArray(mNormalHandle);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glUniform3f(mLightLocationHandle, MyGLRenderer.mLightPosInEyeSpace[0], MyGLRenderer.mLightPosInEyeSpace[1], MyGLRenderer.mLightPosInEyeSpace[2]);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, squareCoords.length/COORDS_PER_VERTEX); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}}
Any answer will be appreciated!
I fixed the problem.
First. The color-given loop was wrong. Be fixed below:
for(int i = 0; i < color.length ; i = i+4)
It caused only few surface being colored; But this was not the main point to cause the model being black;
The main point is that the distance in diffuse light formula is to big; It cause the diffuse to become a very small value which cause the color RGB goes extremely close to zero;
" diffuse = diffuse * (1.0 / (1.0 + (0.00000025 * distance * distance)));"
It need a better formula, but simply decrease the value of distance should show the color and light affect.
In your code, the COORDS_PER_VERTEX is 3. But in your shader code "attribute vec4 a_Position; \n", the a_Position is vec4.
So GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer); has incompatible vector size.
My code is almost exactly the same as the code on the website, with a few variable name changes:
package com.example.opengltraining;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
public class MyGL20Renderer implements GLSurfaceView.Renderer{
private Triangle triangle1;
private final float[] mProjMatrix = new float[16];
private final float[] mVMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
public static int loadShader(int type, String shaderCode){
//create vertex shader type
//or fragment shader type
int shader = GLES20.glCreateShader(type);
//add source code to shader and compile
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void redrawTriangle(float[]triangleCoords){
triangle1.changeTriangle(triangleCoords);
}
public void onSurfaceCreated(GL10 unused, EGLConfig config){
//set background fram color
GLES20.glClearColor(1f,0.5f, 0.25f, .5f);
triangle1 = new Triangle();
}
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
// Draw triangle
triangle1.draw(mMVPMatrix);
}
public void onSurfaceChanged(GL10 unused, int width, int height){
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
//applies projection matrix to object coordinates
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 2, 7);
}
}
class Triangle{
//shaders - vertex
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
//shaders - fragment
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
//number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.5f, 0.0f, // top
-0.5f, -0.25f, 0.0f, // bottom left
0.5f, -0.25f, 0.0f // bottom right
};
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4;
//color of triangle
float color[] = { 0f, 1f, 0f, 1.0f };
public void draw(float[] mvpMatrix) {
// 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.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
public void changeTriangle(float [] newTriangleCoords){
ByteBuffer bb = ByteBuffer.allocateDirect(newTriangleCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(newTriangleCoords);
vertexBuffer.position(0);
}
public Triangle(){
//init vertex buffer for shape cordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
//number of cord vals * 4 bytes per float
triangleCoords.length * 4);
//use hardware's native byte order
bb.order(ByteOrder.nativeOrder());
//create floating point buffer
vertexBuffer = bb.asFloatBuffer();
//add coords to floatbuffer
vertexBuffer.put(triangleCoords);
//set buffer to read first coord
vertexBuffer.position(0);
int vertexShader = MyGL20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGL20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
//creates program for the triangle to go in.,
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
}
}
I've already tested this code vs the original code without the added projection and camera views, and there is no difference between the two. Also, for some reason when I test this on an emulator it doesn't work, but it does work when I test it on an actual android phone (although the projection and camera views still don't work).
I've been trying to do the android dev-guide on OPENGLES20,
but when I run the code, I get only the background color drawn, and not the triangle (I'm done until the stretched triangle photo).
How can I get the triangle to show up?
(Running the app on Android 2.2 device)
Here's the code:
public class HelloOpenGLES20Renderer implements Renderer {
private FloatBuffer triangleVB;
private final String vertexShaderCode = "attribute vec4 vPosition; \n"
+ "void main(){ \n" + " gl_Position = vPosition; \n"
+ "} \n";
private final String fragmentShaderCode = "precision mediump float; \n"
+ "void main(){ \n"
+ " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
+ "} \n";
private int mProgram;
private int maPositionHandle;
private int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
false, 12, triangleVB);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
initShapes();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_VERTEX_SHADER,
fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
}
private void initShapes() {
float[] triangleCoords = new float[] {
// X,Y,Z
-0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0 };
ByteBuffer vbb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
vbb.order(ByteOrder.nativeOrder());
triangleVB = vbb.asFloatBuffer();
triangleVB.put(triangleCoords);
triangleVB.position(0);
}
}
I think you haven't followed the tutorial 100% properly. E.g in onSurfaceCreated(...) you call loadShader(GLES20.GL_VERTEX_SHADER..) twice while the latter one should be loadShader(GLES20.GL_FRAGMENT_SHADER..).