How to implement Frustum Culling? (Lag when rendering many blocks) - java

I'm creating a game, in which when I render many blocks. The fps goes seriously down and everything lags. I know why it is lagging, because of many objects being rendered at once, but I can't figure out how to create and implement a frustum culling or any type of culling class to my game.
NOTE: I'm using VBOs.
I just can't find on the net; please help.
Here is some of my code:
//Render Game this were I render my game
public void Render_GAME() {
Update();
if (isGameRunning == true) {
Update();
world.render();
p1.Update();
}
}
Flat Class: where I render block
package game.terrain.biomes;
import core.camera.*;
import core.graphics.*;
import core.math.*;
import game.blocks.*;
import game.Player;
public class Flat{
//Global Variables:
private int width;
private int height;
private int depth;
private SpaceStone[][][] blocks;
public Flat(int width, int height, int depth)
{
this.width = width;
this.height = height;
this.depth = depth;
blocks = new SpaceStone[width][height][depth];
createBlocks();
}
//Create Blocks
private void createBlocks()
{
SpaceStone.createBlock();
for(int x = 0; x < width; x += 5)
{
for(int y = 0; y < height; y += 5)
{
for(int z = 0; z < depth; z += 5)
{
blocks[x][y][z] = new SpaceStone(new Vector3f(x, y, z), new Vector3f(0, 0, 0), new Vector3f(2.5f, 2.5f, 5f));
}
}
}
}
//Render Blocks
private void renderBlocks()
{
Shader.BLOCK.Enable();
SpaceStone.blocktex.bindTexture();
SpaceStone.block.Bind();
Shader.BLOCK.setUniform1i("tex", 1);
Matrix4f viewMatrix = Player.getViewMatrix(Player.getCamera());
Shader.BLOCK.setUniformMat4f("pr_matrix", Player.getPerspective());
for(int i = 0; i < width; i += 5)
{
for(int j = 0; j < height; j += 5)
{
for(int k = 0; k < depth; k += 5)
{
Matrix4f transform = new Transformation().getTransform(blocks[i][j][k], viewMatrix);
Shader.BLOCK.setUniformMat4f("vw_matrix", transform);
SpaceStone.block.Draw();
}
}
}
Shader.BLOCK.Disable();
SpaceStone.blocktex.unbindTexture();
SpaceStone.block.Unbind();
}
//Render Flat Biome
public void renderFlatBiome()
{
//Render Blocks
renderBlocks();
}
}
If you want more information, such as classes or the whole project please comment and notify me.

OpenGL performs the frustum culling, it sounds like you need to do some processing every frame to decide which blocks to pass to OpenGL to render (or maybe not every frame, new frustum culling calculations would be required every time the geometry or the camera changes). You need to construct a representation of the frustum and test yourself which geometry to be rendered. The viewing frustum could be considered a volume and so you are looking for which cubes are contained within that volume.
First thing is to see which geometry is behind the near clipping plane and further than the far clipping plane. This can be done by simply calculating the distance to the near and far clipping planes and ensuring they are on the correct side of the plane.
The next thing to do is check which geometry is too far left or right to fit in the frustum, and this is slightly more complicated due to the nature and different projections. Orthographic projection is a lot easier to calculate since the frustum for an orthographic projection is essentially cuboid itself. Perspective is trapezoidal in shape (depending of the field of view), but the principle is the same. Construct two planes which represent the left and right clipping planes of the frustum, and cull geometry which is the 'wrong' side in relation to your camera position.
You are simply relieving GL of geometry to draw which GL will determine not to draw anyway. Depending on the scene, the size of the geometry, the way its stored in the buffers and other aspects, the overhead of binding/unbinding and the vertex processing could easily outweigh any performance hit from culling client side.
I haven't written java for years so can't provide source, however I have outlined the simplest form (and not necessarily optimized) of doing this client side (in relation to OpenGL). By spatial grouping geometry data this some form of hierarchy (bounding volume, KD-tree, AABB etc), you can reduce the amount tests required for the culling.
In a lot of cases, the most basic form of hierarchal grouping is Axis Aligned Bounding Box (AABB), which (if none of your cubes ever have a rotation) is what you already have since you are using cubes. Discrete geometry is usually grouped in some form using cuboid volumes denoted by bounding boxes or 'slabs' (two parallel planes which define a volume between them).

