Render ellipse using libgdx - java

I am attempting to render an ellipse using ShapeRenderer, and have come up with the following partial solution:
void drawEllipse(float x, float y, float width, float height) {
float r = (width / 2);
ShapeRenderer renderer = new ShapeRenderer();
renderer.setProjectionMatrix(/* camera matrix */);
renderer.begin(ShapeType.Circle);
renderer.scale(1f, (height / width), 1f);
renderer.circle(x + r, y, r);
renderer.identity();
renderer.end();
}
This draws an ellipse at the specified coordinates with the correct width and height; however, it appears that the scale transformation causes the circle to be translated in the viewport, and I have not been successful in determining the mathematics behind the translation. I am using an orthogonal projection with y-up where the coordinates map to a pixel on the screen. I am not very familiar with OpenGL.
How can I draw an ellipse using libgdx, and have it draw the ellipse at the exact coordinates I specify? Ideally, that would mean that the origin of the ellipse is located in the top-left corner, if the ellipse was contained in a rectangle.

The new Libgdx ShapeRenderer API (current nightlies, in whatever release will come after v0.9.8) contains an ellipse drawing method so you can ignore the rest of this answer. The ShapeRenderer method has changed in other ways, too though (e.g., the ShapeType is just Filled, Line, or Point now).
For folks stuck with the older API, you should be able to work-around the distortion by making sure the scaling happens around the origin. This is a standard OpenGL practice (so its a bit obtuse, but they're following OpenGL's lead). See Opengl order of matrix transformations and OpenGL: scale then translate? and how?. Even better (again standard OpenGL practice) you end up listing the operations in the reverse order you want them to happen at, so to make a circle, distort it into an ellipse, then move it to a specific destination you actually write code like:
renderer.begin(ShapeType.Circle);
renderer.translate(x, y, 0);
renderer.scale(1f, (height/width), 1f);
renderer.circle(0, 0, r);
renderer.end();

Related

In OpenGL, how do I make it so that my skybox does not cover any of my entities?

I am working on an OpenGL game in Java with LWJGL (ThinMatrix's tutorials at the moment) and I just added my skybox. As you can see from the picture, however, it is clipping through the trees and covering everything behind a certain point.
Here is my rendering code for the skybox:
public void render(Camera camera, float r, float g, float b) {
shader.start();
shader.loadViewMatrix(camera);
shader.loadFogColor(r, g, b);
GL30.glBindVertexArray(cube.getVaoID());
GL20.glEnableVertexAttribArray(0);
bindTextures();
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount());
GL30.glBindVertexArray(0);
shader.stop();
}
private void bindTextures() {
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
GL13.glActiveTexture(GL13.GL_TEXTURE1);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, nightTexture);
shader.loadBlendFactor(getBlendFactor());
}
also if it is needed, here is my code for my master renderer:
public void render(List<Light> lights, Camera camera){
prepare();
shader.start();
shader.loadSkyColor(RED, GREEN, BLUE);
shader.loadLights(lights);
shader.loadViewMatrix(camera);
renderer.render(entities);
shader.stop();
terrainShader.start();
terrainShader.loadSkyColor(RED, GREEN, BLUE);
terrainShader.loadLight(lights);
terrainShader.loadViewMatrix(camera);
terrainRenderer.render(terrains);
terrainShader.stop();
skyboxRenderer.render(camera, RED, GREEN, BLUE);
terrains.clear();
entities.clear();
}
There are two things you can do
If you draw your skybox first, you can disable your depth test glDisable(GL_DEPTH_TEST) or your depth write glDepthMask(false). This will prevent that your skybox draws depth values, and the skybox will never be in front of anything that will be drawn later.
If you draw your skybox last, you can make it literally infinitely big by using vertex coordinates with a w-coordinate as 0. A vertex (x y z 0) means it is a vertex infinitely far in the direction of the vector (x y z). To prevent clipping, you have to enable depth clamping glEnable(GL_DEPTH_CLAMP) this will prevent OpenGl to clip away your skybox faces, and you are sure that the skybox is always at the maximum distance and will never hide anything you have drawn earlier.
the advantage of the second method is within the depth test. Because you already have a depth values written for your scene, the OpenGL pipeline can skip the calculation of the skybox pixels that are already covered by your scene. But the fragment shader for skyboxes is usually very trivial, so it shouldn't make that much of a difference.
I am not familiar with LWJGL, are you alllowed to write shader? In plain opengl, you don't have to worry about the size of skybox cube, it can be {1.0, 1.0, 1.0} if you like. What you need is first place your camera at {0.0, 0.0, 0.0} and make skybox fail depth test against everything in your scene, you can achieve that by making the skybox's z value in normalized device coordinate be 1.0.
Do this in your vertex shader
gl_Position = (mvp_mat * vec4(xyz, 1.0)).xyww;
after the perspective divide by w, z will be w / w or 1.0.
You might want to check out How can I increase distance (zfar/gluPerspective) where openGL stops drawing objects?
The problem in that instance is that the skybox itself was too small and intersecting with the geometry.
I also see that you're rendering your terrain first, and then your skybox. I would try flipping the order there; draw the skybox first then the terrain.
First, you should remove the skybox and render the scene again to check if it is skybox that clip the tree.
If it is skybox, simply scale the skybox to make it contain all the object in the terrain.
If not, it is likely to be the problem of camera (like Hanston said). You need to set the far clipping plane at least behind the skybox. That is, it should be larger the diameter of your skybox.
If you want to scale the skybox or any other object, use the transformationMatrix. the game engine use a 4x4 matrix to control the size, location and rotation of the model. you can see example in source TerrainRenderer.java, at function loadModelMatrix. It create a transform matrix and uploads it into the shader. You should do the same thing, but change the scale parameter into what you want.

