Related
I'm trying to work on some OpenGL stuff. What I've got up to now is a viewport, in which I'm drawing some imaginary "borders" by using GL_LINES. It looks like this, with setLookAt set as follows:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0);
My frustum is set: Matrix.frustumM(mProjectionMatrix, 0, -2, 2, -2, 2, 1, 11); so I'm positioned somewhere inside the "cube".
Now what I'm trying to achieve is let the user look around. I'm capturing onTouchEvents, passing any movement in x/y direction to the renderer. What I'm doing next is rotating all lines drawn by the specific angle I received from the touch listener.
It then looks like this:
So the cube is not rotated around the viewer or the eye-center, but instead around some point that I don't know where it's coming from.
My problem is: how can I rotate the object around the viewer's center/position? Do I have to rotate the mViewMatrix which comes from setLookAtM? If yes, simply by using Matrix.setRotateM(mViewMatrix, ...)?
The Line's drawing method looks like this:
public void draw(float[] mViewMatrix, float[] mProjectionMatrix) {
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
GLES20.glUseProgram(iProgId);
lineBuffer.position(0);
GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, lineBuffer);
GLES20.glEnableVertexAttribArray(iPosition);
colorBuffer.position(0);
GLES20.glVertexAttribPointer(iColor, 3, GLES20.GL_FLOAT, false, 0, colorBuffer);
GLES20.glEnableVertexAttribArray(iColor);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.rotateM(mModelMatrix, 0, rotX, 1, 0, 0);
Matrix.rotateM(mModelMatrix, 0, -rotY, 0, 1, 0);
Matrix.setIdentityM(mViewProjectionMatrix, 0);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
//GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewProjectionMatrix, 0);
GLES20.glUniformMatrix4fv(iVPMatrix, 1, false, mMVPMatrix, 0);
//GLES20.glDrawElements(GLES20.GL_LINES, mVertices.length/2, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
GLES20.glDrawArrays(GLES20.GL_LINES, 0, mVertices.length / 2);
}
look at function takes 3 vertices, eye position, target position and up vector. Basically it generates a matrix that moves scene around to render scene like you are looking from eye position to target position. In your example your is at 0,0,0 and looks at 5, 0, 0 (so you are looking at +x direction and up is defined as 0, 1, 0 (higher y value means object will be at top of window.)
Instead of using those constants, first define a camera position.
float cameraX, cameraY, cameraY;
it is harder to work with target vectors, so instead use an angle that defines which direction you are looking at
float angle;
and to calculate targetVector use this angle.
float targetX = cameraX + cos(angle);
float targetY = cameraY;
float targetZ = cameraZ + sin(angle);
Now to move camera around, you have to modify cameraX-Y-Z. If you want to move forward you should move your camera towards to target vector. For example to move 10 unit forward.
targetX += cos(angle)*10;
targetY += sin(angle)*10;
You also need to recalculate target vector since target position also should move.
If you want to move backwards, use -= operator instead. If you want to move sides then you have to add or remove angle PI/2 in those calculations.
To rotate camera around just increase/decrease angle and recalculate target vector.
This is a very basic camera and you won't be able to look up or down. You have to use pitch/yaw camera to be able to look up and down.
sorry for my english
I want to draw textures on clean C, no objective c!
that it is necessary to write a library for ios / android
I draw
- (BOOL)createFramebuffer{
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];//a string
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)drawView {
[EAGLContext setCurrentContext:context];//a string
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, spriteTexture);
Byte *byteData = (Byte*)malloc(3686400);
memcpy(byteData, [texData bytes]+kon, 3686400);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1280, 720, GL_RGBA, GL_UNSIGNED_BYTE, byteData);
free(byteData);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];//a string
}
how to get rid of these lines, which are tied to objective c?
1 [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
2 [EAGLContext setCurrentContext:context];
3 [context presentRenderbuffer:GL_RENDERBUFFER_OES];</code>
You can't, and still have this render to the screen in iOS. EAGLContext is an Objective-C object that is used to manage your OpenGL ES contexts, and you need to interact with it in order to render and display your scene.
However, you can wrap accesses to this in a function that changes its contents depending on what platform you are targeting. Compiler conditionals can help you do this.
I am new to OpenGL programming.I have made a rotating cube with different images on different faces of the cube..i want to set background for the Screen..Any help will be appreciated..
Draw a textured quad covering the whole viewport. To do this, switch the projection and modelview to identity and disable depth testing. With projection and modelview being identity vertex coordinates [-1 … 1] will cover the whole viewport. In code:
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat tex_quad[16] = {
/* x, y, s, t */
-1, -1, 0, 0,
1, -1, 1, 0,
1, 1, 1, 1,
-1, 1, 0, 1
};
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*4, &tex_quad[0]);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*4, &tex_quad[2]);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, background_image_texture_ID);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDisable(GL_TEXTURE_2D);
In my project all code of creation GLSurfaceView looks like:
glSurfaceView = ...
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
glSurfaceView.setBackgroundResource(R.drawable.my_background);
glSurfaceView.setZOrderOnTop(true);
glSurfaceView.setRenderer(...);
glSurfaceView.setRenderMode(...);
NOTE: Do not use
_glSurfaceView.setBackgroundDrawable(this.getResources().getDrawable(R.drawable.my_background));
I wasted a few days on it.
And do not call
gl.glClearColor(...)
in
Renderer.onDrawFrame
I think the OP wants to turn his code into an android live wallpaper.
#Sumit : if I'm right you should do your due dilligence: http://developer.android.com/resources/articles/live-wallpapers.html
If I'm wrong, then please be more precise in your question.
I am examining an interesting problem I'm facing with OpenGL lighting on Android. I'm working on a 3D Viewer where you can add and manipulate 3D objects. You can also set a light with different attributes. The problem I was facing with my Viewer was that the highlight on the 3D objects from the light (it is a point light) behaved strangely. If the light source was in the exact same point as the camera, the highlight would move in the opposite direction you would expect. (So if you move the object to the left, the highlight moves to the leftedge of the object as well, instead of the right, which is what I was expecting.)
So to further narrow the problem down I've created a small sample application that only renders a square and then I rotate that square around the camera position (the origin), which is also where the light is placed. This should result in all squares facing the camera directly, so that they would be completely highlighted. The result though looked like that:
Can it be that these artifacts appear because of the distortion you get on the border due to the projection?
In the first image the distance between the sphere and the camera is about 20 units and the size of the sphere is about 2. If I move the light closer to the object the highlight looks a lot better, in the way I'm expecting it.
In the second image the radius in which the squares are located is 25 units.
I'm using OpenGL ES 1.1 (since I was struggling to get it to work with shaders in ES 2.0) on Android 3.1
Here is some of the code I'm using:
public void onDrawFrame(GL10 gl) {
// Setting the camera
GLU.gluLookAt(gl, 0, 0, 0, 0f, 0f, -1f, 0f, 1.0f, 0.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
for (int i = 0; i < 72; i++) {
gl.glPushMatrix();
gl.glRotatef(5f * i, 0, 1, 0);
gl.glTranslatef(0, 0, -25);
draw(gl);
gl.glPopMatrix();
}
}
public void draw(GL10 gl) {
setMaterial(gl);
gl.glEnable(GL10.GL_NORMALIZE);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFrontFace(GL10.GL_CCW);
// Enable the vertex and normal state
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, mIndexBuffer.capacity(), GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
// Setting the light
private void drawLights(GL10 gl) {
// Point Light
float[] position = { 0, 0, 0, 1 };
float[] diffuse = { .6f, .6f, .6f, 1f };
float[] specular = { 1, 1, 1, 1 };
float[] ambient = { .2f, .2f, .2f, 1 };
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glLightfv(GL10.GL_LIGHT0, GL_POSITION, position, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_DIFFUSE, diffuse, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_AMBIENT, ambient, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_SPECULAR, specular, 0);
}
private void setMaterial(GL10 gl) {
float shininess = 30;
float[] ambient = { 0, 0, .3f, 1 };
float[] diffuse = { 0, 0, .7f, 1 };
float[] specular = { 1, 1, 1, 1 };
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse, 0);
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient, 0);
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular, 0);
gl.glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
}
I'm setting the light in the beginning, when the activity is started (in onSurfaceCreated) and the material everytime I draw a square.
The effect in your second example (with the squares) is rather due to the default non-local viewer that OpenGL uses. By default the eye-space view vector (the vector from vertex to camera, used for the specular highlight computation) is just taken to be the (0, 0, 1)-vector, instead of the normalized vertex position. This approximation is only correct if the vertex is in the middle of the screen, but gets more and more incorrect the farther you move to the boundary of the srceen.
To change this and let OpenGL use the real vector from the vertex to the camera, just use the glLightModel function, especially
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
I'm not sure if this is also the cause for your first problem (with the sphere), but maybe, just try it.
EDIT: It seems you cannot use GL_LIGHT_MODEL_LOCAL_VIEWER in OpenGL ES. In this case there is no way around this problem, except switching to OpenGL ES 2.0 and doing all lighting computations yourself, of course.
Your light is probably moving when you're moving your object.
Take a look at this answer http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050
The reason I'm asking this is that our app (The Elements) runs fine on a Droid and a Nexus One, our two test phones, but not correctly on our recently acquired Atrix 4G. What draws is a skewed version of what should draw, with all the colors being replaced with alternating lines of cyan, magenta, and yellow (approximately), which leads us to believe that one of the primary colors for the sand particles that should show up is missing based on which line it's on. I'm sorry for the unclear description, we had images but since this account doesn't have 10 reputation we couldn't post them.
Here is the code of our gl.c file, which does the texturing and rendering:
/*
* gl.c
* --------------------------
* Defines the gl rendering and initialization
* functions appInit, appDeinit, and appRender.
*/
#include "gl.h"
#include <android/log.h>
unsigned int textureID;
float vertices[] =
{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
float texture[] =
{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
unsigned char indices[] =
{0, 1, 3, 0, 3, 2};
int texWidth = 1, texHeight = 1;
void glInit()
{
//Set some properties
glShadeModel(GL_FLAT);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//Generate the new texture
glGenTextures(1, &textureID);
//Bind the texture
glBindTexture(GL_TEXTURE_2D, textureID);
//Enable 2D texturing
glEnable(GL_TEXTURE_2D);
//Disable depth testing
glDisable(GL_DEPTH_TEST);
//Enable the vertex and coord arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//Set tex params
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//Set up texWidth and texHeight texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, emptyPixels);
//Free the dummy array
free(emptyPixels);
//Set the pointers
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texture);
}
void glRender()
{
//Check for changes in screen dimensions or work dimensions and handle them
if(dimensionsChanged)
{
vertices[2] = (float) screenWidth;
vertices[5] = (float) screenHeight;
vertices[6] = (float) screenWidth;
vertices[7] = (float) screenHeight;
texture[2] = (float) workWidth/texWidth;
texture[5] = (float) workHeight/texHeight;
texture[6] = (float) workWidth/texWidth;
texture[7] = (float) workHeight/texHeight;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (!flipped)
{
glOrthof(0, screenWidth, screenHeight, 0, -1, 1); //--Device
}
else
{
glOrthof(0, screenWidth, 0, -screenHeight, -1, 1); //--Emulator
}
dimensionsChanged = FALSE;
zoomChanged = FALSE;
}
else if(zoomChanged)
{
texture[2] = (float) workWidth/texWidth;
texture[5] = (float) workHeight/texHeight;
texture[6] = (float) workWidth/texWidth;
texture[7] = (float) workHeight/texHeight;
zoomChanged = FALSE;
}
//__android_log_write(ANDROID_LOG_INFO, "TheElements", "updateview begin");
UpdateView();
//__android_log_write(ANDROID_LOG_INFO, "TheElements", "updateview end");
//Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
//Sub the work portion of the tex
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, workWidth, workHeight, GL_RGB, GL_UNSIGNED_BYTE, colors);
//Actually draw the rectangle with the text on it
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
}
Any ideas as to what the difference is between the Atrix 4G and other phones in terms of OpenGL or why our app is doing what it is in general are much appreciated! Thanks in advance.
Here is an example of what it looks like: http://imgur.com/Oyw64
I know it's a bit late to reply, but the real reason you're seeing the mixed colors is due to OpenGL's scanline packing alignment -- not due to any driver bug or power-of-two sized texture issue.
Your glTexSubImage2D call is sending data in GL_RGB format, so I'm guessing your colors buffer is 3 bytes per pixel. Odds are the Droid and Nexus One phones have a default pack alignment of 1, but the Tegra 2 defaults to an alignment of 4. This means your 3 byte array can become misaligned with what the driver expects after every scanline, and a byte or two will be skipped for the next scanline, resulting in the colors you see. The reason why this works with a power-of-two sized texture is because your buffer just happens to be aligned properly for the next scanline. Basically this is the same issue as loading BMPs, where each scanline has to be padded to 4 bytes, regardless of the bit depth of the image.
You can explicitly disable any alignment packing by calling glPixelStorei(GL_PACK_ALIGNMENT, 1);. Note that changing this only affects the way OpenGL interprets your texture data, so there is no rendering performance penalty for changing this value. When the texture is sent to the graphics subsystem, the scanlines are stored in whatever format is optimal for the hardware, but the driver still has to know how to unpack your data properly. However, since you are changing the texture data every frame, instead of the driver being able to do one memcpy() to upload the entire texture, it will have to do TextureHeight *memcpy()s in order to upload it. This is not likely to be a major bottleneck, but if you are looking for the best performance, you may want to query the driver's default pack alignment on startup using glGetIntegerv(GL_PACK_ALIGNMENT, &align); and adjust your buffer accordingly at runtime.
Here's the specification on glPixelStore() for reference.
Ok, we finally found the actual problem. It turns out that glSubTexImage2D() actually requires the WIDTH to be a power of two, but not the height, for some GPUs including the Tegra 2. We though that it was only the texture that needed to be a power of two and that's where we were wrong. We're going to have to do a bit of recoding, but hopefully this will work out in the end (AT LAST!!).
The Atrix 4G is the first prominent phone that uses Nvidia's Tegra GPU. As such, it has an entirely different OpenGL implementation than previous Android devices. Either you are observing a bug Tegra hardware+software combination, or your application was relying on undefined behavior and you were getting lucky on other devices.
You may want to file a bug report with Nvidia.