I want to create a camera moving above a tiled plane. The camera is supposed to move in the XY-plane only and to look straight down all the time. With an orthogonal projection I expect a pseudo-2D renderer.
My problem is, that I don't know how to translate the camera. After some research it seems to me, that there is nothing like a "camera" in OpenGL and I have to translate the whole world. Changing the eye-position and view center coordinates in the Matrix.setLookAtM-function just leads to distorted results.
Translating the whole MVP-Matrix does not work either.
I'm running out of ideas now; do I have to translate every single vertex every frame directly in the vertex buffer? That does not seem plausible to me.
I derived GLSurfaceView and implemented the following functions to setup and update the scene:
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// Setup the projection Matrix for an orthogonal view
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//Setup the camera
float[] camPos = { 0.0f, 0.0f, -3.0f }; //no matter what else I put in here the camera seems to point
float[] lookAt = { 0.0f, 0.0f, 0.0f }; // to the coordinate center and distorts the square
// Set the camera position (View matrix)
Matrix.setLookAtM( vMatrix, 0, camPos[0], camPos[1], camPos[2], lookAt[0], lookAt[1], lookAt[2], 0f, 1f, 0f);
// Calculate the projection and view transformation
Matrix.multiplyMM( mMVPMatrix, 0, projMatrix, 0, vMatrix, 0);
//rotate the viewport
Matrix.setRotateM(mRotationMatrix, 0, getRotationAngle(), 0, 0, -1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
//I also tried to translate the viewport here
// (and several other places), but I could not find any solution
//draw the plane (actually a simple square right now)
mPlane.draw(mMVPMatrix);
}
Changing the eye-position and view center coordinates in the "LookAt"-function just leads to distorted results.
If you got this from the android tutorial, I think they have a bug in their code. (made a comment about it here)
Try the following fixes:
Use setLookatM to point to where you want the camera to be.
In the shader, change the gl_Position line
from: " gl_Position = vPosition * uMVPMatrix;"
to: " gl_Position = uMVPMatrix * vPosition;"
I'd think the //rotate the viewport section should be removed as well, as this is not rotating the camera properly. You can change the camera's orientation in the setlookat function.
Related
I am programming a GUI framework in lwjgl (opengl for java). I've recently implemented rounded rectangles by rendering a couple of normal rectangles surrounded by circles. To render the circles I used GL11.GL_POINTS. I now reached the point, where I am trying to implement animations and for a window open animation, I decided to GL11.glScaled() it from small to normal. That works fine, but unfortunately my circles don't get resized.
I tried changing my GL_POINTS circle render method against a method that uses TRIANGLE_FANs and that worked fine. My problem there was, that the circles didn't look smooth and round at all and if I increase the rendered triangles it starts to lag very quick. Even though my computer isn't bad at all.
This is the code I've used to render circles with GL_POINTS.
GL11.glEnable(GL11.GL_POINT_SMOOTH);
GL11.glHint(GL11.GL_POINT_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glPointSize(radius);
GL11.glBegin(GL11.GL_POINTS);
GL11.glVertex2d(x, y);
GL11.glEnd();
GL11.glDisable(GL11.GL_POINT_SMOOTH);
This is the code I've used to scale the circles
GL11.glPushMatrix();
GL11.glTranslated(x, y, 0);
GL11.glScaled(2.0f, 2.0f, 1);
GL11.glTranslated(-x, -y, 0);
render circles
GL11.glPopMatrix();
I expect the circles to scale accordingly to the number I've put into glScaled()
Currently they aren't rescaling at all, just rendered at their normal size.
Here's a demonstration of how to properly render a circle using triangle fans:
public void render() {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
// Coordinate system starts out as screen space coordinates
glOrtho(0, 400, 300, 0, 1, -1);
glColor3d(1, 0.5, 0.5);
renderCircle(120, 120, 100);
glColor3d(0.5, 1, 0.5);
renderCircle(300, 200, 50);
glColor3d(0.5, 0.5, 1);
renderCircle(200, 250, 30);
}
private void renderCircle(double centerX, double centerY, double radius) {
glPushMatrix();
glTranslated(centerX, centerY, 0);
glScaled(radius, radius, 1);
// Another translation here would be wrong
renderUnitCircle();
glPopMatrix();
}
private void renderUnitCircle() {
glBegin(GL_TRIANGLE_FAN);
int numVertices = 100;
double angle = 2 * Math.PI / numVertices;
for (int i = 0; i < numVertices; ++i) {
glVertex2d(Math.cos(i*angle), Math.sin(i*angle));
}
glEnd();
}
Output image:
The GL_POINT_SIZE value is actually the size of the point in pixels onscreen, not current coordinate units. For that reason your circles were unaffected by GL_SCALE. That's one reason not to use GL_POINTS to render circles. The other (arguably more important) reason being that GL_POINT_SIZE is severely deprecated and unsupported in newer OpenGL profiles.
currently I am scaling a matrix like so:
public void scale(float aw, float ah){
Matrix.scaleM(modelMatrix, 0, aw, ah, 1f);
updateMVP();
}
private void updateMVP(){
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelMatrix, 0);
}
And using: gl_Position = u_Matrix * a_Position; in my vertex shader, u_Matrix being the mvpMatrix. The camera I am using is the default and the projectionMatrix is created by:
ASPECT_RATIO = (float) height / (float) width;
orthoM(projectionMatrix, 0, -1f, 1f, -ASPECT_RATIO, ASPECT_RATIO, -1f, 1f);
Now I can scale my object properly, but the only problem is that every time I scale the matrix, the object moves a little bit. I was wondering how I could scale the matrix while keeping the center point and not having the object translate. Anyone know how I can do this in OpenGL ES 2.0 on Android? Thanks
Do you have any other matrices (rotation/translation)?
If so: you might not be multiplying your matrices in the correct order, which can cause issues.
(proper order multiply right to left)
Translate * Rotation * Scale
Your error sounds like the one explained here:
You translate the ship by (10,0,0). Its center is now at 10 units of the origin.
You scale your ship by 2. Every coordinate is multiplied by 2 relative to the origin, which is far away… So you end up with a big
ship, but centered at 2*10 = 20. Which you don’t want.
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
I am currently trying to snap a crosshair sprite to my game's cursor using libgdx. The game is top-down view:
Texture crosshair_text = new Texture(Gdx.files.internal("data/crosshair1.png"));
this.crosshair = new Sprite(crosshair_text, 0, 0, 429, 569);
//...
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
//.. sprites that scale based on camera (top-down view)
batch.end();
//draws 'ui' elements
floatingBatch.begin();
//...
//snap to cursor
this.crosshair.setPosition( Gdx.input.getX(), (Gdx.graphics.getHeight()-Gdx.input.getY()) );
//transform
this.crosshair.setScale(1/cam.zoom);
//draw
this.crosshair.draw(floatingBatch);
floatingBatch.end();
}
Sorry if there are errors that I didn't catch, this isn't an exact copy of my code. The problem here is that 1. The sprite doesn't snap to the correct position and 2. the crosshair sprite lags behind the current position of the mouse on the screen. Can anyone give me insight on how to fix either of these two issues?
Your position might not be correct because the screen location isn't necessarily the right location to draw onto using your OrthographicCamera, try using the unproject first. E.g:
Vector3 mousePos = new Vector3( Gdx.input.getX(), (Gdx.graphics.getHeight()-Gdx.input.getY()), 0); //Get the mouse-x and y like in your code
cam.unproject(mousePos); //Unproject it to get the correct camera position
this.crosshair.setPosition(mousePos.x, mousePos.y); //Set the position
Plus you need to make sure your floating batch is set to the projection matrix of the camera, add the following code:
floatingBatch.setProjectionMatrix(cam.combined);
Instead of drawing a Sprite at the mouse position, you could change the cursor image:
Gdx.input.setCursorImage(cursorPixMap, hotspotX, hotspotY);
Where cursorPixMap is a PixMap of the new cursor image an hotspotX and hotspotY is the "origin" of the PixMap/cursor image. In your case it would be the center of the crosshair.
So basicly the Gdx.input.getX() and Gdx.input.getY() return the current position of the hotspotX and hotspotY.
I suggest to read the wiki artikcle about the cursor.
I'm trying to draw 5 different textures on the screen, but I can't seem to make the alpha work. Textures are rendered fine if there is no alpha, but when there is, there's a really weird "effect".
Ok, first off I call draw to all 5 of my textures with opacity (in the given order): 0.5,1.0,0.5,1.0,0.5. But when I start the app I actually get 1.0,0.5,1.0,0.5,1.0 like there's an offset of 1. That's not all that's weird. About a half of second after my app launches the very first texture gets opacity of 0.5, even weirder is that this is not happening on the second draw method, but somewhere between the first and second call to draw. How is this even possible?
This is the final result (it should be 0.5,1.0,0.5,1.0,0.5, but as you can see it's not even close):
Now for some code (I've skipped some unrelevant parts).
Creating the surface:
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// Textures are being loaded in here, which is just fine (code skipped)
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
}
Updating the surface:
public void onSurfaceChanged(GL10 gl, int width, int height)
{
// Here I pass width & height to my texture objects for future reference (code skipped)
gl.glViewport(0, 0, width, height);
gl.glOrthof(0, width, height, 0, 0, 1);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
Drawing:
public void onDrawFrame(GL10 gl)
{
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
// Here I call draw of each texture object
}
Draw method of the texture object:
public void draw(GL10 gl)
{
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
gl.glColor4f(1.0f, 1.0f, 1.0f, this.alpha); // This is where the magic doesn't happen (:
}
I've skipped the part where I create vertex/texture buffers and load the textures, that part follows this tutorial and seems to work just fine.
So.. what do you think am I missing? What could be the cause to this weird issue?
If I must guess, I'd say it's some weird hardcore OpenGL issue/bug or more like a flag I forgot to raise or something like that. It can't be the order of drawing or anything like that, I've double checked it all. I've also tried setting say 0.5f as opacity to each texture and it works perfectly, the problem only happens whenever the opacity of the textures differ from each other. I also don't think, that the weird between-draw flicker can be caused by user code, it's gotta be some OpenGL weirdness.
I must point out that I am using a 3rd party library to pack all of this GL magic into a live wallpaper, it's this awesome lib: GLWallpaperService
Why is the place where the magic happens not before the draw call? The default colour value is (1,1,1,1) so at first your start with alpha at 1.0, then you draw the texture and set the alpha to .5 and draw the 2nd texture with this value still set... Ergo the strange offset effect.
When the last texture is drawn you have an alpha of 1.0 (from the one before) and then set it to .5 which is used to draw the first texture in the next refresh: Since the alpha changes from 1.0 to .5 on the top most element it flickers. In the end you clearly get the result seen on the image you posted.
So this truly is where the magic happens:
gl.glColor4f(1.0f, 1.0f, 1.0f, this.alpha); // This is where the magic doesn't happen
So try removing that line and try it like this:
gl.glColor4f(1.0f, 1.0f, 1.0f, this.alpha); // This is where the magic does happen
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Low mana, stop the magic
I'm trying to implement a basic physics engine in Java and I'm using the JOGL bindings so I can visualize the results. I can create and rotate shapes easily enough, but have run into problems whilst manipulating the viewport and whilst moving the shapes.
I don't think a clipping issue - I've tried using the gluPerspective method with a massive range (0.0001f - 10000f) with no success. When I move the camera further away from my objects or move the objects themselves, they disappear.
Tutorials about JOGL are few and far between and many also use different versions of OpenGL, so I turn to the only friend I have left: the wonderful users of stack overflow. :)
Flattery aside, the code follows:
public class JoglEventListener implements GLEventListener, KeyListener, MouseListener, MouseMotionListener {
// keep pointer to associated canvas so we can refresh the screen (equivalent to glutPostRedisplay())
public GLCanvas canvas;
public Particle triforce;
public float x;
// constructor
public JoglEventListener(GLCanvas canvas) {
this.canvas = canvas;
}
#Override
public void display(GLAutoDrawable drawable) {
update();
render(drawable);
}
#Override
public void init(GLAutoDrawable drawable) {
triforce = new Particle();
x = 0;
}
private void update() {
triforce.integrate(0.0001);
x = x + 0.25f;
}
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLU glu = new GLU();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
//gl.glFrustum (.5f, -.5f, -.5f * 1080, .5f * 960, 1.f, 500.f);
glu.gluPerspective(0, 1, 0.1f, 100f);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glHint(GL2.GL_CLIP_VOLUME_CLIPPING_HINT_EXT,GL2.GL_FASTEST);
glu.gluLookAt(0, 0, 1.5, 0, 0, -10, 0, 1, 0);
//gl.glRotatef(90, 0f , 1f , 0f );
//Draw some scale lines
gl.glBegin(GL.GL_LINES);
gl.glColor3f(0.75f, 0.75f, 0.75f);
for (int i = 0; i < 20; i += 1)
{
gl.glVertex3f(-5.0f, 0.0f, i + 0.5f);
gl.glVertex3f(5.0f, 0.0f, i + 0.5f);
}
gl.glEnd();
//gl.glRotatef(x, 1f , 1f , 1f );
gl.glPushMatrix();
gl.glTranslated(triforce.position.x, triforce.position.y, triforce.position.z);
gl.glBegin(GL.GL_TRIANGLE_STRIP);
gl.glColor3f(1f, 0f, 0f);
gl.glVertex3d(0, 0, -2);
gl.glColor3f(0f, 1f, 0f);
gl.glVertex3d(0, 0.25d, -2);
gl.glColor3f(0f, 0f, 1f);
gl.glVertex3d(0.25d, 0, -2);
gl.glColor3f(1f, 1f, 0f);
gl.glVertex3d(0.25d, 0.25d, -2.25d);
gl.glEnd();
gl.glPopMatrix();
gl.glFlush();
}
// (empty overridden methods omitted)
public Particle () {
setMass(200d);
velocity = new Vector3(0d, 30d, 40d);
acceleration = new Vector3(0d, -20d, 0d);
position = new Vector3(0d, 0d, 0d);
damping = 0.99d;
}
public void integrate (double duration) {
if (inverseMass <= 0.0d) {
return;
}
assert (duration > 0.0);
position.addScaledVector(velocity, duration);
Vector3 resultingAcc = new Vector3(acceleration.x, acceleration.y, acceleration.z);
velocity.addScaledVector(resultingAcc, duration);
velocity.multEquals(Math.pow(damping, duration));
//clearAccumulator();
}
public void setMass(double mass)
{
assert(mass != 0);
inverseMass = (1.0d)/mass;
}
Before movement / starting position:
The shape drifts upward and is obscured from the right and top, becoming invisible:
Any help would be greatly appreciated! Thanks!
The massive view range can be a problem. The coordinates of the objects are only so precise, and with a huge view range, things that should be near each other are determined to be at the same point. This can cause an object that should be in front of another to disappear behind it. Try using a smaller view range.
I had the same problem. Objects disappearing, while some stay in the scene. After removing:
gl.glEnable(GL2.GL_CULL_FACE);
everything was working just fine ! Of course this is JOGL code, in C, the command would be without all those objects. Just to make this answer clear for everyone.
In the render function, change the value of last parameter of gluPerspective from 100f to 1000f. It will solve your problem.
gl.gluPerspective(0, 1, 0.1f, 100f);
to
gl.gluPerspective(0, 1, 0.1f, 500f);
And I think in your code you have done a mistake in the above line writing glu.gluperspective
I think it is gl.gluPerspective.
In the end, I was never able to track down the issue, and started again from scratch. I didn't run into any further clipping issues on my new build.
My best guess as to my initial failure is an improperly used glHint or glClear call, or perhaps some problem with the version of JOGL I was referencing.