Pan within large image borders with LibGdx

I am building a small testing game, basically where is waldo. I have a large image that I can pan around and look for Waldo, but I can't figure out how to keep the camera within the sprite borders (x, y). Right now you can pan past the image borders and on and on and on forever.
Relevant code:
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
public boolean pan(float x, float y, float deltaX, float deltaY) {
camera.translate(-deltaX * PAN_SPEED, deltaY * PAN_SPEED);
camera.update();
return true;
}
there isn't much, I've tried quite a few things but the problem is I can't figure out how to get the distance I have panned, and I need that if I am going to put up a "border". Right now the sprite.getX() == -2200), and the camera viewport is only (480x800), so I am having a hard time working with the Image size and the viewport, and the distance that has been panned.
I've had to solve this before, but I did it very inelegantly. I basically just had a log printing out my current camera's position as I panned around. When I could see off the edge of the screen (to the blank GL wipe underneath), I wrote down the camera's position.
I ended up knowing that if the camera.getX() > sprite.getWidth() - someVal, the edge would on screen. So, I just added in a method that clipped down any X/Y val of a camera if it over shot these predefined bounds.
It's not a great answer, but it also allows you control.

Android OpenGL ES: How do you select a 2D object?

I have been searching for a introductory to 2D selection in OpenGL ES in Stack Overflow. I mostly see questions about 3D.
I'm designing a 2D tile-based level editor on Android 4.0.3, using OpenGL ES. In the level editor, there is a 2D, yellow, square object placed in the center of the screen. All I wanted is to detect to see if the object has been touched by a user.
In the level editor, there aren't any tiles overlapping. Instead, they are placed side-by-side, just like two nearby pixels in a bitmap image in MS Paint. My purpose is to individually detect a touch event for each square object in the level editor.
The object is created with a simple vertex array, and using GL_TRIANGLES to draw 2 flat right triangles. There are no manipulations and no loading from a file or anything. The only thing I know is that if a user touches any one of the yellow triangles, then both yellow triangles are to be selected.
Could anyone provide a hint as to how I need to do this? Thanks in advance.
EDIT:
This is the draw() function:
public void draw(GL10 gl) {
gl.glPushMatrix();
gl.glTranslatef(-(deltaX - translateX), (deltaY - translateY), 1f);
gl.glColor4f(1f, 1f, 0f, 1f);
//TODO: Move ClientState and MatrixStack outside of draw().
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glPopMatrix();
}
EDIT 2:
I'm still missing some info. Are you using a camera? or pushing other
matrixes before the model rendering?. For example, if you are using an
orthographic camera, you can easily unproject your screen coordinates
[x_screen, y_screen] like this (y is analogous):
I'm not using a camera, but I'm probably using an orthographic projection. Again, I do not know, as I'm just using a common OpenGL function. I do pushing and popping matrices, because I plan on integrating many tiles (square 2D objects) with different translation matrices. No two tiles will have the same translation matrix M.
Is a perspective projection the same as orthographic projection when it comes to 2D? I do not see any differences between the two.
Here's the initial setup when the surface is created (a class extending GLSurfaceView, and implementing GLSurfaceView.Renderer):
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
reset();
}
public void onDrawFrame(GL10 gl) {
clearScreen(gl);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0f, super.getWidth(), 0f, super.getHeight(), 1, -1);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
canvas.draw(gl);
}
private void clearScreen(GL10 gl) {
gl.glClearColor(0.5f, 1f, 1f, 1f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}
A basic approach would be the following:
Define a bounding box for each "touchable" object. This could be
just a rectangle (x, y, width, height).
When you update a tile in the world you update its
bounding box (completely in world coordinates).
When user touches the screen, you have to unproject screen
coordinates to world coordinates
Check if unprojected point overlaps with any bounding box.
Some hints on prev items.[Edited]
1 and 2. You should have to keep track of where you are rendering
your tiles. Store their position and size. A rectangle is a
convenient structure. In your example it could be computed like
this. And you have to recompute it when model changes. Lets call it Rectangle r:
r.x = yourTile.position.x -(deltaX - translateX)
r.y = yourTile.position.y -(deltaY - translateY)
r.width= yourTile.width //as there is no model scaling
r.height = yourTile.height//
3 - if you are using
an orthographic camera, you can easily unproject your screen
coordinates [x_screen, y_screen] like this (y is analogous):
x_model = ((x_screen/GL_viewport_width) -0.5 )*camera.WIDTH + Camera.position.x
4 - For each of your Rectangles check if [x_model; y_model] is inside it.
[2nd Edit] By the way you are updating your matrixes, you can consider you are using a camera with postition surfaceView.width()/2, surfaceView.height()/2. You are matching 1 pixel on screen to 1 unit in world, so you dont need to unproject anything. You can replace that values on my formula and get x_screen = x_model - (You 'll need to flip the Y component of the touch event because of the Y grows downwards in Java, and upwards in GL).
Final words. If user touches point [x,y] check if [x, screenHeight-y]* hits some of your rectangles and you are done.
Do some debugging, log the touching points and see if they are as expected. Generate your rectangles and see if they match what you see on screen, then is a matter of checking if a point is inside a rectangle.
I must tell you that you should not set the camera to screen dimensions, because your app will look dramatically different on different devices. This is a topic on its own so i won't go any further, but consider defining your model in terms of world units - independent from screen size. This is getting so off-topic, but i hope you have gotten a good glimpse of what you need to know!
*The flipping i told you.
PS: stick with the orthographic projection (perspective would be more complex to use).
Please, allow me to post a second answer to your question. This is completely more high-level/philosophical. May be a silly, useless answer but, I hope it will help someone new to computer graphics to change it's mind to "graphics mode".
You can't really select a triangle on the screen. That square is not 2 triangles. That square is just a bunch of yellow pixels. OpenGL takes some vertices, connects them, process them and colors some pixels on the screen. At one stage on the graphics pipeline even geometrical information is lost, and you only have isolated pixels. That's analogous to a letter printed by a printer on a paper. You usually don't process information from a paper (ok, maybe a barcode reader does :D)
If you need to further process your drawings, you have to model them and process them yourself with auxiliary data structures. That's why I suggested you created a rectangle to model your tiles. You create your imaginary "world" of objects, and then render them to screen. The user touch-event does not belong to the same world, so you have to "translate" screen coordinates into your world coordinates. Then you change something in your world (may be the user drags her finger and you have to move an object), and back again tell OpenGL to render your world to screen.
You should operate on your model, not the view. Meshes are more of a view thing, so you shouldn't mix them with the model information, it's a good practice to separate both things. (please, an expert correct me, I'm quite a graphics hobbyist)
Have you checked out LibGDX?
Makes life so much easier when working with OpenGL ES.

How would I read a sprite sheet in LWJGL?

I currently use LWJGL Textures to draw images on the screen. I would like to read Textures* from a sprite sheet. I am using slick's TextureLoader class to load the textures.
I draw an LWJGL Shape and bind a Texture onto it.
e.g:
Me drawing an image:
Texture texture = ResourceManager.loadTexture("Images/Tests/test.png");
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, texture.getHeight());
GL11.glVertex2f(0, height);
GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());
GL11.glVertex2f(width,height);
GL11.glTexCoord2f(texture.getWidth(), 0);
GL11.glVertex2f(width,0);
}
GL11.glEnd();
I think there is a way by when calling glTexCoord2f, I could give it a sprite offset and load the sprite sheet in the texture instead,
for example one call would be like this:
GL11.glTexCoord2f(0+spriteXOffset, texture.getHeight()-spriteYOffset);
But I would really like to know if there is a simpler way, maybe extracting Textures from a single texture for example like they do in here:
Reading images from a sprite sheet Java
Just instead of BufferedImage, Texture object.
Thank you for the help!
Texture coordinates for GL_TEXTURE_2D, used internally by the Slick texture loader, require normalized texture coordinates. That is, the coordinates range from 0.0 to 1.0. So (0,0) is the top-left corner of the texture, and (1,1) is the bottom-right corner. Assuming that you have your sprite coordinates in pixel coordinates at hand, you then have to divide the x coordinate by the texture width and the y coordinate by the texture height, resulting in normalized texture coordinates. You would then supply these coordinates to OpenGL using glTexCoord.
glTexCoord2f(spriteX / textureWidth, spriteY / textureHeight);
glVertex2f(coordinateX, coordinateY);
glTexCoord2f(spriteX+spriteWidth / textureWidth, spriteY / textureHeight);
glVertex2f(coordinateX2, coordinateY);
// Et cetera
There is, however, also an easier way of doing this. Take a look at this video (I created it), to see how you can use the pixel coordinates for textures instead of normalized ones.

