I am rendering a mesh using GLSL shaders and a VBO, and the VBO stores 4 attributes; positionXYZ, normalXYZ, textureUV, colourRGBA. Everything works, except for the UVs (possibly the normals too, but I haven't got a way to test them yet).
What is happening is, the texture UV positions in the array are offset to the normal x and y position in the array. The array is structured as VVVNNNTTCCCC (vertex position, normal, texture, colour) by the way. I am pretty sure that the problem is somewhere in sending the VBO to the shaders. I know for certain that the data in the VBO is in the correct order.
This is my rendering code:
The VBO class
public final class Mesh
{
public static final int FLOAT_SIZE_BYTES = 4;
public static final int FLOATS_PER_POSITION = 3;
public static final int FLOATS_PER_NORMAL = 3;
public static final int FLOATS_PER_TEXTURE = 2;
public static final int FLOATS_PER_COLOUR = 4;
public static final int VERTEX_SIZE_FLOATS = FLOATS_PER_POSITION + FLOATS_PER_NORMAL + FLOATS_PER_TEXTURE + FLOATS_PER_COLOUR;
public static final int VERTEX_SIZE_BYTES = VERTEX_SIZE_FLOATS * FLOAT_SIZE_BYTES;
public static final int POSITION_OFFSET_FLOATS = 0;
public static final int NORMAL_OFFSET_FLOATS = POSITION_OFFSET_FLOATS + FLOATS_PER_POSITION;
public static final int TEXTURE_OFFSET_FLOATS = NORMAL_OFFSET_FLOATS + FLOATS_PER_NORMAL;
public static final int COLOUR_OFFSET_FLOATS = TEXTURE_OFFSET_FLOATS + FLOATS_PER_TEXTURE;
public static final int POSITION_OFFSET_BYTES = POSITION_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int NORMAL_OFFSET_BYTES = NORMAL_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int TEXTURE_OFFSET_BYTES = TEXTURE_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int COLOUR_OFFSET_BYTES = COLOUR_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
public static final int POSITION_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int NORMAL_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int TEXTURE_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public static final int COLOUR_STRIDE_BYTES = VERTEX_SIZE_BYTES;
public final static int VERTICES_PER_FACE = 3;
public static final int ATTRIBUTE_LOCATION_POSITION = 0;
public static final int ATTRIBUTE_LOCATION_NORMAL = 1;
public static final int ATTRIBUTE_LOCATION_TEXTURE = 2;
public static final int ATTRIBUTE_LOCATION_COLOUR = 3;
private int vaoID;
private int iboID;
private int indexCount;
private Mesh(int vaoID, int iboID, int indexCount)
{
this.vaoID = vaoID;
this.iboID = iboID;
this.indexCount = indexCount;
}
public void draw(AbstractShaderProgram shader, Texture texture)
{
glEnable(GL_TEXTURE_2D);
if (texture != null) texture.bind(shader);
else Texture.MISSING_TEXTURE.bind(shader);
glBindVertexArray(vaoID);
glEnableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
// glEnableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
// glDisableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);
glBindVertexArray(0);
glDisable(GL_TEXTURE_2D);
}
public static Mesh compile(List<Face> faces)
{
if (faces.size() <= 0)
throw new RuntimeException("Failed to compile mesh. No faces were provided.");
HashMap<Vertex, Integer> indexMap = new HashMap<>();
ArrayList<Vertex> vertices = new ArrayList<>();
int vertexCount = 0;
for (Face face : faces)
{
for (Vertex vertex : face.getVertices())
{
if (!indexMap.containsKey(vertex))
{
indexMap.put(vertex, vertexCount++);
vertices.add(vertex);
}
}
}
int indicesCount = faces.size() * VERTICES_PER_FACE;
int dataSize = vertexCount * VERTEX_SIZE_FLOATS;
FloatBuffer vertexData = BufferUtils.createFloatBuffer(dataSize);
if (vertexData == null)
System.err.println("Failed to allocate FloatBuffer with size " + dataSize);
for (Vertex vertex : vertices)
{
vertexData.put(vertex.getPosition().x);
vertexData.put(vertex.getPosition().y);
vertexData.put(vertex.getPosition().z);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().x);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().y);
// vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().z);
// vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().x);
// vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().y);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().x);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().y);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().z);
// vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().w);
}
vertexData.flip();
IntBuffer indices = BufferUtils.createIntBuffer(indicesCount);
for (Face face : faces)
{
for (Vertex vertex : face.getVertices())
{
int index = indexMap.get(vertex);
indices.put(index);
}
}
indices.flip();
int vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
int vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
glVertexAttribPointer(ATTRIBUTE_LOCATION_POSITION, FLOATS_PER_POSITION, GL_FLOAT, false, 0, 0);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_NORMAL, FLOATS_PER_NORMAL, GL_FLOAT, false, NORMAL_STRIDE_BYTES, NORMAL_OFFSET_BYTES);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_TEXTURE, FLOATS_PER_TEXTURE, GL_FLOAT, false, TEXTURE_STRIDE_BYTES, TEXTURE_OFFSET_BYTES);
// glVertexAttribPointer(ATTRIBUTE_LOCATION_COLOUR, FLOATS_PER_COLOUR, GL_FLOAT, false, COLOUR_STRIDE_BYTES, COLOUR_OFFSET_BYTES);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
int iboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return new Mesh(vaoID, iboID, indicesCount);
}
}
The vertex shader:
#version 400 core
in vec3 vertPosition;
in vec3 vertNormal;
in vec2 vertTexture;
in vec4 vertColour;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
out vec3 pVertPosition;
out vec3 pVertNormal;
out vec2 pVertTexture;
out vec4 pVertColour;
void main()
{
pVertPosition = vertPosition;
pVertNormal = vertNormal;
pVertTexture = vertTexture;
pVertColour = vertColour;
gl_Position = vec4(vec3(vertPosition.xy + vertTexture, vertPosition.z), 1.0);
}
The fragment shader:
#version 400 core
in vec3 ppVertPosition;
in vec3 ppVertNormal;
in vec2 ppVertTexture;
in vec4 ppVertColour;
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture, ppVertTexture);
}
There is a geometry shader in between these, but it is currently redundant and just pases the information straight to the fragment shader (that is why the out and in variables don't match.) Also, the reason the textureUV is added to the vertex position in the fragment shader was to debug what the texture UV values being passed actually were. This is how I know the UVs are offset to the normal xy. If I put the texture UVs into the normal xy, they work perfectly fine.
If there is any extra code you would like to see, that I haven't included, I'll add it. I haven't added everything, for example, the whole VBO class, because it is too much code. I have only included what I think is relevant and where I think the problem is.
Edit #1:
The variable locations in the shader, such as vertPosition and vertNormal are bound. This is my code to bind them
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_POSITION, "vertPosition");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_NORMAL, "vertNormal");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_TEXTURE, "vertTexture");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_COLOUR, "vertColour");
Changing the vertex shader to use layouts, like so, yields the ex\ct same result;
layout(location = 0) in vec3 vertPosition;
layout(location = 1) in vec3 vertNormal;
layout(location = 2) in vec2 vertTexture;
layout(location = 3) in vec4 vertColour;
Edit #2
I decided to post the entire Mesh class, rather than just parts of it. I have also tried to implement VAOs instead of VBOs, but it isn't working.
You are mixing standard pipeline functionality with custom shader variables.
Calling glEnableClientState(GL_VERTEX_ARRAY); tells OpenGL to use a certain data bind point, all good.
Calling glVertexPointer( tells OpenGL where to find its vertices. Since you enabled the correct array previously, all is still good.
Then we get to the vertex shader and you use in vec3 vertPosition; but GLSL doesn't know that you want your vertex data there. Sure, we can see the name is "vertPosition", but GLSL shouldn't have to guess the data you want based on the variable name of course! Instead, the default pipeline behavior for GLSL is to use gl_Vertex, a pre built GLSL variable tied to GL_VERTEX_ARRAY.
So why does it work for positions? Sheer luck with the variables you define being allocated the pre-built constants by chance, I guess.
What you should do is switch glEnableClientState to glEnableVertexAttribArray, use Layouts to assign each variable a number, and call glVertexAttribPointer instead of glVertexPointer to link that number to the correct data.
Now, the variables you declared, like vertPosition, point to the right data in your buffers, not by chance, but because you told them to!
This is the correct way to do things in modern OpenGL, using the pre built variables like gl_Vertex and functions like glEnableClientState is considered old and bad because its inflexible.
You can also omit the layouts (because it requires OGL 4+, which not everyone has), but that requires some more work before linking the shaders.
Good luck!
More info on converting your code
(I hope im right with this, I cant comment to actually verify that this is the issue)
Okay, I got it working... finally. I have no idea what the initial problem was with the VBO, but once I switched to use a VAO, and not render with glClientState, it worked fine. Also, the problem I was having with the VAO not rendering anything what-so-ever was the line:
glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
should have been
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
Related
The main issue:
Good afternoon, everyone. I have such a question, when I use more than two textures in batch rendering, when using 2 textures (that is, my downloaded from disk), it starts glitching with the first texture (white), which in theory should not be because when the second texture is used from the texture slot, it becomes the main one for rendering. And this happens only in the perspective projection, everything is fine with the orthographic projection (most likely because it does not display the distance between objects and the Z-coordinate).
Here is a couple images of the issue:
Video
Google Drive
The whole problem is that I have a lot of code written and I think it will not make sense to throw off all of it. I will still show some pieces, but I would like you to express your assumption why this may happen. Maybe it's because I'm binding several texture slots at once. In general, I will be grateful to every advice or answer if it turns out.
Draw Sprite using batch rendering (Example)
public static void drawRectnagle(GameObject rect) {
var transform = rect.getComponent(Transform.class);
var spriteRenderer = rect.getComponent(SpriteRenderer.class);
// Begin new batch if in this batch not has room left.
if (batch.indexCount >= Batch.maxIndices)
newBatch();
int textureIndex = 0;
Vector2f[] textureCoords = batch.textureCoords;
Texture texture = null;
Vector4f color = null;
if(spriteRenderer != null) {
texture = spriteRenderer.texture;
color = spriteRenderer.color;
} else
color = new Vector4f(1, 1, 1, 1);
if(texture != null)
textureCoords = texture.getTextureCoords();
else
texture = batch.textures[0];
for (int i = 1; i < batch.textureIndex; i++) {
if (batch.textureIndex >= Batch.maxTextures)
newBatch();
// Equal texture by OpenGL ID's.
if (batch.textures[i].equals(texture)) {
textureIndex = i;
break;
}
}
if (textureIndex == 0.0f) {
textureIndex = batch.textureIndex;
batch.textures[batch.textureIndex] = texture;
batch.textureIndex++;
}
...
// Loading vertex data to batch.
...
}
Rendering batch after setting sprites data (Example)
private static void endBatch() {
if (batch.indexCount == 0)
return;
int sizeBytes = sizeof(Vertex.class); // NOTE: Size of Vertex class is currect here.
int size = batch.vertexIndex * sizeBytes;
batch.vertexBuffer.putData(batch.vertex, size, batch.vertexIndex, sizeBytes / 4);
// Bind each texture from slot.
for (int i = 0; i < batch.textureIndex; i++)
batch.textures[i].bind(i);
RenderEngine.EnableAlphaBlending();
RenderEngine.EnableDepthTesting();
glBindVertexArray(batch.vertexArray.get());
glDrawElements(GL_TRIANGLES, batch.vertexArray.getIndexBuffer().getCount(), GL_UNSIGNED_INT, 0);
RenderEngine.DisableAlphaBlending();
RenderEngine.DisableDepthTesting();
}
And if someone interest how my putData method works:
public void putData(Vertex[] vertex, int size, int index, int elementCount) {
//Convert all Vertex data to single float[] to pass as data in vertex buffer.
float[] data = ...
if(data != null) {
var pData = memAlloc(size).asFloatBuffer().put(data).flip();
glBindBuffer(GL_ARRAY_BUFFER, handle);
nglBufferData(GL_ARRAY_BUFFER, size, memAddress(pData), getOpenGLUsage(usage));
memFree(pData);
}
}
Fragment Shader
#version 450 core
layout (location = 0) out vec4 out_Pixel;
in vec3 position;
in vec4 color;
in vec2 textureCoord;
in float textureIndex;
uniform sampler2D u_Textures[32];
void main() {
vec4 texColour = vec4(1, 1, 1, 1);
texColour *= texture(u_Textures[int(textureIndex)], textureCoord);
vec4 finalColor = color * texColour;
if(finalColor.a < 0.1)
discard;
out_Pixel = finalColor;
}
I've a trouble with moving my entities in a OpenGL context:
when I try to place an entity, the position seems correct, but when the entity starts to move, everything is going wrong, and collisions don't work. I'm new to OpenGL, and I suspect my world matrix or model matrix to be wrong.
Here's the code of the vertex shader:
#version 330 core
layout (location=0) in vec3 position;
out vec3 extColor;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform vec3 inColor;
void main()
{
gl_Position = projectionMatrix * modelMatrix * vec4(position, 1.0);
extColor = inColor;
}
Here is the class that computes most of the Matrix:
public class Transformations {
private Matrix4f projectionMatrix;
private Matrix4f modelMatrix;
public Transformations() {
projectionMatrix = new Matrix4f();
modelMatrix = new Matrix4f();
}
public final Matrix4f getOrthoMatrix(float width, float height, float zNear, float zFar) {
projectionMatrix.identity();
projectionMatrix.ortho(0.0f, width, 0.0f, height, zNear, zFar);
return projectionMatrix;
}
public Matrix4f getModelMatrix(Vector3f offset, float angleZ, float scale) {
modelMatrix.identity().translation(offset).rotate(angleZ, 0, 0, 0).scale(scale);
return modelMatrix;
}
}
Here's the test for collisions:
public boolean isIn(Pos p) {
return (p.getX() >= this.pos.getX() &&
p.getX() <= this.pos.getX() + DIMENSION)
&& (p.getY() >= this.pos.getY() &&
p.getY() <= this.pos.getY() + DIMENSION);
}
Also, there's a link to the github project: https://github.com/ShiroUsagi-san/opengl-engine.
I'm really new to OpenGL 3 so I could have done some really big mistakes.
I'm also running i3 as WM, I don't really know if this could lead to this kind of issues.
I fixes the issues after thinking about how openGL and VBO work: Indeed, I was setting a new reference for each entity, so I had to change the line
Mesh fourmiMesh = MeshBuilder.buildRect(this.position.getX(), this.position.getY(), 10, 10);
to
Mesh fourmiMesh = MeshBuilder.buildRect(0, 0, 10, 10);
It was a confusion that I made between the positions of the vertex in a VBO and the positions in my world.
Hope that misunderstood helps people to understand.
I am new to OpenGL and I have a Triangle that gets created to my surfaceView which in turns shows on my screen. I have been able to add Rotation to make my Triangle rotate however that is not what I need. I have been looking around a lot into OpenGL and have read into Transformation and then into Translation which I believe to be correct for adding vertical movement to my Triangle, however with my current understanding I have been unable to implement this.
Example:
Triangle is created at the top of the screen and moves down the Y axis towards the bottom of the screen.
This translation is on an angle however it shows what I mean, I would just like to move in y-Axis.
I have a Render as follows:
public class MyGLRenderer implements GLSurfaceView.Renderer {
//Project Matrix
private float mMatrix[] = new float[16];
private Triangle mTriangle;
private final float[] mMVPMatrix = new float[16];
private final float[] mModelMatrix = new float[16];
private float[] mTempMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
// Called once to set up the view's opengl es environment
public void onSurfaceCreated(GL10 unused, EGLConfig config){
//Set the background frame color
GLES30.glClearColor(208.0f,208.0f,208.0f,1.0f);
mTriangle= new Triangle();
}
// Called for each redraw of the view
public void onDrawFrame(GL10 gl){
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//Redraw background color
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
// Apply transformation, start with translation
Matrix.setIdentityM(mModelMatrix, 0); // initialize to identity matrix
Matrix.translateM(mModelMatrix, 0, -0.5f, 0, 0); // translation to the left
// Create a rotation transformation for the triangle
long time = SystemClock.uptimeMillis() % 4000L;
float mAngle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
Matrix.orthoM(mMatrix, 0, -1, 1, -1, 1, -1, 1);
// Combine Rotation and Translation matrices
mTempMatrix = mModelMatrix.clone();
Matrix.multiplyMM(mModelMatrix, 0, mTempMatrix, 0, mRotationMatrix, 0);
// Combine the model matrix with the projection and camera view
mTempMatrix = mMVPMatrix.clone();
Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mModelMatrix, 0);
mTriangle.draw(mMatrix);
}
// Called if the geometry of the view changes (example is when the screen orientation changes from landscape to portrait
public void onSurfaceChanged(GL10 unused, int width, int height){
// Called if the geometry of the viewport changes
GLES30.glViewport(0, 0, width, height);
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES30.GL_VERTEX_SHADER)
// or a fragment shader type (GLES30.GL_FRAGMENT_SHADER)
int shader = GLES30.glCreateShader(type);
// add the source code to the shader and compile it
GLES30.glShaderSource(shader, shaderCode);
GLES30.glCompileShader(shader);
return shader;
}
}
I have a triangle as follows:
public class Triangle {
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final 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.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
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.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
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
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* #param mvpMatrix - The Model View Project matrix in which to draw
* this shape.
*/
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);
}
}
I have a Surface View as follows:
public class MyGLSurfaceView extends GLSurfaceView {
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context, AttributeSet attrs){
super(context, attrs);
//Create an OpenGl 3.0 context
setEGLContextClientVersion(3);
mRenderer = new MyGLRenderer();
//Set the Renderer for drawing on the GLSurfaceView
setRenderer(mRenderer);
}
}
I am looking for a bare bones example/answer/URL that can accomplish moving a drawn Triangle on the y axis (I am assuming using Translation).
I have read and tried to implement the following links (some way above my current understanding).
http://www.swiftless.com/tutorials/opengl/rotation.html
http://www.songho.ca/opengl/gl_transform.html
https://open.gl/transformations
http://www.informit.com/articles/article.aspx?p=2111395&seqNum=3
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
As well as a few others however these seem to be the best sources I have found.
Yes, it would be a translation. It is quite simple, all you would need to do is to modify mvpMatrix in the draw() method of Triangle.
It is important to keep track of the triangle's position to make it move, however. You would add private member to the class resembling this:
private Point mPosition;
Keep in mind, the Point in that code is a simple point/vector class I am assuming you have since I am pretty sure this is on android? Check out this class.
Then, you would need to increment the y-position of the triangle each frame. You could do this in draw(), but I would add another method for movement.
mPosition.y += 0.01;
Note: I see you have an MVP matrix as an argument to draw. Right now, since this is 2D and orthogonic, it is not that important, but think about moving your rotation from the onDrawFrame() function into the Triangle.draw(), since the M stands for Model which would normally be per model/triangle. Normally, you would only pass the VP (view and projection) to the Triangle.draw() method. Check this out.
Finally, you would translate the mvp matrix in the Triangle.draw() method by the triangle's position. So, before passing the matrix to the shader (before GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);), translate it:
Matrix.translateM(mvpMatrix, mPosition.x, mPosition.y);
// Or whatever translate method you have, I am not sure
i am making a opengl engine for learning purposes and in a later stadium develop some games/apps with it. Now with the newest iteration of my engine i cant seem to find out why my quads aren't being colored.
Each vertex is composed of 4 coords (x, y, z, w)and 4 colorcoords r, g, b, a. As far as i can tell the values i pass into the vertices are correct
The offset calculations are hidden away in a seperate static class. i have added it at the bottom of the post.
Vertex[] vertices = new Vertex[] { v0, v1, v2, v3 };
verticesBuffer = BufferUtils.createFloatBuffer(vertices.length * ELEMENT);
for (int i = 0; i < vertices.length; i++) {
verticesBuffer.put(vertices[i].getElements());
}
verticesBuffer.flip();
indicesBuffer = BufferUtils.createByteBuffer(indices.length);
indicesBuffer.put(indices);
indicesBuffer.flip();
int vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
int vboId = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, POSITION_ELEMENT, GL_FLOAT, false, ELEMENT_BYTES, POSITION_OFFSET);
glVertexAttribPointer(1, COLOR_ELEMENTS, GL_FLOAT, false, ELEMENT_BYTES, COLOR_OFFSET);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int vboIId = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Shaders shader = new Shaders();
int vsId = shader.load("shaders/shader.vert", GL_VERTEX_SHADER);
int fsId = shader.load("shaders/shader.frag", GL_FRAGMENT_SHADER);
pId = glCreateProgram();
glAttachShader(pId, vsId);
glAttachShader(pId, fsId);
glBindAttribLocation(pId, 0, "in_Position");
glBindAttribLocation(pId, 1, "in_Color");
glBindAttribLocation(pId, 2, "in_TextureCoord");
glLinkProgram(pId);
glValidateProgram(pId);
My render call is in another class that i call after i passed through the vaoId, vboIID, the amount of indices and the pId
glClear(GL_COLOR_BUFFER_BIT); // scherm schoonmaken
glUseProgram(pId);
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIId);
glDrawElements(GL_TRIANGLES, amount_of_indices, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
Seperate static class with offset calculations
// Amount of bytes per element
static final int BYTES_PER_ELEMENT = 4;
// Elements per parameter
static final int POSITION_ELEMENT = 4;
static final int COLOR_ELEMENTS = 4;
static final int TEXTURE_ELEMENTS = 2;
// Bytes per parameter
static final int POSITION_BYTES = POSITION_ELEMENT * BYTES_PER_ELEMENT;
static final int COLOR_BYTES = COLOR_ELEMENTS * BYTES_PER_ELEMENT;
static final int TEXTURE_BYTES = TEXTURE_ELEMENTS * BYTES_PER_ELEMENT;
// Byte offset per parameter
static final int POSITION_OFFSET = 0;
static final int COLOR_OFFSET = POSITION_OFFSET + POSITION_BYTES;
static final int TEXTURE_OFFSET = COLOR_OFFSET + COLOR_BYTES;
// Amount of elements per vertex
static final int ELEMENT = POSITION_ELEMENT + COLOR_ELEMENTS + TEXTURE_ELEMENTS;
// Byte size per vertex
static final int ELEMENT_BYTES = POSITION_BYTES + COLOR_BYTES + TEXTURE_BYTES;
As far as i can tell my offset calculations are correct. I had positions reserved for texture mapping but i removed them to see if those aren't causing any problems.
A full version of the code is at github https://github.com/darR3Ke/EngineWorks-2.0
nm, i've solved it.
Somehow copying the example shaders from the lwjgl for the texture quads is interfering with my non textured quad.
So for all those following the lwjgl tutorials on the wiki. the Texture quad shaders are not compatible with the colored quad shaders.
Still need to wait a couple of days before i can check this awnser
android developers!
I'm in trouble. My android app has to draw a few lines using OpenGL. I started off with this as example and rewrote it. It throws up the IllegalArgumentException: must use a native order direct Buffer when calling GLES20.glVertexAttribPointer. I don't understand why, since I set it to the nativeorder, like in the example I used. Here's my complete OpenGLRenderer class: (I use the second constructor with the float[] parameter when creating an instance of this class)
public class OpenGLRenderer implements GLSurfaceView.Renderer {
final int COORDS_PER_VERTEX = 3;
final int NR_OF_LINES;
final int NR_OF_VERTECES;
final int VertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
final int NR_OF_VERTECES_PER_LINE = 2;
final int BYTES_PER_VERTEX = 4;
private FloatBuffer bufferVertecesLines;
private float[] arrayVertecesLines;
//private FloatBuffer ColorBuffer;
// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.3f, 0.7f, 0.2f, 1.0f };
private int GlProgram;
private int PositionHandle;
private int ColorHandle;
//SHADERS----------------------------------------------------------------------------------------------------------------------------
private final String VertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String FragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
//CONSTRUCTOR----------------------------------------------------------------------------------------------------------------------------
public OpenGLRenderer(FloatBuffer thisLineVertexBuffer, int numberoflines)
{
bufferVertecesLines = thisLineVertexBuffer;
NR_OF_VERTECES = numberoflines * 2;
NR_OF_LINES = numberoflines;
Log.v("Leen","mijn eigen logje - OpenGLRenderer - Constructor");
}
public OpenGLRenderer(float[] thisLineVertexArray)
{
arrayVertecesLines = thisLineVertexArray;
NR_OF_VERTECES = thisLineVertexArray.length / COORDS_PER_VERTEX;
NR_OF_LINES = thisLineVertexArray.length / COORDS_PER_VERTEX / NR_OF_VERTECES_PER_LINE;
}
private void convertArrayToBuffer()
{
int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
// in voorbeeld:
// NrOfBytes = 2 * 2 * 3 * 4 = 48
ByteBuffer bb = ByteBuffer.allocate(NrOfBytes);
bb.order(ByteOrder.nativeOrder());
bufferVertecesLines = bb.asFloatBuffer();
bufferVertecesLines.put(arrayVertecesLines);
}
//---------------------------------------------------------------------------------------------------------------------------------------
#Override
public void onSurfaceChanged(GL10 unused, int width, int height)
{
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES20.glViewport(0, 0, width, height);
}
//---------------------------------------------------------------------------------------------------------------------------------------
#Override
public void onDrawFrame(GL10 arg0)
{
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FragmentShaderCode);
GlProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(GlProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(GlProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(GlProgram); // creates OpenGL ES program executables
this.drawAllLines();
}
//---------------------------------------------------------------------------------------------------------------------------------------
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
//---------------------------------------------------------------------------------------------------------------------------------------
public static 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;
}
//---------------------------------------------------------------------------------------------------------------------------------------
public void drawAllLines()
{
// Add program to OpenGL ES environment
GLES20.glUseProgram(GlProgram);
// get handle to vertex shader's vPosition member
PositionHandle = GLES20.glGetAttribLocation(GlProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(PositionHandle);
// Prepare the Line coordinate data
// vertexstride = offset. 3 coordinaten per vertex * 4 bytes per vertex = 12
this.convertArrayToBuffer();
GLES20.glVertexAttribPointer(PositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
VertexStride, bufferVertecesLines);
// get handle to fragment shader's vColor member
ColorHandle = GLES20.glGetUniformLocation(GlProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(ColorHandle, 1, color, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_LINES, 0, NR_OF_VERTECES);
// Disable vertex array
GLES20.glDisableVertexAttribArray(PositionHandle);
}
}
OK, found it. I didn't use the ByteBuffer.allocate() method, but the ByteBuffer.allocateDirect() - method. This piece is throwing no exceptions:
private void convertArrayToBuffer()
{
int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
// in voorbeeld:
// NrOfBytes = 2 * 2 * 3 * 4 = 48
ByteBuffer bb = ByteBuffer.allocateDirect(NrOfBytes); //!!!!!!!!!!
bb.order(ByteOrder.nativeOrder());
bufferVertecesLines = bb.asFloatBuffer();
bufferVertecesLines.put(arrayVertecesLines);
bb.position(0);
bufferVertecesLines.position(0);
}
private void convertArrayToBuffer()
{
int NrOfBytes = NR_OF_LINES * NR_OF_VERTECES_PER_LINE * COORDS_PER_VERTEX * BYTES_PER_VERTEX;
// in voorbeeld:
// NrOfBytes = 2 * 2 * 3 * 4 = 48
ByteBuffer bb = ByteBuffer.allocate(NrOfBytes);
bb.order(ByteOrder.nativeOrder());
bufferVertecesLines = bb.asFloatBuffer();
bufferVertecesLines.put(arrayVertecesLines);
bb.position(0); //!!!!!!!!!!!!!
bufferVertecesLines.position(0);//!!!!!!!!!!!!!
}
I have encountered the same problem, and I find the answer at enter link description here.
use allocateDirect instead of allocate, the bb needs to be direct so it isn't move around the memeory.