Here is my code for created a cube in OpenGL with Java, how to implement algorithm for rotation over Ox, Oy and Oz axis without using predefinition function. For example how to rotate it over origin point or another point.
import java.awt.DisplayMode;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import com.jogamp.opengl.util.FPSAnimator;
public class Cube implements GLEventListener {
public static DisplayMode dm, dm_old;
private GLU glu = new GLU();
private float rquad = 0.0f;
#Override
public void display( GLAutoDrawable drawable ) {
final GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT );
gl.glLoadIdentity();
gl.glTranslatef( 0f, 0f, -5.0f );
// Rotate The Cube On X, Y & Z
gl.glRotatef(rquad, 1.0f, 1.0f, 1.0f);
//giving different colors to different sides
gl.glBegin(GL2.GL_QUADS); // Start Drawing The Cube
gl.glColor3f(1f,0f,0f); //red color
gl.glVertex3f(1.0f, 1.0f, -1.0f); // Top Right Of The Quad (Top)
gl.glVertex3f( -1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Top)
gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Bottom Left Of The Quad (Top)
gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Bottom Right Of The Quad (Top)
gl.glColor3f( 0f,1f,0f ); //green color
gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Top Right Of The Quad
gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Top Left Of The Quad
gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad
gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad
gl.glColor3f( 0f,0f,1f ); //blue color
gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Top Right Of The Quad (Front)
gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Top Left Of The Quad (Front)
gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom Left Of The Quad
gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom Right Of The Quad
gl.glColor3f( 1f,1f,0f ); //yellow (red + green)
gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad
gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad
gl.glVertex3f( -1.0f, 1.0f, -1.0f ); // Top Right Of The Quad (Back)
gl.glVertex3f( 1.0f, 1.0f, -1.0f ); // Top Left Of The Quad (Back)
gl.glColor3f( 1f,0f,1f ); //purple (red + green)
gl.glVertex3f( -1.0f, 1.0f, 1.0f ); // Top Right Of The Quad (Left)
gl.glVertex3f( -1.0f, 1.0f, -1.0f ); // Top Left Of The Quad (Left)
gl.glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom Left Of The Quad
gl.glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom Right Of The Quad
gl.glColor3f( 0f,1f, 1f ); //sky blue (blue +green)
gl.glVertex3f( 1.0f, 1.0f, -1.0f ); // Top Right Of The Quad (Right)
gl.glVertex3f( 1.0f, 1.0f, 1.0f ); // Top Left Of The Quad
gl.glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom Left Of The Quad
gl.glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom Right Of The Quad
gl.glEnd(); // Done Drawing The Quad
gl.glFlush();
rquad -= 0.15f;
}
#Override
public void dispose( GLAutoDrawable drawable ) {
// TODO Auto-generated method stub
}
#Override
public void init( GLAutoDrawable drawable ) {
final GL2 gl = drawable.getGL().getGL2();
gl.glShadeModel( GL2.GL_SMOOTH );
gl.glClearColor( 0f, 0f, 0f, 0f );
gl.glClearDepth( 1.0f );
gl.glEnable( GL2.GL_DEPTH_TEST );
gl.glDepthFunc( GL2.GL_LEQUAL );
gl.glHint( GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST );
}
#Override
public void reshape( GLAutoDrawable drawable, int x, int y, int width, int height ) {
// TODO Auto-generated method stub
final GL2 gl = drawable.getGL().getGL2();
if( height lt;= 0 )
height = 1;
final float h = ( float ) width / ( float ) height;
gl.glViewport( 0, 0, width, height );
gl.glMatrixMode( GL2.GL_PROJECTION );
gl.glLoadIdentity();
glu.gluPerspective( 45.0f, h, 1.0, 20.0 );
gl.glMatrixMode( GL2.GL_MODELVIEW );
gl.glLoadIdentity();
}
public static void main( String[] args ) {
final GLProfile profile = GLProfile.get( GLProfile.GL2 );
GLCapabilities capabilities = new GLCapabilities( profile );
// The canvas
final GLCanvas glcanvas = new GLCanvas( capabilities );
Cube cube = new Cube();
glcanvas.addGLEventListener( cube );
glcanvas.setSize( 400, 400 );
final JFrame frame = new JFrame ( " Multicolored cube" );
frame.getContentPane().add( glcanvas );
frame.setSize( frame.getContentPane().getPreferredSize() );
frame.setVisible( true );
final FPSAnimator animator = new FPSAnimator(glcanvas, 300,true);
animator.start();
}
}
Related
So I'm using LWJGL3 and I'm trying to render a cube, however I have 2 issues:
The orthographic camera is too close and I tried increasing/decreasing the values in the parameters but none achieve the effect I want which is to eventually show lots of cubes stacked side-by-side so it needs to be zoomed out,
The cube renders in 2D, I would like it to initially look 2D but then I will use keys to rotate the camera so you can get a 3D view also.
Here is the code I have so far:
package io.ryankshah;
import io.ryankshah.util.Constants;
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
import java.nio.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Window
{
// Create a keycallback to check for key actions
private static GLFWKeyCallback keyCallback = new GLFWKeyCallback()
{
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
// If ESC is pressed, close the window
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
};
private static long window;
private static void init() {
glfwSetErrorCallback(Constants.ERROR_CALLBACK);
// Initialize GLFW
if(!glfwInit()) throw new IllegalStateException("Failed to initialize GLFW");
// Create window
window = glfwCreateWindow(Constants.WINDOW_WIDTH, Constants.WINDOW_HEIGHT,
Constants.WINDOW_TITLE, 0, 0);
if(window == 0) {
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
// Center the window
GLFWVidMode vm = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (vm.width() - Constants.WINDOW_WIDTH) / 2,
(vm.height() - Constants.WINDOW_HEIGHT) / 2);
// Create OpenGL context
glfwMakeContextCurrent(window);
GL.createCapabilities();
// Enbale vsync
glfwSwapInterval(1);
// Set key callback
glfwSetKeyCallback(window, keyCallback);
}
private static void render() {
/* Declare buffers for using inside the loop */
IntBuffer width = MemoryUtil.memAllocInt(1);
IntBuffer height = MemoryUtil.memAllocInt(1);
/* Loop until window gets closed */
while (!glfwWindowShouldClose(window)) {
float ratio;
/* Get width and height to calcualte the ratio */
glfwGetFramebufferSize(window, width, height);
ratio = width.get() / (float) height.get();
/* Rewind buffers for next get */
width.rewind();
height.rewind();
/* Set viewport and clear screen */
glViewport(0, 0, width.get(), height.get());
glClear(GL_COLOR_BUFFER_BIT);
/* Set ortographic projection */
float zoom = 50.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1f, 1f, 1f, -1f);
glMatrixMode(GL_MODELVIEW);
/* Rotate matrix */
glLoadIdentity();
glRotatef((float) glfwGetTime() * 50f, 0f, 0f, 1f);
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glColor3f(1, 0, 0);
GL11.glBegin(GL11.GL_QUADS);
GL11.glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
GL11.glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top)
GL11.glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top)
GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
GL11.glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
GL11.glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom)
GL11.glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom)
GL11.glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom)
GL11.glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom)
GL11.glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
GL11.glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front)
GL11.glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front)
GL11.glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
GL11.glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Back)
GL11.glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Back)
GL11.glVertex3f(-1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Back)
GL11.glVertex3f( 1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Back)
GL11.glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
GL11.glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left)
GL11.glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left)
GL11.glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left)
GL11.glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
GL11.glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right)
GL11.glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
GL11.glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right)
GL11.glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right)
GL11.glEnd();
GL11.glLoadIdentity();
/* Swap buffers and poll Events */
glfwSwapBuffers(window);
glfwPollEvents();
/* Flip buffers for next loop */
width.flip();
height.flip();
}
MemoryUtil.memFree(width);
MemoryUtil.memFree(height);
}
private static void loop() {
render();
}
public static void main(String[] args) {
init();
loop();
glfwDestroyWindow(window);
keyCallback.free();
glfwTerminate();
Constants.ERROR_CALLBACK.free();
}
}
Also if anyone has pointers as to the way I have structured my program or any calls that are unnecessary, would be great to have some sort of boiler-plate knowledge of how I should structure my lwjgl program.
I can't figure out how to increase the size of the image, I know how to rotate, but how would I adjust the size? Also, I would like to know how to prevent the bitmap from looking squished. Right now when I load it on screen it looks like the sides are being squished.
#Override
public void onDrawFrame(GL10 gl) {
// clear Screen and Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
// Drawing
gl.glTranslatef(0.0f, 0.0f, -5.0f); // move 5 units INTO the screen
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glRotatef(mAngle, 0, 1, 0);
gl.glRotatef(mAngle*0.25f, 1, 0, 0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glRotatef(mAngle*2.0f, 0, 1, 1);
gl.glTranslatef(0.5f, 0.5f, 0.5f);
mAngle += 1.2f;
bitmap_image.draw(gl);
}
In another class I'm loading the bitmap with:
private FloatBuffer vertexBuffer; // buffer holding the vertices
private float vertices[] = {
-1.0f, -1.0f, 0.0f, // V1 - bottom left
-1.0f, 1.0f, 0.0f, // V2 - top left
1.0f, -1.0f, 0.0f, // V3 - bottom right
1.0f, 1.0f, 0.0f // V4 - top right
};
private FloatBuffer textureBuffer; // buffer holding the texture coordinates
private float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
/** The texture pointer */
private int[] textures = new int[1];
public ImageLoader() {
// a float has 4 bytes so we allocate for each coordinate 4 bytes
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
// allocates the memory from the byte buffer
vertexBuffer = byteBuffer.asFloatBuffer();
// fill the vertexBuffer with the vertices
vertexBuffer.put(vertices);
// set the cursor position to the beginning of the buffer
vertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
}
I'm developing some OpenGL game using JOGL library.
When I draw objects regulary, e.g. using GL_QUADS directly in the display method, the scene lighting appears on the object.
However, when I prepare objects in the init method and load using glCallList in the display list, those objects doesn't seem to be affected from the lighting.
To be precise, they are affected in SOME way: altering the materialfv function parameters or the ambient parameters brighten or darken the scene, but the color I'm trying to diffuse is not working (only on the regular drawn objects without lists).
Code
Here's the lighting code:
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glShadeModel(GL2.GL_SMOOTH); // Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
gl.glClearDepth(1.0f); // Depth Buffer Setup
gl.glEnable(GL2.GL_DEPTH_TEST); // Enables Depth Testing
gl.glDepthFunc(GL2.GL_LEQUAL); // The Type Of Depth Testing To Do
glu = new GLU();
// Really Nice Perspective Calculations
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
// Light
float ambient[] = {0.1f,0.1f,0.1f,1.0f};
float diffuse0[] = {1f,0f,0f,1.0f};
float diffuse1[] = {0f,0f,1f,1.0f};
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, ambient, 0);
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, diffuse0, 0);
gl.glEnable(GL2.GL_LIGHT0);
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, ambient, 0);
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, diffuse1, 0);
gl.glEnable(GL2.GL_LIGHT1);
gl.glEnable(GL2.GL_LIGHTING);
// make display lists here...
The lighting part of display:
// display method...
// apply light
float position0[] = {500, 300, 3500,1.0f};
float position1[] = {500, 300, 500,1.0f};
gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, position0, 0);
gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, position1, 0);
// draw objects directly
// draw objects using glCallLists
Here's an example of how I draw regular object in the display method:
gl.glPushMatrix();
gl.glTranslatef(1000, 500, 2000);
gl.glTexParameteri ( GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT );
gl.glTexParameteri( GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT );
float material[] = {0.8f,0.8f,0.8f,1.0f};
gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE, material, 0);
gl.glBegin(GL2.GL_QUADS);
// Front Face
gl.glNormal3f(0,0,1);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glTexCoord2f(2f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glTexCoord2f(2f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
gl.glNormal3f(0,0,-1);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
// Top Face
gl.glNormal3f(0,1,0);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
// Bottom Face
gl.glNormal3f(0,-1,0);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
gl.glNormal3f(1,0,0);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, -1.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
// Left Face
gl.glNormal3f(-1,0,0);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(-1.0f, 1.0f, -1.0f);
gl.glEnd();
gl.glPopMatrix();
Here's the class I use to load obj files.
I use the method loadWavefrontObjectAsDisplayList which accepts a path to obj file and then returns the list integer.
Another Edit:
The scene (lamp is being lighten up, crate is not):
Link to lamp and crate .obj files.
The normals are probably missing in the WaveFront OBJ file of the crate model.
Then, the OBJ importer that you use generates plain wrong normals whose coordinates are (0, 0, 0), it has no chance to work with the lightning.
I cannot seem to render a Texture to my square. I have gotten my program to render the blank square with color. Any help is greatly appreciated.
I've redesigned my code to the following and believe that the problem exists with how I'm setting up my Vertex Coordinates and Texture Coordinates. I also get a libc Fatal signal 11 at my glDrawArrays function.
Here are the Vertex and Texture Coordinates:
private final FloatBuffer vertexBuffer;
private final FloatBuffer textureBuffer;
static final int COORDS_PER_VERTEX = 3;
static float positionCoords[] = { // in counterclockwise order:
-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,
};
static final int COORDS_PER_TEXTURE = 2;
static float textureCoords[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
};
Here's my draw function in my square class:
public void draw(float[] mvpMatrix)
{
int MVPMatrixHandle = GLES20.glGetUniformLocation(shader.getProgram(), "u_MVPMatrix");
int textureHandler = GLES20.glGetUniformLocation(shader.getProgram(), "u_s_texture");
int positionHandler = GLES20.glGetAttribLocation(shader.getProgram(), "a_position");
int texCoordHandler = GLES20.glGetAttribLocation(shader.getProgram(), "a_texCoord");
Log.d(TAG, "Setting up GLProgram Handlers");
GlRenderer.checkGlError("Setup GLProgram Handlers");
GLES20.glEnableVertexAttribArray(positionHandler);
GLES20.glEnableVertexAttribArray(texCoordHandler);
GlRenderer.checkGlError("EnableVertexAttribArrays");
GLES20.glVertexAttribPointer(positionHandler, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(textureHandler, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
textureStride, textureBuffer);
GlRenderer.checkGlError("VertexAttribPointers (Position, Texture)");
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
GLES20.glUniform1i(textureHandler, 0);
GlRenderer.checkGlError("Binding Texture");
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
GlRenderer.checkGlError("Draw Arrays");
GLES20.glDisableVertexAttribArray(positionHandler);
GLES20.glDisableVertexAttribArray(texCoordHandler);
GlRenderer.checkGlError("DisableVertexAttribArrays");
}
Your SetupGLPositionHandle function looks wrong to me. Why disable the PositionHandle attribute at the end of the function?
The attribute must be enabled at the time glDrawArrays is called.
My main problem in the above code was the fact that I was using the textureHandleinstead of the texCoordHandler in the glVertexAttribPointer //Texture
The code should look like this:
GLES20.glVertexAttribPointer(texCoordHandler, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
textureStride, textureBuffer);
Since this problem arose I've rewritten my code yet again. Adding indices (draworder), combining my Vertex and Texture arrays into a Vertices array, and just reference a vertexBuffer //Contains both position coordinates and texture coordinates instead of a textureBuffer and a vertexBuffer //Only contains position coordinates
I've also changed the GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); to:
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length,
GLES20.GL_UNSIGNED_SHORT, indexBuffer);
I'm learning Java and OpenGL ES for Android by reading tutorials and applying what I already know. And I have now hit a brick wall when it comes to rotating an object.
Rotating a cube by touching the screen is no problem. But if I rotate the cube 180 degrees up or down, then when I now try to rotate the cube left or right it is inverted. I know why this is happening but I cannot find a solution.
The code is below if some want to test it:
File "Rotating.java":
package com.test.opengl;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class Rotating extends Activity {
private GLControlView glControlView;
#Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
this.requestWindowFeature( Window.FEATURE_NO_TITLE );
getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN );
glControlView = new GLControlView( this );
setContentView( glControlView );
}
}
File "GLControlView.java":
package com.test.opengl;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
import android.view.MotionEvent;
public class GLControlView extends GLSurfaceView implements Renderer {
private Context context;
private float xPrevious, yPrevious;
private float xRotation = 0.0f, yRotation = 0.0f;
private SimpleCubeObject cubeObject;
public GLControlView( Context context ) {
super( context );
this.context = context;
this.setRenderer( this );
this.requestFocus();
this.setFocusableInTouchMode( true );
cubeObject = new SimpleCubeObject();
}
public void onSurfaceCreated( GL10 gl, EGLConfig config ) {
gl.glClearColor( 0.0f, 0.0f, 0.0f, 0.5f );
gl.glShadeModel( GL10.GL_SMOOTH );
gl.glClearDepthf( 1.0f );
gl.glEnable( GL10.GL_DEPTH_TEST );
gl.glDepthFunc( GL10.GL_LEQUAL );
gl.glHint( GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST );
}
public void onDrawFrame( GL10 gl ) {
gl.glClear( GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT );
gl.glLoadIdentity();
gl.glTranslatef( 0.0f, 0.0f, -10.0f );
gl.glPushMatrix();
gl.glRotatef( xRotation, 1.0f, 0.0f, 0.0f );
gl.glRotatef( yRotation, 0.0f, 1.0f, 0.0f );
gl.glPushMatrix();
cubeObject.draw( gl );
gl.glPopMatrix();
gl.glPopMatrix();
}
public void onSurfaceChanged( GL10 gl, int width, int height ) {
gl.glViewport( 0, 0, width, height );
gl.glMatrixMode( GL10.GL_PROJECTION );
gl.glLoadIdentity();
GLU.gluPerspective( gl, 45.0f, ( ( float )width / ( float )height ), 0.1f, 100.0f );
gl.glMatrixMode( GL10.GL_MODELVIEW );
gl.glLoadIdentity();
}
#Override
public boolean onTouchEvent( MotionEvent event ) {
float xEvent = event.getX();
float yEvent = event.getY();
switch( event.getAction() ) {
case MotionEvent.ACTION_DOWN: {
xPrevious = xEvent;
yPrevious = yEvent;
return true;
}
case MotionEvent.ACTION_MOVE: {
float xDelta = xEvent - xPrevious;
float yDelta = yEvent - yPrevious;
xRotation += ( yDelta * 0.5f );
yRotation += ( xDelta * 0.5f );
xPrevious = xEvent;
yPrevious = yEvent;
return true;
}
default: return super.onTouchEvent( event );
}
}
}
File "SimpleCubeObject.java":
package com.test.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
public class SimpleCubeObject {
private int[] textures = new int[ 1 ];
private float[] colors = {
0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
private short[] indices = {
0, 1, 2, 0, 2, 3,
1, 5, 6, 1, 6, 2,
2, 6, 7, 2, 7, 3,
3, 7, 4, 3, 4, 0,
0, 4, 5, 0, 5, 1,
7, 6, 5, 7, 5, 4
};
private float[] vertices = {
-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 FloatBuffer colorBuffer;
private ShortBuffer indexBuffer;
private FloatBuffer vertexBuffer;
public SimpleCubeObject() {
ByteBuffer cbb = ByteBuffer.allocateDirect( colors.length * 4 );
cbb.order( ByteOrder.nativeOrder() );
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put( colors );
colorBuffer.position( 0 );
ByteBuffer ibb = ByteBuffer.allocateDirect( indices.length * 2 );
ibb.order( ByteOrder.nativeOrder() );
indexBuffer = ibb.asShortBuffer();
indexBuffer.put( indices );
indexBuffer.position( 0 );
ByteBuffer vbb = ByteBuffer.allocateDirect( vertices.length * 4 );
vbb.order( ByteOrder.nativeOrder() );
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put( vertices );
vertexBuffer.position( 0 );
}
public void draw( GL10 gl ) {
gl.glFrontFace( GL10.GL_CCW );
gl.glEnable( GL10.GL_CULL_FACE );
gl.glCullFace( GL10.GL_BACK );
gl.glBindTexture( GL10.GL_TEXTURE_2D, textures[ 0 ] );
gl.glEnableClientState( GL10.GL_COLOR_ARRAY );
gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );
gl.glColorPointer( 4, GL10.GL_FLOAT, 0, colorBuffer );
gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, vertexBuffer );
gl.glDrawElements( GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer );
gl.glDisableClientState( GL10.GL_VERTEX_ARRAY );
gl.glDisableClientState( GL10.GL_COLOR_ARRAY );
gl.glDisable( GL10.GL_CULL_FACE );
}
}
I sure hope someone can help me with this. I believe, as always, that the solution is simple and easy - it is just me who can't see it right now.
This problem is inherent to Euler angles representation of rotation (that is storing rotation as rotations from the reference axes) as each subsequent part of rotation changes the reference frame.
You could try using some different representation of object rotation, like quaternions or - per Ishtar's suggestion - rotation matrix or axis/angle.
Here is a tutorial on quaternions if you would like to try them:
http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
And also some different suggestions:
http://gpwiki.org/forums/viewtopic.php?t=8611&sid=7d8cb26617084c80c670634d3d7e9f36
http://www.gamedev.net/community/forums/topic.asp?topic_id=491391
I think it's the order that you are doing the rotations in. Have you tried this way:
gl.glRotatef( yRotation, 0.0f, 1.0f, 0.0f );
gl.glRotatef( xRotation, 1.0f, 0.0f, 0.0f );
It's not simple.
xRotation += ( yDelta * 0.5f );
yRotation += ( xDelta * 0.5f );
This is not going to work. Either your x or y-axis won't be correct, these are the pitch and roll-axis(?). Not the x and y-axis.
I think you'll need to remember the rotation matrix itself, not some x and y rotations. You better have only one axis you are rotating about. The axis of course depends on the direction of the MotionEvent. And the rotation amount on the total dragged distance.
float xDelta = xEvent - xActionDown;//from starting point
float yDelta = yEvent - yActionDown;
float distance = sqrt(xDelta*xDelta+yDelta*yDelta);
float xaxis = xDelta/distance;//normalized: 0.0 <-> 1.0
float yaxis = yDelta/distance;
gl.glRotatef( distance, yaxis, xaxis, 0.0f );//x and y swapped!
I am 100% sure the above is incorrect. You'll have to add some checks, a minus, etc. But I hope you get the basic idea?