Related

Handling many static bodies in Processing

I'm working on a Java program with Processing library, that plots/draws millions of galaxies (the coordinates do not change) in 3D-space (as simple points) and allows translating, rotating and scaling the view in real time.
I'm using Processing to have GPU acceleration on rendering the view, but the points have to be given to the graphics card by the CPU anyway. So currently my draw() method contains a for loop which "draws" the points one by one. Since nothing about the points changes, only the camera angle, position and scale, it is too slow for my needs.
Current draw():
transformSpace();
for (int i = 0; i < visibleBodies.length; i++) {
Body b = visibleBodies[i];
point(b.x, -b.z, -b.y); // Z-up world
}
Could all the points be handled somehow differently, so draw() wouldn't have to contain a massive loop? I've been unsuccessful in trying to find a way to feed the coordinates to the GPU in a separate one-time process or make all the data one big object.
You could draw the to a PGraphics ahead of time, and then just draw that PGraphics when you want to draw your bodies.
PGraphics image;
void setup() {
size(500, 500);
image = createGraphics(500, 500);
image.beginDraw();
for (int i = 0; i < visibleBodies.length; i++) {
Body b = visibleBodies[i];
image.point(b.x, -b.z, -b.y); // Z-up world
}
image.endDraw();
}
void draw() {
background(255, 0, 0);
image(image, 0, 0, width, height);
}
More info can be found in the Processing reference.

Achieve parallax effect in libGDX game

I'm working in a game with some friends in which we have a large horizontal world and a OrthographicCamera that shows only 1/3 of it. This camera it's moved when the horizontal position of the player change so the camera only move to the left and to the right.
Some of the objects showed in the game are near the player point-of-view but others are far away (for example, islands). With this in consideration, we cannot set fixed positions for elements and move only the camera. We need to achieve a parallax effect taking in consideration the distance of the elements.
Here is a simple image to explain it better:
The viewport to the left shows 3 objects of the game. The green one is near the player, the red ellipse is far and the yellow one is in the middle. In the viewport to the right the camera has been moved to the right so all the objects disappear to the left. The thing is that the relative movement of the green rectangle is greater than the movement of the yellow. In the same way, movement of yellow object is greater than red object movement.
I created all my assets scaled taking in consideration how far they are but now, how can I simulate this perspective using libGDX? Is there any class to do it? If I have to set elements position in each iteration, how could I calculate the right position?
Note that the example below is not tested as I am just recalling how I did it. The idea is simple - create layers with an extra layer for each with initial positions and velocity and move them. If a layer goes off the edge, put another one (that is why we create an extra layer) at the opposite edge.
Say you have a parallax object that takes initial positions, size, and velocity-
public class Parallax extends DynamicGameObject {
public float width, height; // Use setter/getter if you prefer
public Parallax(float x, float y, float width, float height, float velocityX, float velocityY) {
super(x, y, width, height);
velocity.set(velocityX, velocityY);
this.width = width;
this.height = height;
}
public void update(float deltaTime) {
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
}
public void setPosition(float x, float y) {
position.set(x, y);
}
}
DynamicGameObject is taken from SuperJumper demo-
public class DynamicGameObject extends GameObject {
public final Vector2 velocity;
public final Vector2 accel;
public DynamicGameObject(float x, float y, float width, float height) {
super(x, y, width, height);
velocity = new Vector2();
accel = new Vector2();
}
}
GameObject as well-
public class GameObject {
public final Vector2 position;
public final Rectangle bounds;
public GameObject(float x, float y, float width, float height) {
this.position = new Vector2(x,y);
this.bounds = new Rectangle(x - width/2f, y - height/2f, width, height);
}
}
Say we have two layers - one in front and the other goes at back. We have one texture for each. Each texture fills the entire screen. We create two instances for each layer so that when one texture starts going off the screen, the other shows up at the edge to fill the gap. If you have smaller textures, you need to determine first how many textures you need to fill the screen and then create layers with one extra to fill the gap in between.
We can create an array of parallax layers during world creation-
Array<Parallax> parallaxList = new Array<Parallax>(4);
We can create the layers like this-
// Back
/* First parallax for back layer is at 0 x-axis. If you want to move the texture from right to left, the value of BACK_VELOCITY_X should be negative. You can experiment with velocity value for desire pace of movement. We do not want our layer to move on y-axis. Hence, it is set to 0. */
parallaxList.add(new Parallax(0, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_VELOCITY_X, 0));
/* This one is also for back layer but it is positioned at the right edge of the layer above*/
parallaxList.add(new Parallax(BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, BACK_TEXTURE_WIDTH, BACK_TEXTURE_HEIGHT, SOME_VELOCITY_X, 0));
// Front
parallaxList.add(new Parallax(0, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));
parallaxList.add(new Parallax(FRONT_TEXTURE_WIDTH, 0, FRONT_TEXTURE_WIDTH, FRONT_TEXTURE_HEIGHT, FRONT_VELOCITY_X, 0));
We update the layers on an update call in each frame-
// In our example, TOTAL_LAYERS is 4
for (int i = 0; i < TOTAL_LAYERS; i++) {
int tmpInt;
Parallax parallax = parallaxList.get(i);
parallax.update(deltaTime);
// If one layer is off the edge, put it at the right of the next one
// In this example, layers are moving from right to left
if (parallax.position.x <= -parallax.width) {
// We know that parallaxList's indexes 0 and 1 hold the back layers
// and indexes 2 and 3 have the front layers. You can add additional
// parameters in Parallax class to indicate a group so that you do not
// have to determine the group in dirty way like this
if(i == 0){
tmpInt = 1;
} else if(i == 1) {
tmpInt = 0;
} else if(i == 2) {
tmpInt = 3;
} else {
tmpInt = 2;
}
parallax.setPosition(parallaxList.get(tmpInt).position.x + parallax.width, parallax.position.y);
}
}
You can use an OrthographicCamera and a SpriteBatch to draw the parallax layers. You can actually use the game camera you have but I think using a separate camera is much cleaner. Anyways, parallax textures are usually big enough to be batched in a separate call so using the game camera most probably will not save you a draw call.

