I am trying to implement frustum culling in my 3D Game currently and it has worked efficiently with the entities because they have a bounding box (AABB) and its easier to check a box against the frustum. On saying that, how would I cull the terrain? (it physically cannot have a AABB or sphere)
The frustum class (I use the inbuilt JOML one):
import org.joml.FrustumIntersection;
import org.joml.Matrix4f;
import engine.Terrians.Terrain;
import engine.maths.Matrices;
import engine.maths.Vector3f;
import engine.objects.Camera;
import engine.physics.AABB;
public class FrustumG {
private final Matrix4f projectionViewMatrix;
private FrustumIntersection frustumInt;
public FrustumG() {
projectionViewMatrix = new Matrix4f().identity();
frustumInt = new FrustumIntersection();
}
public void update(Matrix4f projectionMatrix, Matrix4f viewMatrix) {
projectionViewMatrix.set(projectionMatrix);
projectionViewMatrix.mul(viewMatrix);
frustumInt.set(projectionViewMatrix);
}
public boolean intersectsAABB(AABB aabb) {
return frustumInt.testAab(aabb.getWorldMinX(), aabb.getWorldMinY(), aabb.getWorldMinZ(),
aabb.getWorldMaxX(), aabb.getWorldMaxY(), aabb.getWorldMaxZ());
}
public boolean intersectsPoint(Vector3f point) {
return frustumInt.testPoint(point.getX(), point.getY(), point.getZ());
}
}
My Mesh Class stores vertices information for the Terrain. I do not want to edit and update the vertices VBO every frame, as I have googled that it can affect the performance of the game (and I would also have to edit the indices list, and loop through the two lists every frame). I saw some websites saying to use GL_DYNAMIC_DRAW
instead of GL_STATIC_DRAW
, but I did not understand it.
Here is the Mesh Class:
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
public class Mesh {
private float[] verticesData;
private int[] indicesData;
private float[] textureData;
private float[] normalsData;
private int vao, pbo, ibo, cbo, tbo, nbo;
private Texture texture;
public Mesh(float[] verticesArray, int[] indices, float[] normalsArray, float[] texturesArray) {
this.verticesData = verticesArray;
this.indicesData = indices;
this.textureData = texturesArray;
this.normalsData = normalsArray;
}
public Mesh(float[] positions, int dimensions) {
this.verticesData = positions;
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
FloatBuffer positionBuffer = MemoryUtil.memAllocFloat(positions.length);
positionBuffer.put(positions).flip();
pbo = storeData(positionBuffer, 0, dimensions);
}
public void createTextures(String filepath) {
Texture texture = new Texture(filepath);
texture.create();
this.texture = texture;
}
public int loadCubeMap(String[] textureFiles, String textureMainSystemPath) {
int texID = GL11.glGenTextures();
GL30.glActiveTexture(GL30.GL_TEXTURE0);
GL30.glBindTexture(GL30.GL_TEXTURE_CUBE_MAP, texID);
for(int i = 0; i < textureFiles.length; i++) {
Texture.createSkybox(textureMainSystemPath + textureFiles[i] + ".png", i);
}
GL30.glTexParameteri(GL30.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MAG_FILTER, GL30.GL_LINEAR);
GL30.glTexParameteri(GL30.GL_TEXTURE_CUBE_MAP, GL30.GL_TEXTURE_MIN_FILTER, GL30.GL_LINEAR);
return texID;
}
public void createMeshes() {
vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
FloatBuffer positionBuffer = MemoryUtil.memAllocFloat(verticesData.length);
positionBuffer.put(verticesData).flip();
pbo = storeData(positionBuffer, 0, 3);
/**FloatBuffer colorBuffer = MemoryUtil.memAllocFloat(vertices.length * 3);
float[] colorData = new float[vertices.length * 3];
for (int i = 0; i < vertices.length; i++) {
colorData[i * 3] = vertices[i].getColor().getX();
colorData[i * 3 + 1] = vertices[i].getColor().getY();
colorData[i * 3 + 2] = vertices[i].getColor().getZ();
}
colorBuffer.put(colorData).flip();
cbo = storeData(colorBuffer, 1, 3);**/
FloatBuffer textureBuffer = MemoryUtil.memAllocFloat(verticesData.length);
textureBuffer.put(textureData).flip();
tbo = storeData(textureBuffer, 1, 2);
FloatBuffer normalBuffer = MemoryUtil.memAllocFloat(verticesData.length);
normalBuffer.put(normalsData).flip();
nbo = storeData(normalBuffer, 2, 3);
IntBuffer indicesBuffer = MemoryUtil.memAllocInt(indicesData.length);
indicesBuffer.put(indicesData).flip();
ibo = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL15.GL_STATIC_DRAW);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
}
private int storeData(FloatBuffer buffer, int index, int size) {
int bufferID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(index, size, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
return bufferID;
}
public void destroyBuffers() {
GL15.glDeleteBuffers(pbo);
GL15.glDeleteBuffers(cbo);
GL15.glDeleteBuffers(ibo);
GL15.glDeleteBuffers(tbo);
GL15.glDeleteBuffers(nbo);
GL30.glDeleteVertexArrays(vao);
}
public float[] getVertices() {
return verticesData;
}
public float[] getPositions2D() {
return verticesData;
}
public int[] getIndices() {
return indicesData;
}
public int getVAO() {
return vao;
}
public int getPBO() {
return pbo;
}
public int getCBO() {
return cbo;
}
public int getIBO() {
return ibo;
}
public int getTBO() {
return tbo;
}
public int getNBO() {
return nbo;
}
public Texture getTexture() {
return texture;
}
}
Is there a more efficient way to frustum cull the vertices / triangles of the terrain?