I was trying to render a mesh (that i created programmatically) with textures. Everything works fine except that it doesn't render the texture. It's just a black triangle. Here is a simplified version of the code (which doesn't work either):
public ModelBatch batch;
public OrthographicCamera cam;
public Renderable renderable;
#Override
public void create () {
cam = new OrthographicCamera(5, 5);
batch = new ModelBatch();
Mesh mesh = new Mesh(true, 3, 3,
new VertexAttribute(VertexAttributes.Usage.Position, 2, "a_position"),
new VertexAttribute(VertexAttributes.Usage.TextureCoordinates, 2, "a_texCoord")
);
mesh.setVertices(new float[]{
0, 0, 0, 0,
1, 0, 1, 0,
1, 1, 1, 1
});
mesh.setIndices(new short[]{
0, 1, 2
});
renderable = new Renderable();
renderable.primitiveType = GL20.GL_TRIANGLES;
renderable.mesh = mesh;
renderable.meshPartOffset = 0;
renderable.meshPartSize = mesh.getNumIndices();
renderable.material = new Material(TextureAttribute.createDiffuse(new Texture("badlogic.jpg")));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin(cam);
batch.render(renderable);
batch.end();
}
I solved the problem.
I should have created the mesh this way:
Mesh mesh = new Mesh(true, 3, 3,
new VertexAttribute(VertexAttributes.Usage.Position, 2, "a_position"),
new VertexAttribute(VertexAttributes.Usage.TextureCoordinates, 2, "a_texCoord0")
);
The difference is that now the alias in the texture coordinates attribute is a_texCoord0 instead of a_texCoord.
Related
I've seen a couple of questions about the same topic but still couldn't figure out what was wrong with my code.
It worked to get a window running, where a keypress would change the background color with glClearColor().
But now, when trying to draw a quad onto the screen, the screen stays black.
A little summary of how I think it should work:
How mesh is created:
public Mesh(Vertex[] verts, int[] indices) {
this.verts = verts;
this.indices = indices;
}
//Differend class
public Mesh mesh = new Mesh(new Vertex[] {
new Vertex(new Vector3f(-0.5f, 0.5f, 0.0f)),
new Vertex(new Vector3f(-0.5f, -0.5f, 0.0f)),
new Vertex(new Vector3f( 0.5f, -0.5f, 0.0f)),
new Vertex(new Vector3f( 0.5f, 0.5f, 0.0f))
}, new int[] {
0, 1, 2,
0, 3, 2
});
For initializing the game, this is called:
public void create() {
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
FloatBuffer positionBuffer = MemoryUtil.memAllocFloat(verts.length * 3);
float[] positionData = new float[verts.length * 3];
for (int i = 0; i < verts.length; i++) {
positionData[i * 3] = verts[i].getPosition().getX();
positionData[i * 3 + 1] = verts[i].getPosition().getY();
positionData[i * 3 + 2] = verts[i].getPosition().getZ();
}
positionBuffer.put(positionData).flip();
pbo = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, pbo);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, positionBuffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
IntBuffer indexBuffer = MemoryUtil.memAllocInt(indices.length * 3);
indexBuffer.put(indices).flip();
ibo = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
}
And lastly, the mesh should be rendered with this:
public void renderMesh(Mesh mesh) {
clear();
GL30.glBindVertexArray(mesh.getVAO());
GL30.glEnableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, mesh.getIBO());
GL11.glDrawElements(GL11.GL_TRIANGLES, mesh.getIndices().length, GL11.GL_FLOAT, 0);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
GL30.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
I've checked that the methods are actually invoked by using System.out.println.
The game's input still works. It's just that the screen is black and not showing any quad.
Why is it not drawing anything onto the screen?
The type argument which is set to glDrawElements hs to correspond to the index buffer, rather than the vertex buffer.
In your case it has to be GL_UNSIGNED_INT rather than GL_FLOAT. See glDrawElements.
GL11.glDrawElements(GL11.GL_TRIANGLES, mesh.getIndices().length, GL11.GL_FLOAT, 0);
GL11.glDrawElements(GL11.GL_TRIANGLES, mesh.getIndices().length, GL11.GL_UNSIGNED_INT, 0);
Note, GL_FLOAT is not an accepted value for glDrawElements and will cause an INVALID_ENUM error.
I already have a drawn model, but it has flat shading (for what I understand it should be smooth by default...)
This is the initial config:
private void SetLightningAndMaterials(){
//float[] lightPos = {1, 1, 1, 0};
float[] lightPos = {0, 0, 1, 0};
float[] lightColorDiffuse = {1, 1, 1, 1};
float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1};
gl.glShadeModel(GL.GL_SMOOTH);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPos, 0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, lightColorDiffuse, 0);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightColorAmbient, 0);
gl.glEnable(GL.GL_LIGHT1);
gl.glEnable(GL.GL_LIGHTING);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, ambientColour, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mesh.colour, 0);
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);
float[] noAmbient =
{ 0.1f, 0.1f, 0.1f, 1f }; // low ambient light
float[] spec =
{ 1f, 0.6f, 0f, 1f }; // low ambient light
float[] diffuse =
{ 0.5f, 0.5f, 0.5f, 1f };
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, noAmbient, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, spec, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, new float[]{0,0,10,1}, 0);
}
And this is how I draw the model:
public void Draw(GL gl, GLU glu){
Vec3d normal;
MassPoint vertex1, vertex2, vertex3;
int faceIndex=0;
Face surfaceFace;
for (faceIndex=0; faceIndex<surfaceFaces.size();faceIndex++){
surfaceFace = surfaceFaces.get(faceIndex);
surfaceFace.recalculateNormal();
vertex1 = surfaceFace.vertex1;
vertex2 = surfaceFace.vertex2;
vertex3 = surfaceFace.vertex3;
normal = surfaceFace.normal;
gl.glBegin(gl.GL_TRIANGLES);
gl.glNormal3d(normal.x, normal.y, normal.z);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, colour, 0);
gl.glVertex3d(vertex1.position.x, vertex1.position.y, vertex1.position.z);
gl.glVertex3d(vertex2.position.x, vertex2.position.y, vertex2.position.z);
gl.glVertex3d(vertex3.position.x, vertex3.position.y, vertex3.position.z);
gl.glEnd();
}
}
I want to believe there's an easy way of solving this without having to create a shader (I don't have any idea how to set these in Java).
I'm using JOGL 1 by the way, and is probably an old version (the imports are like javax.media.opengl.*).
I managed to solve the problem. For smoothness to work, the drawing expects 3 normals (one per vertex), I was only passing 1 normal (one per face).
Here's the new code for the drawing:
public void Draw(GL gl, GLU glu) {
Vec3d[] normalsPerVertex = new Vec3d[3];
MassPoint vertex1, vertex2, vertex3;
int faceIndex=0;
Face surfaceFace;
for (faceIndex=0; faceIndex<surfaceFaces.size();faceIndex++){
surfaceFace = surfaceFaces.get(faceIndex);
vertex1=surfaceFace.vertex1;
normalsPerVertex[0] = vertex1.CalcNormal();
vertex2=surfaceFace.vertex2;
normalsPerVertex[1] = vertex2.CalcNormal();
vertex3=surfaceFace.vertex3;
normalsPerVertex[2] = vertex3.CalcNormal();
gl.glBegin(GL.GL_TRIANGLES);
gl.glNormal3d(normalsPerVertex[0].x, normalsPerVertex[0].y, normalsPerVertex[0].z);
gl.glVertex3d(vertex1.position.x, vertex1.position.y, vertex1.position.z);
gl.glNormal3d(normalsPerVertex[1].x, normalsPerVertex[1].y, normalsPerVertex[1].z);
gl.glVertex3d(vertex2.position.x, vertex2.position.y, vertex2.position.z);
gl.glNormal3d(normalsPerVertex[2].x, normalsPerVertex[2].y, normalsPerVertex[2].z);
gl.glVertex3d(vertex3.position.x, vertex3.position.y, vertex3.position.z);
gl.glEnd();
}
}
The calculated normal for each vertex is the media of all the faces connected to that vertex. Here's the code for that:
public Vec3d CalcNormal() {
Vec3d normalMedia = new Vec3d();
for (Face face : facesRelated) {
face.recalculateNormal();
normalMedia.add(face.normal);
}
normalMedia.mul(1d/facesRelated.size());
return normalMedia;
}
Hope this helps someone else.
I'm trying to display a simple textured trapezoid (a road in perspective). For this I'm using SpriteBatch.draw with vertexes array as a parameter. But the result is unexpected.
What I expected:
What I got:
What exactly gone wrong? Or maybe I'm using the wrong method?
Here is the code:
#Override
public void create () {
texture = new Texture("road.jpg");
spriteBatch = new SpriteBatch();
float color = Color.toFloatBits(255, 255, 255, 255);
verts = new float[]{
0, 0, color, 0, 0,
Gdx.graphics.getWidth()/2-100, 300, color, 0, 1,
Gdx.graphics.getWidth()/2+100, 300, color, 1, 1,
Gdx.graphics.getWidth(), 0, color, 1, 0,
};
shapeRenderer = new ShapeRenderer();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0.5f, 1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(0, 0, 640, 300);
shapeRenderer.end();
spriteBatch.begin();
spriteBatch.draw(texture, verts, 0, verts.length);
spriteBatch.end();
}
From documentation
draw(Texture texture, float[] spriteVertices, int offset, int count)
Draws a rectangle using the given vertices.
LibGDX draws these rectangles as two triangles, so it splits the texture. The problem is that these triangles in rectangle are the same size, but in trapezoid they are not, so they become distorted.
Solution would be to use projection or mesh.
Ok, first of all I totally agree that "TheNewBoston" tutorials are very... wrong at times. However that is what I was following to try to make a cube in OpenGL on android.
Anyways, I can't say that I have found great material on OpenGL to be honest. I have read through OpenGL Superbible... it was ok.
So here is the code that I have.
GLRenderer.java
package android.gem.opengltest;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
import android.os.SystemClock;
public class GLRenderer implements Renderer {
private GLCube cube;
public GLRenderer() {
cube = new GLCube();
}
#Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glDisable(GL10.GL_DITHER);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_STENCIL_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, -5, 0, 0, 0, 0, 2, 0);
long time = SystemClock.uptimeMillis() % 4000L;
float angle = .09f * ((int) time);
gl.glRotatef(angle, 1, 1.5f, 2);
cube.draw(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
float ratio = (float) width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 25);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
// TODO Auto-generated method stub
// START OF PERFORMANCE //
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// END OF PERFORMANCE //
gl.glClearColor(.8f, 0, .2f, 1f); // Red, Green, Blue, Alpha (0 - 1)
gl.glClearDepthf(1f);
}
}
GLCube.java
package android.gem.opengltest;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
public class GLCube {
private float verticies[] = {
1, 1, -1, // point 0 - topFrontRight
1, -1, -1, // point 1 - bottomFrontRight
-1, -1, -1, // point 2 - bottomFrontLeft
-1, 1, -1, // point 3 - frontTopLeft
1, 1, 1, // point 4 - topBackRight
1, -1, 1, // point 5 - bottomBackRight
-1, -1, 1, // point 6 - bottomBackLeft
-1, 1, 1 // point 7 - frontBackLeft
};
private float rgbaValues[] = {
1, 1, 0, 1,
.25f, 0, .85f, 1,
0, 1, 1, 1,
1, 1, 0, 1,
.25f, 0, .85f, 1,
0, 1, 1, 1,
.5f, .5f, .2f, 1,
.3f, .3f, .3f, 1
};
private FloatBuffer vertBuff, colorBuff;
private short[] pIndex = { // Indicies
3, 4, 0, 0, 4, 1, 3, 0, 1,
3, 7, 4, 7, 6, 4, 7, 3, 6,
3, 1, 2, 1, 6, 2, 6, 3, 2,
1, 4, 5, 5, 6, 1, 6, 5, 4
};
private ShortBuffer pBuffer;
public GLCube() {
ByteBuffer bBuff = ByteBuffer.allocateDirect(this.verticies.length * 4);
bBuff.order(ByteOrder.nativeOrder());
vertBuff = bBuff.asFloatBuffer();
vertBuff.put(this.verticies);
vertBuff.position(0);
ByteBuffer pbBuff = ByteBuffer.allocateDirect(this.pIndex.length * 2);
pbBuff.order(ByteOrder.nativeOrder());
pBuffer = pbBuff.asShortBuffer();
pBuffer.put(pIndex);
pBuffer.position(0);
ByteBuffer cBuff = ByteBuffer.allocateDirect(this.rgbaValues.length * 4);
cBuff.order(ByteOrder.nativeOrder());
colorBuff = cBuff.asFloatBuffer();
colorBuff.put(rgbaValues);
colorBuff.position(0);
}
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CW); // Clock Wise
gl.glEnable(GL10.GL_CULL_FACE); // Removes back end of cube
gl.glCullFace(GL10.GL_BACK);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, this.vertBuff);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, this.colorBuff);
gl.glDrawElements(GL10.GL_TRIANGLES, this.pIndex.length, GL10.GL_UNSIGNED_SHORT, this.pBuffer);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
}
}
I get a cube that looks like this...
What am I doing wrong? What should I do to make it look like an actual cube?
Also, if it helps all my code is at the following address: https://github.com/gemurdock/OpenGlTest/tree/alpha.0.1.0
First of all, this is a (horribly deformed) cube, not a square. Unless you look at it face-on it is never going to look like a "good square" :)
Your polygon face culling appears to be culling the wrong side of your cube faces. It still looks like a cube, just an inside out cube.
This is likely because you have overridden OpenGL's default front face winding direction (GL_CCW).
When I just draw texture on SpriteBatch and set TextureWrap.Repeat everything is OK. But now I have 3D scene and I want have ground and texture must be repeated on model/mesh and this just don' t work.
public static StillModel createPlainMesh(float xs, float zs, Texture texture) {
final Mesh mesh = new Mesh(true, 4, 6, new VertexAttribute(
Usage.Position, 3, "a_position"), new VertexAttribute(
Usage.TextureCoordinates, 2, "a_texCoords"));
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 1,
-xs, 0f, zs, 1, 0,
-xs, 0f, -zs , 1,1
});
mesh.setIndices(new short[] { 0, 1, 2, 1, 2, 3 });
final StillModel model = new StillModel(new StillSubMesh(
"ground", mesh, GL10.GL_TRIANGLES, new Material()));
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
model.setMaterial(new Material("material", new TextureAttribute(texture, 0, "s_tex")));
return model;
}
I have this code. I use setWrap(TextureWrap.Repeat, TextureWrap.Repeat), but textures are still streched. I don't know why, but it looks terrible.
I solved it. If you want repeat texture on model, You must modify this:
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 1,
-xs, 0f, zs, 1, 0,
-xs, 0f, -zs , 1,1
});
Modify Texture Coords - change to for example 20 if You want repeat it 20times
Example:
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 20,
-xs, 0f, zs, 20, 0,
-xs, 0f, -zs , 20,20
});