Tetris: Turning the pieces?

So I am making a tetris game and one of the problems I am running into is piece rotation. I know I can just hard code it but thats not the right way to do it. The way the system works is I have a 2d array of an object 'Tile' the 'Tile' object has x, y coords, boolean isActive, and color. The boolean isActive basically tells the computer which tiles are actually being used (Since tetris shapes are not perfect quadrilaterals).
Here is how I would make a shape in my system:
public static Tile[][] shapeJ() {
Tile[][] tile = new Tile[3][2];
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 2; y++) {
tile[x][y] = new Tile(false, Color.blue);
}
}
tile[0][0].setActive(true);
tile[0][0].setX(0);
tile[0][0].setY(0);
tile[1][0].setActive(true);
tile[1][0].setX(50);
tile[1][0].setY(0);
tile[2][0].setActive(true);
tile[2][0].setX(100);
tile[2][0].setY(0);
tile[2][1].setActive(true);
tile[2][1].setX(100);
tile[2][1].setY(50);
return tile;
}
Now I need to rotate this object, I do not know how to do that without hard coding the positions. There has to be an algorithm for it. Can anyone offer some help?
A good way that I used when writing a tetris clone is to use rotational matrices:
http://en.wikipedia.org/wiki/Rotation_matrix
So the coordinates (x',y') of the point (x,y) after rotation are:
x' = x*cos(theta) - y*sin(theta);
y' = x*sin(theta) + y*cos(theta);
Where theta is the angle of rotation(+-90 degrees or +-PI/2 radians for the java functions that I know)
In this case the blocks are rotated around the origin (0, 0) so you either have to have the coordinates of the block in special "block space" that then gets transposed onto "field space" or you take away the offset of the block so that it is centered at the origin every iteration.
I hope that helps, I am happy to answer specific questions in the comments.

Generating Box2D body(collision map) from tilemap efficiently