How to -accurately- measure size in pixels of text being drawn on a canvas by drawTextOnPath()

I'm using drawTextOnPath() to display some text on a Canvas and I need to know the dimensions of the text being drawn. I know this is not feasible for paths composed of multiple segments, curves, etc. but my path is a single segment which is perfectly horizontal. I am using Paint.getTextBounds() to get a Rect with the dimensions of the text I want to draw.
I use this rect to draw a bounding box around the text when I draw it at an arbitrary location.
Here's some simplified code that reflects what I am currently doing:
// to keep this example simple, always at origin (0,0)
public drawBoundedText(Canvas canvas, String text, Paint paint) {
Rect textDims = new Rect();
paint.getTextBounds(text,0, text.length(), textDims);
float hOffset = 0;
float vOffset = paint.getFontMetrics().descent; // vertically centers text
float startX = textDims.left; / 0
float startY = textDims.bottom;
float endX = textDims.right;
float endY = textDims.bottom;
path.moveTo(startX, startY);
path.lineTo(endX, endY);
path.close();
// draw the text
canvas.drawTextOnPath(text, path, 0, vOffset, paint);
// draw bounding box
canvas.drawRect(textDims, paint);
}
The results are -close- but not perfect. If I replace the second to last line with:
canvas.drawText(text, startX, startY - vOffset, paint);
Then it works perfectly. Usually there is a gap of 1-3 pixels on the right and bottom edges. The error seems to vary with font size as well. Any ideas? It's possible I'm doing everything right and the problem is with drawTextOnPath(); the text quality very visibly degrades when drawing along paths, even if the path is horizontal, likely because of the interpolation algorithm or whatever its using behind the scenes. I wouldnt be surprised to find out that the size jitter is also coming from there.
I've found a solution that works for my particular situation, although it doesn't really resolve the original question.
Since my particular use case only draws text along single segment straight paths, I was able to get rid of the paths all together and use Canvas.drawText() along with Canvas.translate() and canvas.rotate(). This got rid of the text size randomness and ugliness I was seeing when drawing along paths as well.

Categories