Related
Hello I am trying to render texture on two triangles. glGetError() does not return any error. I can render colored rectangle, but texture does not work. Shaders are compiled without errors. Why this code does not work? (Image)
class MainRenderer implements GLSurfaceView.Renderer {
int vertexBuffer;
int indexBuffer;
int shaderProgram;
int texture;
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(1, 0, 0, 1);
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
texture = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
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);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, BitmapFactory.decodeResource(MainActivity.MainActivityHandle.getResources(), R.drawable.pes), 0);
float vertices[] = {
1, 1,
1, 0,
0, 0,
0, 1
};
int indices[] = {
0, 1, 3,
1, 2, 3
};
String vertexShaderCode = "attribute vec2 position; vec2 texturePosition; void main(){texturePosition = position;gl_Position = vec4(position,0.0, 1.0);}";
String fragmentShaderCode = "precision mediump float;uniform sampler2D texture; vec2 texturePosition; void main(){gl_FragColor = texture2D(texture, texturePosition);}";
int vertexBuffers[] = new int[1];
GLES20.glGenBuffers(1, vertexBuffers, 0);
vertexBuffer = vertexBuffers[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffer);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 4 * 2 * 4, FloatBuffer.wrap(vertices), GLES20.GL_STATIC_DRAW);
int indexBuffers[] = new int[1];
GLES20.glGenBuffers(1, indexBuffers, 0);
indexBuffer = indexBuffers[0];
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, 2 * 3 * 4, IntBuffer.wrap(indices), GLES20.GL_STATIC_DRAW);
int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
GLES20.glLinkProgram(shaderProgram);
}
#Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(shaderProgram);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffer);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
int positionAttributeHandle = GLES20.glGetAttribLocation(shaderProgram, "position");
GLES20.glEnableVertexAttribArray(positionAttributeHandle);
GLES20.glVertexAttribPointer(positionAttributeHandle, 2, GLES20.GL_FLOAT, false, 2*4, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
GLES20.glDisableVertexAttribArray(positionAttributeHandle);
}
}
I can at least see that you are using (in vertex and fragment shaders) just 'vec2 texturePosition', while you should use a 'varying' for output from vertex shader to the fragment shader. Try adding 'varying' before 'vec2 ...' in shaders.
So, I'm trying to make a simple 3d engine based on OpenGL ES 2 (Android). First (apart from many tutorials and such), I copy-pasted code from developer.android.com tutorial step-by-step. Everything worked fine. Then I started to modify it. I changed Mesh class' fields and constructor so that vertex coordinates, shader codes, color and number of vertices are not preset (all the code is at the end of the question).
Changed a Mesh field in GL20Renderer class to private List<Mesh> meshs = new ArrayList<Mesh>();. Created functions for adding and removing meshs. The only add function used at the moment in my code is the following:
public void addMesh( Mesh meshToAdd ) {
meshs.add( meshToAdd );
}
The only change in GL20Renderer.onDrawFrame() is that the code there loops through mesh list and calls Mesh.draw() method for every mesh:
for( Mesh meshToDraw : meshs ) {
meshToDraw.draw(scratch);
}
Then I tried to add one mesh from GL20Renderer.onSurfaceCreated() method - it worked fine. Add another mesh from the same method - works fine.
And then I tried to add a mesh from GL20Activity.onCreate() method (while removing the same code from GL20Renderer.onSurfaceCreated()):
float[] vertexCoords = { 0.0f, 0.622008459f, 0.0f, -0.5f, -0.311004243f, 0.0f, 0.5f, -0.311004243f, 0.0f };
int[] drawOrder = { 1, 2, 3 };
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
String vertexShaderCode = "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main() {" + " gl_Position = uMVPMatrix * vPosition;" + "}";
String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}";
renderer.addMesh( new Mesh( 3, vertexCoords, drawOrder, 1, color, vertexShaderCode, fragmentShaderCode) );
Mesh gets added to mesh list but doesn't get displayed for some reason (it's properties are the same as the tutorial's mesh's ones). If meshs are added from both GL20Activity.onCreate() and Renderer.onSurfaceCreated() - none of them gets displayed, but they're still on mesh list. Then I added onRendererInitialized() method to GL20Activity, which is called from the very end of GL20Renderer.onCreate() method. onRendererInited() just adds a mesh, and it gets displayed, but only if no mesh is added from GL20Activity.onCreate().
The question is: Why does that mesh not get drawn if it's added from GL20Activity.onCreate() method? I tried changing vertices' coordinates so they are not the cause of a problem. I have also tried to add some code to GL20Renderer.onDrawFrame() to make sure that meshToDraw.draw( scratch ); line of code runs properly, and it does run properly, but still mesh doesn't get drawn. But since mesh with same vertices' coordinates and color added from GL20Activity.onRendererInitialized() and/or from GL20Renderer.onSurfaceCreated() gets drawn, there shouldn't be any problem with drawing mesh, which is added from GL20Activity.onCreate().
MainActivity.java:
package com.Reaper.VisionEngine;
import android.app.*;
import android.content.*;
import android.os.*;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState {
super.onCreate(savedInstanceState);
Intent intent = new Intent( this, GL20Activity.class );
startActivity( intent );
}
}
GL20Activity.java:
package com.Reaper.VisionEngine;
import android.app.*;
import android.os.*;
import android.widget.*;
import com.Reaper.VisionEngine.GLRenderer.*;
import com.Reaper.VisionEngine.GLSurfaceView.*;
import com.Reaper.VisionEngine.Mesh.*;
import java.io.*;
public class GL20Activity extends Activity {
GL20SurfaceView GLView;
GL20Renderer renderer;
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
GLView = new GL20SurfaceView(this);
setContentView(GLView);
renderer = GLView.getRenderer();
float[] vertexCoords = { 0.0f, 0.622008459f, 0.0f, -0.5f, -0.311004243f, 0.0f, 0.5f, -0.311004243f, 0.0f };
int[] drawOrder = { 1, 2, 3 };
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
String vertexShaderCode = "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main() {" + " gl_Position = uMVPMatrix * vPosition;" + "}";
String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}";
renderer.addMesh( new Mesh( 3, vertexCoords, drawOrder, 1, color, vertexShaderCode, fragmentShaderCode) );
}
GL20Renderer.java:
package com.Reaper.VisionEngine.GLRenderer;
import android.opengl.*;
import com.Reaper.VisionEngine.*;
import com.Reaper.VisionEngine.Mesh.*;
import java.util.*;
import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.*;
import javax.microedition.khronos.egl.EGLConfig;
public class GL20Renderer implements GLSurfaceView.Renderer {
private List<Mesh> meshs = new ArrayList<Mesh>();
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private float[] mRotationMatrix = new float[16];
public volatile float mAngle;
private List<Mesh> meshQueue = new ArrayList<Mesh>();
private GL20Activity activity;
public void onSurfaceCreated(GL10 gl, EGLConfig glConfig) {
GLES20.glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
}
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
float[] scratch = new float[16];
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
for( Mesh meshToDraw : meshs ) {
meshToDraw.draw(scratch);
}
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void addMesh( Mesh meshToAdd ) {
meshs.add( meshToAdd );
}
GL20SurfaceView.java:
package com.Reaper.VisionEngine.GLSurfaceView;
import android.content.*;
import android.opengl.*;
import android.view.*;
import com.Reaper.VisionEngine.*;
import com.Reaper.VisionEngine.GLRenderer.*;
public class GL20SurfaceView extends GLSurfaceView {
private final GL20Renderer Renderer;
public GL20SurfaceView(Context context) {
super(context);
setEGLContextClientVersion(2);
Renderer = new GL20Renderer();
setRenderer(Renderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public boolean onTouchEvent(MotionEvent e) { // TODO: CHANGE THIS
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
requestRender();
}
return true;
}
public GL20Renderer getRenderer() {
return Renderer;
}
}
Mesh.java:
package com.Reaper.VisionEngine.Mesh;
import android.opengl.*;
import com.Reaper.VisionEngine.GLRenderer.*;
import java.nio.*;
public class Mesh {
private FloatBuffer vertexBuffer;
public final int GL20Program;
private int PositionHandle;
private int ColorHandle;
private int MVPMatrixHandle;
private int colorOverridesTexture = 0;
private int vertexCount = 1;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private int[] drawOrder; // TODO: Implement
static final int COORDS_PER_VERTEX = 3;
private float vertexCoords[];
float color[] = new float[3];
private String vertexShaderCode;
private String fragmentShaderCode;
private final String defaultVertexShaderCode = "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "void main() }" + " gl_Position = uMVPMatrix * vPosition;" + "}";
private final String defaultFragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() }" + " gl_FragColor = vColor;" + "}";
public Mesh( int newVertexCount, float[] newVertexCoords, int[] newDrawOrder, int useColor, float[] newColor, String newVertexShaderCode, String newFragmentShaderCode ) {
vertexCount = newVertexCount;
vertexCoords = newVertexCoords;
drawOrder = newDrawOrder;
colorOverridesTexture = useColor;
color = newColor;
vertexShaderCode = newVertexShaderCode;
fragmentShaderCode = newFragmentShaderCode;
ByteBuffer bb = ByteBuffer.allocateDirect( vertexCoords.length * 4 );
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put( vertexCoords );
vertexBuffer.position( 0 );
int vertexShader = GL20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = GL20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
GL20Program = GLES20.glCreateProgram();
GLES20.glAttachShader(GL20Program, vertexShader);
GLES20.glAttachShader(GL20Program, fragmentShader);
GLES20.glLinkProgram(GL20Program);
}
public void draw(float[] mvpMatrix) {
MVPMatrixHandle = GLES20.glGetUniformLocation(GL20Program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glUseProgram(GL20Program);
PositionHandle = GLES20.glGetAttribLocation(GL20Program, "vPosition");
GLES20.glEnableVertexAttribArray(PositionHandle);
GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
ColorHandle = GLES20.glGetUniformLocation(GL20Program, "vColor");
GLES20.glUniform4fv(ColorHandle, 1, color, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
GLES20.glDisableVertexAttribArray(PositionHandle);
}
}
Sorry for bad english.
I think at your GL20Activity.onCreate() stage, the EGL context is not available or not made current. Hence the mesh added there, the gl* commands in Mesh's constructor will fail. Even though the mesh object is added to the list, the corresponding OpenGL elements are not initialized so the draw will fail, or draw nothing. You can verify this by checking for OpenGL errors after gl* statements in Mesh's constructor when called from GL20Activity.onCreate().
Now when you do the same at the GL20Renderer.onSurfaceCreated(), (I think that's what you mean by GL20Renderer.onCreated()) the EGL context is available and valid so all gl* commands in Mesh's constructor will execute and hence the mesh's OpenGL components exist, so it is displayed correctly.
Since this method is called at the beginning of rendering, as well as
every time the EGL context is lost, this method is a convenient place
to put code to create resources that need to be created when the
rendering starts, and that need to be recreated when the EGL context
is lost. Textures are an example of a resource that you might want to
create here.
refer https://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html for more info.
I developed a simple JOGL rendering a Cube on the screen, followed the same procedure that would work on OpenGL ES 2 from IPhone. but this piece of code does not displaying anything when it is ran.
can someone help to take a browse and point out what is the problem?
Here is my Code
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.FPSAnimator;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
public class TestScene extends JFrame implements GLEventListener {
private static final float[] CUBE_POSITIONS = {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
};
private static final short[] INDICIES = {
0, 1, 2, 0, 2, 3,//front
2, 1, 5, 6, 2, 5,//right
7, 6, 4, 6, 5, 4,//back
7, 4, 3, 3, 4, 0,//right
6, 7, 2, 7, 3, 2,//top
0, 4, 1, 1, 4, 5,//bottom
};
private GL4 gl;
private int program;
private Matrix4f projection = new Matrix4f();
private Matrix4f viewing = new Matrix4f();
private Matrix4f translation = new Matrix4f();
private int projectionIndex;
private int viewingMatrix;
private int transIndex;
private int positionIndex;
private int vbo;
private int vio;
public TestScene() throws HeadlessException {
super("Testing");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final GLCanvas canvas = new GLCanvas(new GLCapabilities(GLProfile.get(GLProfile.GL4)));
final FPSAnimator animator = new FPSAnimator(25);
animator.add(canvas);
animator.start();
canvas.addGLEventListener(this);
getContentPane().add(canvas);
setSize(800, 600);
setVisible(true);
}
#Override
public void init(final GLAutoDrawable drawable) {
gl = drawable.getGL().getGL4();
try {
//init program and shader
final int vertexShader = createShader("/Users/gang_liu/Develop/Java/ideaProject/KLM/JOGL_Studies_1/vertex.glsl", GL4.GL_VERTEX_SHADER);
final int fragmentShader = createShader("/Users/gang_liu/Develop/Java/ideaProject/KLM/JOGL_Studies_1/fragment.glsl", GL4.GL_VERTEX_SHADER);
program = gl.glCreateProgram();
gl.glAttachShader(program, vertexShader);
gl.glAttachShader(program, fragmentShader);
gl.glLinkProgram(program);
//generate vbo
final IntBuffer intBuffer = IntBuffer.allocate(1);
gl.glGenBuffers(1, intBuffer);
vbo = intBuffer.get();
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo);
gl.glBufferData(GL.GL_ARRAY_BUFFER, CUBE_POSITIONS.length * Buffers.SIZEOF_FLOAT, FloatBuffer.wrap(CUBE_POSITIONS), GL.GL_STATIC_DRAW);
intBuffer.flip();
//generate vio
gl.glGenBuffers(1, intBuffer);
vio = intBuffer.get();
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vio);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, INDICIES.length * Buffers.SIZEOF_SHORT, ShortBuffer.wrap(INDICIES), GL.GL_STATIC_DRAW);
//get program indexes
positionIndex = gl.glGetAttribLocation(program, "position");
projectionIndex = gl.glGetUniformLocation(program, "projection");
viewingMatrix = gl.glGetUniformLocation(program, "view");
transIndex = gl.glGetUniformLocation(program, "trans");
//init projection matrix;
final int width = getWidth();
final int height = getHeight();
projection.perspective(45.0f, (float)width/height, 1.0f, 100.0f);
viewing.lookAt(new Vector3f(0.0f, 0.0f, 10.0f), new Vector3f(0.0f, 0.0f, 0.0f), new Vector3f(0.0f, 1.0f, 0.0f));
} catch (final Exception ex){
ex.printStackTrace();
}
}
#Override
public void dispose(GLAutoDrawable drawable) {
}
#Override
public void display(final GLAutoDrawable drawable) {
gl.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
gl.glEnable(GL4.GL_CULL_FACE);
gl.glEnable(GL4.GL_DEPTH_TEST);
gl.glClearDepth(1.0);
gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);
gl.glUseProgram(program);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vbo);
gl.glEnableVertexAttribArray(positionIndex);
gl.glVertexAttribPointer(positionIndex, 3, gl.GL_FLOAT, false, Buffers.SIZEOF_FLOAT * 3, 0);
gl.glUniformMatrix4fv(projectionIndex, 1, false, FloatBuffer.wrap(projection.get(new float[16])));
gl.glUniformMatrix4fv(viewingMatrix, 1, false, FloatBuffer.wrap(viewing.get(new float[16])));
gl.glUniformMatrix4fv(transIndex, 1, false, FloatBuffer.wrap(translation.get(new float[16])));
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vio);
gl.glDrawElements(gl.GL_TRIANGLES, INDICIES.length, gl.GL_UNSIGNED_SHORT, 0);
gl.glUseProgram(0);
}
#Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
}
private int createShader(final String fileName, final int type) throws IOException {
final int shaderID = gl.glCreateShader(type);
final StringBuilder sb = new StringBuilder();
final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
gl.glShaderSource(shaderID, 1, new String[]{sb.toString()}, null, 0);
gl.glCompileShader(shaderID);
final IntBuffer intBuffer = IntBuffer.allocate(1);
gl.glGetShaderiv(shaderID, gl.GL_COMPILE_STATUS, intBuffer);
if (intBuffer.get() == gl.GL_FALSE) {
intBuffer.flip();
gl.glGetShaderiv(shaderID, gl.GL_INFO_LOG_LENGTH, intBuffer);
final int logLength = intBuffer.get();
final ByteBuffer byteBuffer = ByteBuffer.allocate(logLength);
gl.glGetShaderInfoLog(shaderID, logLength, null, byteBuffer);
System.out.println("Filed to compile " +
(type == GL4.GL_VERTEX_SHADER ? "vertex shader" : "fragment shader")
+ " shader :\n" + new String(byteBuffer.array()));
}
return shaderID;
}
public static void main(String[] args) {
new TestScene();
}
}
here are the shader files
vertex shader
#version 400
uniform lowp mat4 trans;
uniform lowp mat4 view;
uniform lowp mat4 projection;
in lowp vec3 position;
out lowp vec3 out_color;
void main(){
gl_Position = projection * view * trans * vec4(position, 1.0);
out_color = position;
}
fragment shader
#version 400
in lowp vec3 out_color;
out vec4 fragColor;
void main(){
fragColor = vec4(out_color, 1.0);
}
I know I should calculate uniform matrix in CPU. again, this is just good for debugging.
beside of this problem, I have another question. it seems some opengl functions related of a program like glGetAttribLocation and glGetUniformLocation has program parameter, so does that mean we do not have to call glUseProgram ahead of these function invocations? is that assumption correct? any opinion regarding on this question is welcome.
Thanks
So, I received this code from another post to SO. It seems to be the most complete working code for adding textures in openGl 2.0 with shaders in android. How does he know what integer to pass into textureResourceId, and how do I set-up a resource Id to the .png files I put into my project?
Here's the link to the SO post I'm reffering to:
Android OpenGL|ES 2.0 Texturing
And here's the Square Code:
public class Square{
private static final String TAG = "Square";
public float[] rotation = {0.0f,0.0f,45.0f};
public float[] scale = {100.0f,100f,100f};
public float[] position = {0.0f,0.0f,100f};
public float[] color = { 0.0f, 0.0f, 1.0f, 1.0f };
private int textureRef = -1;
private int mMVPMatrixHandle;
protected int DRAW_MODE = GLES20.GL_TRIANGLES;
protected int mProgram;
protected int mPositionHandle;
protected Vertex vertices;
protected Vertex texture;
private int mColorHandle;
private int vsTextureCoord;
private int fsTexture;
protected float[] result_matrix = new float[16];
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec3 vPosition;" +
"attribute vec2 TexCoordIn;" +
"varying vec2 TexCoordOut;" +
"void main() {" +
//the matrix must be included as a modifier of gl_Position
" gl_Position = uMVPMatrix * vec4(vPosition,1.0);" +
" TexCoordOut = TexCoordIn;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D Texture;" +
"varying lowp vec2 TexCoordOut;" +
"void main() {" +
" gl_FragColor = vColor*TexCoordOut*Texture;" +
"}";
//I am fully aware that I am not using the texture by assigning the colour, but until I can actually SEND the texture through, there would be no point.
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
public Square(int textureResourceId) {
int vertexShader = GFXUtils.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = GFXUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
textureRef = GFXUtils.textures.get(textureResourceId);
// initialize vertex byte buffer for shape coordinates
vertices = new Vertex(squareCoords, drawOrder, GFXUtils.COORDS_PER_VERTEX);
texture = new Vertex (new float[]
{
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
}, GFXUtils.COORDS_PER_TEXTURE);
DRAW_MODE = GLES20.GL_TRIANGLE_FAN;
}
private void getHandles()
{
//get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
if (mPositionHandle == -1) Log.e(TAG, "vPosition not found");
//get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
if (mColorHandle == -1) Log.e(TAG, "vColor not found");
//get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
if (mMVPMatrixHandle == -1) Log.e(TAG, "uMVPMatrix not found");
//get handle to texture coordinate variable
vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "TexCoordIn");
if (vsTextureCoord == -1) Log.e(TAG, "TexCoordIn not found");
//get handle to shape's texture reference
fsTexture = GLES20.glGetUniformLocation(mProgram, "Texture");
if (fsTexture == -1) Log.e(TAG, "Texture not found");
}
private void translateRotateScale(float[] matrix, float[] perspectiveMatrix)
{
for (int i= 0; i < perspectiveMatrix.length;i++)
matrix[i] = perspectiveMatrix[i];
Matrix.translateM(matrix, 0, position[0], position[1], position[2]);
Matrix.rotateM(matrix, 0, rotation[0], 1.0f, 0.0f, 0.0f);
Matrix.rotateM(matrix, 0, rotation[1], 0.0f, 1.0f, 0.0f);
Matrix.rotateM(matrix, 0, rotation[2], 0.0f, 0.0f, 1.0f);
Matrix.scaleM(matrix, 0, scale[0], scale[1], scale[2]);
}
public void draw(float[] mvpMatrix) {
rotation[2]+=0.5;
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
GFXUtils.checkGlError("using program");
//Housekeeping
getHandles();
translateRotateScale(result_matrix, mvpMatrix);
//end housekeeping
// Set color for drawing the shape
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, result_matrix, 0);
GFXUtils.checkGlError("glUniformMatrix4fv");
// Prepare the shape coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, GFXUtils.COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
GFXUtils.vertexStride, vertices.floatBuffer);
GFXUtils.checkGlError("load vertex buffer");
GLES20.glVertexAttribPointer(vsTextureCoord, GFXUtils.COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
GFXUtils.textureStride, texture.floatBuffer);
GFXUtils.checkGlError("load texture buffer - " + vsTextureCoord);
// Enable a handle to the shape vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
GFXUtils.checkGlError("enable position handle");
GLES20.glEnableVertexAttribArray(vsTextureCoord);
GFXUtils.checkGlError("enable texture handle");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GFXUtils.checkGlError("activtexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureRef);
GFXUtils.checkGlError("bindtexture");
GLES20.glUniform1i(fsTexture, 0);
GFXUtils.checkGlError("uniformi");
//Draw the shape
GLES20.glDrawElements(DRAW_MODE, vertices.numIndeces, GLES20.GL_UNSIGNED_SHORT, vertices.indexBuffer);
GFXUtils.checkGlError("glDrawArrays with " + vertices.numVertices + " vertices");
//Disable vertex array
GLES20.glDisableVertexAttribArray(vsTextureCoord);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GFXUtils.checkGlError("glDisableVertexAttribArray for position");
}
}
My Main Activity Class:
public class MainActivity extends ActionBarActivity {
GLSurfaceView myGL;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGL=new MySurface(this);
setContentView(myGL);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
//---------------------------------Open GL-------------------------------------------------------
class MySurface extends GLSurfaceView
{
private MyRenderer myRend;
public MySurface(Context context)
{
super(context);
myRend=new MyRenderer();
setEGLContextClientVersion(2);
setRenderer(myRend);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
Square mSquare;
float [] mViewMatrix=new float[16];
float [] mMVPMatrix=new float[16];
float [] mProjectionMatrix=new float[16];
private float[] mRotationMatrix=new float[16];
class MyRenderer implements GLSurfaceView.Renderer
{
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1f);
mSquare=new Square(R.drawable.brick_texture);
}
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
mSquare.draw(mMVPMatrix);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 50);
}
}
}
Anything I render outside of the range 1 to -1 (in the z-range) just doesn't appear on the screen. I've been trying everything, including using different matrices to try to transform vertices outside of 1 to -1 into this range but nothing seems to work.
I'll put my code in below. It consists of a model class where data is stored, a shader program(which I won't include - its pretty simple) and a main class.
Vertex Shader
#version 330 core
in vec4 in_Position;
in vec4 in_Color;
out vec4 pass_Color;
void main(void) {
gl_Position = in_Position;
pass_Color = in_Color;
}
Fragment Shader
#version 330 core
in vec4 pass_Color;
out vec4 out_Color;
void main(void) {
out_Color = pass_Color;
}
Model Class
package util;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL20.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
public class Model {
// Vertex Array ID
int vaoID;
// VBO ID's
int vboVertexID, vboColorID, vboIndexID;
// Vertex Count
int numVertices, numIndices;
public Model(FloatBuffer vertexData, int vertexCount, FloatBuffer colorData, int colorCount, ByteBuffer indexData, int indexCount) {
// Create the vertex array
vaoID = glGenVertexArrays();
// Select the vertex array
bind();
// Attach vertex data
attachVertexData(vertexData, vertexCount);
// Attach Color data
attachColorData(colorData, colorCount);
// Deselect the vertex array
unbind();
// Indice attachment
attachIndexArray(indexData);
// Set the vertex count
numVertices = vertexCount;
numIndices = indexCount;
}
/**
* Attach some vertex data
*/
public void attachVertexData(FloatBuffer vertexData, int vertexCount) {
// Create the buffer
vboVertexID = glGenBuffers();
// Bind the new buffer
glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
// Give the data to the GPU
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
// Set the location of the data within the vertex array
glVertexAttribPointer(0, vertexCount, GL_FLOAT, false, 0, 0);
// Deselect this buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
/**
* Attach some color data
*/
public void attachColorData(FloatBuffer colorData, int colorCount) {
// Create the buffer
vboColorID = glGenBuffers();
// Bind the new buffer
glBindBuffer(GL_ARRAY_BUFFER, vboColorID);
// Give the data to the GPU
glBufferData(GL_ARRAY_BUFFER, colorData, GL_STATIC_DRAW);
// Set the location of the data within the vertex array
glVertexAttribPointer(1, colorCount, GL_FLOAT, false, 0, 0);
// Deselect this buffer
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
/**
* Attach the index data
*/
public void attachIndexArray(ByteBuffer indexData) {
// Create the buffer
vboIndexID = glGenBuffers();
// Bind it
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);
// Put the data in
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData, GL_STATIC_DRAW);
// Unbind the buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);
}
/**
* Enable the buffers
*/
public void enableAttribArrays() {
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
}
/**
* Disable buffers
*/
public void disableAttribArrays() {
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
/**
* Bind the Model
*/
public void bind() {
glBindVertexArray(vaoID);
}
/**
* Unbind the Model
*/
public void unbind() {
glBindVertexArray(0);
}
/**
* Bind the indices
*/
public void bindIndexBuffer() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexID);
}
/**
* Unbind the indices buffer
*/
public void unbindIndexBuffer() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
/**
* Draw the vertex array
*/
public void drawArray() {
glDrawElements(GL_TRIANGLE_STRIP, numIndices, GL_UNSIGNED_BYTE, 0);
}
}
Main Class
package d3;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL20.*;
import util.Game;
import util.Model;
import util.ShaderProgram;
public class Pyramidion {
ShaderProgram shader;
Model model;
public Pyramidion() {
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create(new PixelFormat(), new ContextAttribs(3, 2).withForwardCompatible(true).withProfileCore(true));
Display.setVSyncEnabled(true);
} catch (LWJGLException e) {
e.printStackTrace();
}
init();
while(!Display.isCloseRequested()) {
render();
Display.update();
}
Display.destroy();
}
public void init() {
Display.setTitle("Pyramid");
glViewport(0, 0, Display.getWidth(), Display.getHeight());
// Shader Initialization
setupShader();
// Model Init
setupModel();
}
private void setupModel() {
int verticesCount = 4;
float[] verticesData = {
-0.5f, +0.5f, -10f, 1f, // Top Left
-0.5f, -0.5f, 0f, 1f, // Bottom Left
+0.5f, -0.5f, 0f, 1f, // Bottom Right
+0.5f, +0.5f, 0f, 1f // Top Right
};
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(verticesData.length);
verticesBuffer.put(verticesData); verticesBuffer.flip();
int colorCount = 4;
float[] colorData = {
0f, 1f, 0f, 1f, // Green
1f, 0f, 0f, 1f, // Red
0f, 0f, 1f, 1f, // Blue
1f, 1f, 1f, 1f // White
};
FloatBuffer colorBuffer = BufferUtils.createFloatBuffer(colorData.length);
colorBuffer.put(colorData); colorBuffer.flip();
int indicesCount = 6;
byte[] indicesData = {
0, 1, 2,
2, 3, 0
};
ByteBuffer indicesBuffer = BufferUtils.createByteBuffer(indicesData.length);
indicesBuffer.put(indicesData); indicesBuffer.flip();
// Create Model
model = new Model(verticesBuffer, verticesCount, colorBuffer, colorCount, indicesBuffer, indicesCount);
}
private void setupShader() {
shader = new ShaderProgram();
shader.attachVertexShader("src/d3/vertex.vert");
shader.attachFragmentShader("src/d3/fragment.frag");
shader.link();
shader.bindAtrribLocation(0, "in_Position");
shader.bindAtrribLocation(1, "in_Color");
}
public void render() {
glClear(GL_COLOR_BUFFER_BIT);
shader.bind();
model.bind();
model.enableAttribArrays();
model.bindIndexBuffer();
model.drawArray();
model.unbindIndexBuffer();
model.disableAttribArrays();
model.unbind();
ShaderProgram.unbind();
}
public static void main(String[] args) {
new Pyramidion();
}
}
EDIT: Added the setup for matrices I had
Vertex Shader
#version 330 core
uniform mat4 model_Matrix;
uniform mat4 view_Matrix;
uniform mat4 projection_Matrix;
in vec4 in_Position;
in vec4 in_Color;
out vec4 pass_Color;
void main(void) {
gl_Position = projection_Matrix * view_Matrix * model_Matrix * in_Position;
//gl_Position = in_Position;
pass_Color = in_Color;
}
Code that sets up the Matrices
private void setupMatrices() {
// Model - Identity Matrix
model_Matrix = new Mat4(1.0f);
shader.setUniformMat4("model_Matrix", model_Matrix);
// View - translate it forward
view_Matrix = new Mat4(1f);
shader.setUniformMat4("view_Matrix", view_Matrix);
// Projection - simple perspective
projection_Matrix = Matrices.perspective(60, Display.getWidth() / Display.getHeight(), 0.1f, 100f);
projection_Matrix = Matrices.ortho(-1, 1, 1, -1, 0.1f, 100f);
projection_Matrix = new Mat4(1);
shader.setUniformMat4("projection_Matrix", projection_Matrix);
}
Have a close look to your vertex shader with matrix multiplications applied. Notably those two lines:
gl_Position = projection_Matrix * view_Matrix * model_Matrix * in_Position;
gl_Position = in_Position;
So you see it? Okay, look at the second line? What does it? It overwrites the gl_Position variable with the untransformed in_Position. Get rid of that and you should see matrices do their work.
Update
Next problem here
// Projection - simple perspective
projection_Matrix = Matrices.perspective(60, Display.getWidth() / Display.getHeight(), 0.1f, 100f);
projection_Matrix = Matrices.ortho(-1, 1, 1, -1, 0.1f, 100f);
projection_Matrix = new Mat4(1);
You should really settle for one matrix and stay with that. Right now you're just overwriting projecting_Matrix with a identity matrix.
In the calculation of the perspective matrix the division of display width and height will likely be an integer division with round-down. You have to cast the results of getWidth and getHeight to float first.
projection_Matrix =
Matrices.perspective(
60,
(float)Display.getWidth() / (float)Display.getHeight(),
0.1f, 100.f );
However I doubt you really want the display size there. More likely you want the viewport size use for the aspect ration calculation. Also 0.1 for near and 100 for far are not optimal values. You should choose near as large as possible.
It turns out I am an idiot. I was forgetting that when you upload a uniform to a shader you have to bind it first. That was the problem.