I am working on a platformer game that will use tile maps, which I don't know if is a good idea!
I've made a neat tile map editor with tools for setting a spawn point etc. but now that I want to be able to test play the game after editing map and for future use I need of course integrate physics which I've done with Box2D which comes with LibGDX!
I am creating a method to create a collision map from tile map which has data if tile is collideable or not!
So I came up with this great idea:
loop through the map and if we find a colliding tile loop through its neighbor tiles and see if they're colliding too, and do this til noncolliding tile is found when we set width and height for the colliding rectangle
after we got bunch of rectangle I sort them in order from biggest square to smallest so we get biggest pieces and I add the rectangles to final list and check against the final rect if any of them overlaps with current body so I don't have overlapping bodys
But you know, code tells more than 1000 words, right?
public void createBody() {
List<Rectangle> allRects = new ArrayList<Rectangle>();
for(int x = 0; x < info.getWidth(); x++) {
for(int y = 0; y < info.getHeight(); y++) {
if(tiles[x][y].getInfo().isColliding()) {
int width = 1;
int height = 1;
//loop through neighbors horizontally
for(int i = 0; i < info.getWidth() - x; i++) {
if(!tiles[x + i][y].getInfo().isColliding()) {
//if tile is not clipped, we set width to i which is current x offset
width = i;
break;
}
}
//only if width is bigger than zero can the rect have any tiels..
if(width > 0) {
boolean breakingBad = false;
//loop through neighbors horizontally
for(int j = 0; j < info.getHeight() - y; j++) {
//loop though neigbors vertizally
for(int i = 0; i < width; i++) {
//check if tile is not colliding
if(!tiles[x + i][y + j].getInfo().isColliding()) {
//and if so, we set height to j which is current y offset
height = j;
//breaking bad aka leaving both loops
breakingBad = true;
break;
}
}
if(breakingBad) {
break;
}
}
}
if(width * height > 0)
allRects.add(new Rectangle(x, y, width, height));
}
}
}
Collections.sort(allRects, new Comparator<Rectangle>() {
#Override
public int compare(Rectangle o1, Rectangle o2) {
Integer o1Square = o1.width * o1.height;
Integer o2Square = o2.width * o2.height;
return o2Square.compareTo(o1Square);
}
});
List<Rectangle> finalRects = new ArrayList<Rectangle>();
mainloop:
for(Rectangle rect: allRects) {
for(Rectangle finalRect: finalRects) {
if(finalRect.contains(rect)) {
continue mainloop;
}
}
finalRects.add(rect);
}
for(Rectangle rect: finalRects) {
PolygonShape polyShape = new PolygonShape();
polyShape.setAsBox((float)rect.getWidth() / 2, (float)rect.getHeight() / 2, Vector2.tmp.set((float)rect.getCenterX(), (float)rect.getCenterY()), 0f);
mapBody.createFixture(polyShape, 1);
polyShape.dispose();
}
}
however this sill seems pretty inefficient because for some reasons its still creating smaller fixtures than it could be possible, for example in upper right corner
also its creating single fixtures in the corners of the center rectangle and I can't figure out why!
Is the whole idea all inefficient, and should I use other method or manually create collision maps or what could be the best idea?
Originally each tile was its own fixture which caused weird bugs on their edges as expected
First off, a custom tile mapping tool is a great idea on the surface, but you're reinventing the wheel.
libGDX has built-in support for TMX maps.
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/maps/tiled/TmxMapLoader.html
Instead of using your homebrew editor, you can use a full featured editor such as this Tiled - http://www.mapeditor.org/
So once you have a better system in place for your maps, I would look at this from an object oriented perspective. Since you want to use box2d physics, each collidableTile HAS A body. So all you need to do is assign a physics body to each collidableTile, and set the size according to your standard tile size.
Don't forget that there is a difference between the box2d world and your game screen, where box2d is measured in metric units, and your screen is measured in pixels. So you need to do some math to set positions and size properly. If you want a set of tiles to share a body, you may want to pass in the body as a parameter when you construct each collidableTile, and then adjust the size of the body based on how many adjacent tiles you can find. More complex shapes for the physics body may be more complex.
You can also save resources by setting those tiles to 'sleep', where box2d does a reduced simulation on those bodies until it detects a collision. If you're only using box2d for collision detection on terrain, you may want to consider other options, like using shape libraries to detect intersections, and then setting the box2d physics on your player characters body to stop downward acceleration while there is contact, or something.

SWT - Drawing a Moving Image Over Tiles

I've been experimenting with different ways of moving a image over a grid of tiles for a game, but I've been unable to get a working implementation.
First I tried using a grid layout to hold a bunch of Tiles that extended Canvas and drew themselves. This drew the tiles nicely, however it seems that I am unable to draw my Player object on top of them. Originally, the Player also extended Canvas and I intended to have the widget on top of the tiles. It seems like this is impossible.
I then tried to have the Tile simply extend nothing, and just hold the image. I then hold each Tile in a 2D array and draw each Tile by a nested for loop, using the int from the for loop, multiplied by the image size, to draw Tile's Image. I put this code in a PaintListener inside of my constructor for my Map class that extended Canvas and dropped my Map onto my Shell in a Fill layout, but the PaintListener never gets called (I tested with a print statement).
What implementation could I use to draw the Tiles at the start of the game, then allow me to control the movement of my Player image?
I did something similar.
Using a PaintListener I get the calls when the Widget needs to be repainted. In my paint function, I loop over a tile array (wrapped in a World class) and draw all tiles. Afterwards I use the same technique with a worldObjects array/class:
public class WorldWidget extends Canvas {
WorldWidget() {
addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
WorldWidget.this.paintControl(e);
}
});
}
protected void paintControl(PaintEvent e) {
GC gc = e.gc;
for (short y = 0; y < world.getHeight(); y++) {
for (short x = 0; x < world.getWidth(); x++) {
final ITile tile = world.getTile(x, y);
final Image image = ImageCache.getImage(tile);
gc.drawImage(image, x * tileSize, y * tileSize);
}
}
// Here is used a similar loop, to draw world objects
}
}
This is obviously a condensed code example, as the class is part of an editor and reacts on mouse clicks and movement amongst other things.
When I did a tile based simulation while ago I did it this way:
I had 2 layers of the tile map - one for the terrain and second for the units.
The map itself was represented by a JPanel.
So roughly you got this for the JPanel:
public void paintComponent(Graphics graphics) {
// create an offscreen buffer to render the map
if (buffer == null) {
buffer = new BufferedImage(SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT, BufferedImage.TYPE_INT_ARGB);
}
Graphics g = buffer.getGraphics();
g.clearRect(0, 0, SimulationMap.MAP_WIDTH, SimulationMap.MAP_HEIGHT);
// cycle through the tiles in the map drawing the appropriate
// image for the terrain and units where appropriate
for (int x = 0; x < map.getWidthInTiles(); x++) {
for (int y = 0; y < map.getHeightInTiles(); y++) {
if (map.getTerrain(x, y) != null) {
g.drawImage(tiles[map.getTerrain(x, y).getType()], x * map.getTILE_WIDTH(), y * map.getTILE_HEIGHT(), null);
}
}
}
if (map.getSimulationUnits() != null) {
for (Unit unit : map.getSimulationUnits()) {
g.drawImage(tiles[unit.getUnitType()], (int) Math.round(unit.getActualXCor() * map.getTILE_WIDTH()), (int) Math.round(unit.getActualYCor() * map.getTILE_HEIGHT()),
null);
}
}
// ...
// draw the buffer
graphics.drawImage(buffer, 0, 0, null);
}
Logic:
private Terrain[][] terrain = new Terrain[WIDTH][HEIGHT];
/** The unit in each tile of the map */
private Unit[][] units = new Unit[WIDTH][HEIGHT];
Then you have your game loop where you update the position of the units and other things, basically render() and update() the game. Check the links I've provided below.
NOTE
Since you are making a simple game this post about making game loops will be definitely useful for you. This hopefully also answer your question about moving the object on the map.
This site will be also very helpful since you will probably need to detect collision at some point too.

Categories

Resources