LWJGL Forum

Programming => OpenGL => Topic started by: konny86 on December 28, 2016, 15:16:53

Title: Problem with rendering of points in 3D
Post by: konny86 on December 28, 2016, 15:16:53
Hello guys,
I am currently trying to implement the screen space rendering of SPH. However, while SPH by itself is already implemented and working, the rendering of particles as points seems not to work correctly. I have a list of particles with several attributes, amongst others the position.
Now first, I try to load these points into a VAO with the following method:


public int loadPointsToVAO(float[] positions) {
int vaoID = createVAO();
storeDataInAttributeList(0, positions, 3);
unbindVAO();
return vaoID;
}
private void storeDataInAttributeList(int attribute, float[] data, int coordinateSize) {
int vboID = GL15.glGenBuffers();//create a new buffer
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);//bind the buffer so it can not be manipulated during this method
FloatBuffer buffer = storeDataInFloatBuffer(data);//convert the handed over data to a float buffer as req. by GL
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);//put the data in buffer
GL20.glVertexAttribPointer(attribute, coordinateSize, GL11.GL_FLOAT, false, 0, 0);//now add a pointer
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);//finally unbind the buffer so it can be used
}


After a new VAO with the corresponding data has been created, I try to render it with the following code:


/**
* Renders a set of entities to the screen.
*/
public void render(List<Particle> particleList) {
vaoID = MainLoop.loader.loadPointsToVAO(gatherPointsFromList(particleList));
prepare();//bind everything
for (Particle entity : particleList) {//now finally render everything
prepareInstance(entity);
GL11.glPointSize(10f);
if (triangles) {
GL11.glDrawElements(GL11.GL_TRIANGLES, 1, GL11.GL_UNSIGNED_INT, 0);
} else {
GL11.glDrawElements(GL11.GL_POINTS, 1, GL11.GL_UNSIGNED_INT, 0);
}
}
//unbind textures to free it for other renderer
unbind();

}


private void prepare() {
GL30.glBindVertexArray(vaoID);//bind the vertex array object id so nothing else is rendered or changed
GL20.glEnableVertexAttribArray(0);//bind the arrays so nothing else changes them
}

/**
* Unbinds the texture so they can be used for other entities. This method has to be used each time
* a entity has been rendered.
*/
private void unbind() {
MasterRenderer.enableCulling();
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}


However, no points are rendered at all. I have a working renderer (crated from a online tutorial) which renders models representing each particle, however, for screen space rendering, it is required to render each particle as a point (according to my understanding). The positions of the points are changes in each iteration of the main loop, therefore this method is called several times with different positions.


I would really appreciate it if someone could help me and point out the mistake.

Here is the remaining code used to render everthing:


package Engine;

import Entities.Camera;
import Entities.Entity;
import Entities.Light;
import Entities.Particle;
import MainLogic.MainLoop;
import Models.TexturedModel;
import Shaders.FluidShader;
import Shaders.StaticShader;
import Shaders.TerrainShader;
import Terrain.Terrain;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* This is the master renderer, i.e. the class which deals with rendering of all objects and terrains.
*
*
*/
public class MasterRenderer {

//parameter for the projection matrix, i.e. the "view" on the world.
private static final float FOV = 70;
public static final float NEAR_PLANE = 0.1f;
public static final float FAR_PLANE = 1000f;

private Matrix4f projectionMatrix;

//create shader and renderer
private StaticShader shader = new StaticShader();
private EntityRenderer entityRenderer;

private TerrainRenderer terrainRenderer;
private TerrainShader terrainShader = new TerrainShader();

private FluidShader fluidShader = new FluidShader();
private FluidRenderer fluidRenderer;



//everything that shall be rendered
private Map<TexturedModel, List<Entity>> entities = new HashMap<>();
private List<Terrain> terrains = new ArrayList<>();
private Particle marchingCube;
private List<Particle> particles = new ArrayList<>();


public MasterRenderer() {
enableCulling();
createProjectionMatrix();
this.entityRenderer = new EntityRenderer(shader, projectionMatrix);
this.terrainRenderer = new TerrainRenderer(terrainShader, projectionMatrix);
this.fluidRenderer = new FluidRenderer(fluidShader,projectionMatrix);
}

/**
* Enable culling, i.e. the not rendering of back sites.
*/
public static void enableCulling() {
GL11.glEnable(GL11.GL_CULL_FACE);//stop gl from rendering faces not visible to the camera
GL11.glCullFace(GL11.GL_BACK);
}

/**
* Disable culling, i.e. the not rendering of back sites.
*/
public static void disableCulling() {
GL11.glDisable(GL11.GL_CULL_FACE);
}

/**
* A shortcut to clean everything up.
*/
public void cleanUp() {
shader.cleanUp();
terrainShader.cleanUp();
}

/**
* Renders the current simulation in the world according to the view of the camera object.
*
* @param camera the camera looking into the world.
*/
public void render(Camera camera, Light light) {
prepare();
if(!MainLoop.fluidRendering&&!entities.isEmpty()) {
shader.start();//start the shader program
shader.loadLight(light);
shader.loadViewMatrix(camera);//load matrices
entityRenderer.render(entities);//render all objects
if (MainLoop.marchingCube && marchingCube != null) {
entityRenderer.render(marchingCube.getModel(), marchingCube);
}
}
//start rendering the fluid
if(MainLoop.fluidRendering&&!particles.isEmpty()){
fluidShader.start();
fluidShader.loadViewMatrix(camera);
fluidRenderer.render(particles);
particles.clear();
}
terrainShader.start();//now start the terrain shader program
terrainShader.loadViewMatrix(camera);//now load the view matrix once more to render the terrain
terrainRenderer.render(terrains);//render it

terrains.clear();
entities.clear();//now everything has been rendered, clear the buffer
}

/**
* Ads a terrain which shall be rendered.
*
* @param terrain a terrain object which shall be rendered
*/
public void processTerrain(Terrain terrain) {
terrains.add(terrain);
}

public void processEntities(Entity entity) {
TexturedModel entityModel = entity.getModel();
List<Entity> batch = entities.get(entityModel);
if (batch != null) {
batch.add(entity);
} else {
List<Entity> newBatch = new ArrayList<>();
newBatch.add(entity);
entities.put(entityModel, newBatch);
}
}

public void processParticleAsPoint(Particle particle){
this.particles.add(particle);
}

public void processTriangles(Particle particle){
this.marchingCube = particle;
}

/**
* Prepares the rendering engine.
*/
public void prepare() {
GL11.glEnable(GL11.GL_DEPTH_TEST);//faces pointing to the user shall be in front
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);//clear the screen
GL11.glClearColor(0, 0, 0, 1);//TODO: das hier ist die hintergrundfrabe
}

/**
* Creates a projection matrix, i.e. a matrix which transforms the world view to a screen view. For more
* information: http://www.songho.ca/opengl/gl_projectionmatrix.html
*/
private void createProjectionMatrix() {
float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = FAR_PLANE - NEAR_PLANE;

projectionMatrix = new Matrix4f();
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * NEAR_PLANE * FAR_PLANE) / frustum_length);
projectionMatrix.m33 = 0;
}

public Matrix4f getProjectionMatrix() {
return projectionMatrix;
}

public StaticShader getShader() {
return shader;
}
}



package Engine;

import Entities.Entity;
import Entities.Particle;
import MainLogic.MainLoop;
import Models.RawModel;
import Models.TexturedModel;
import Shaders.FluidShader;
import Shaders.StaticShader;
import Textures.ModelTexture;
import Toolbox.Maths;
import org.lwjgl.opengl.*;
import org.lwjgl.util.vector.Matrix4f;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.List;
import java.util.Map;


public class FluidRenderer {

private FluidShader shader;
public static boolean triangles = true;

private int vaoID;
private int vboID;

/**
* Renders a set of entities to the screen.
*/
public void render(List<Particle> particleList) {
vaoID = MainLoop.loader.loadPointsToVAO(gatherPointsFromList(particleList));
prepare();//bind everything
for (Particle entity : particleList) {//now finally render everything
prepareInstance(entity);
GL11.glPointSize(10f);
if (triangles) {
GL11.glDrawElements(GL11.GL_TRIANGLES, 1, GL11.GL_UNSIGNED_INT, 0);
} else {
GL11.glDrawElements(GL11.GL_POINTS, 1, GL11.GL_UNSIGNED_INT, 0);
}
}
//unbind textures to free it for other renderer
unbind();

}


private void prepare() {
GL30.glBindVertexArray(vaoID);//bind the vertex array object id so nothing else is rendered or changed
GL20.glEnableVertexAttribArray(0);//bind the arrays so nothing else changes them
}

/**
* Unbinds the texture so they can be used for other entities. This method has to be used each time
* a entity has been rendered.
*/
private void unbind() {
MasterRenderer.enableCulling();
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}

public FluidRenderer(FluidShader shader, Matrix4f projectionMatrix) {
this.shader = shader;
shader.start();
shader.loadProjectionMatrix(projectionMatrix);
shader.stop();
}

private float[] gatherPointsFromList(List<Particle> particleList){
float[] ret = new float[particleList.size()*3];
int counter = 0;
for(Particle part:particleList){
ret[counter++] = part.getPosition().x;
ret[counter++] = part.getPosition().y;
ret[counter++] = part.getPosition().z;
}
return ret;
}

}





package Shaders;

import Entities.Camera;
import Entities.Light;
import Toolbox.Maths;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;


public class FluidShader extends ShaderProgram{

//provide the paths to the shader programs
private static final String VERTEX_FILE = "src/Shaders/fluidVertexShader.glsl";
private static final String FRAGMENT_FILE = "src/Shaders/fluidFragmentShader.glsl";
//the matrices
private int location_transformationMatrix;
private int location_projectionMatrix;
private int location_viewMatrix;
private int location_lightPosition;
private int location_lightColor;

public FluidShader() {
super(VERTEX_FILE, FRAGMENT_FILE);
}

/**
* Used to find out the location (in memory) of the attributes in the shader program.
*/
@Override
protected void getAllUniformLocations() {
location_transformationMatrix = super.getUniformLocation("transformationMatrix");
location_projectionMatrix = super.getUniformLocation("projectionMatrix");
location_viewMatrix = super.getUniformLocation("viewMatrix");
location_lightColor = super.getUniformLocation("lightColor");
location_lightPosition = super.getUniformLocation("lightPosition");
}

/**
* Loads the transformation matrix to the shader program.
*
* @param matrix the matrix which will be loaded to the transformationMatrix location.
*/
public void loadTransformationMatrix(Matrix4f matrix) {
super.loadMatrix(location_transformationMatrix, matrix);
}

/**
* Loads the projection matrix to the shader program.
*
* @param matrix the matrix which will be loaded to the projectionMatrix location.
*/
public void loadProjectionMatrix(Matrix4f matrix) {
super.loadMatrix(location_projectionMatrix, matrix);
}

/**
* Loads the transformation matrix to the shader program.
*
* @param camera the camera whose position will be used in the view matrix.
*/
public void loadViewMatrix(Camera camera) {
Matrix4f viewMatrix = Maths.createViewMatrix(camera);
super.loadMatrix(location_viewMatrix, viewMatrix);
}

/**
* Binds the attributes to the names.
*/
@Override
protected void bindAttributes() {
super.bindAttribute(0, "position");
}

public void loadLight(Light light){
super.loadVector(location_lightPosition,light.getPosition());
super.loadVector(location_lightColor,light.getColor());
}
}


//fluid shader vertex
#version 330 core

in vec3 position;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;


void main(void){
vec4 worldPosition = transformationMatrix * vec4(position,1.0);
gl_Position = projectionMatrix * viewMatrix * worldPosition;
}



//fluid shader fragment
#version 330 core

out vec4 out_Color;

void main()
{

   out_Color = vec4(1);
}


Title: Re: Problem with rendering of points in 3D
Post by: abcdef on December 28, 2016, 16:15:49
which version of LWJGL are you using? 2 or 3?

Looks like 2, most people are on LWJGL 3 so I would recommend migrating over to this as it will be easier to find people that can help debug (I've forgotten most of how to render in LWJGL2)
Title: Re: Problem with rendering of points in 3D
Post by: konny86 on December 28, 2016, 16:28:44
Hey,
ok, I will try to migrate it to the latest version of LWJGL and then adjust this post.

Edit:
Ok, I guess the problem has been solved: The implentation is almost correct, but instead of drawElements, drawArray hast to be used. Here is a working example:

public void render(List<Particle> particleList) {
vaoID = MainLoop.loader.loadPointsToVAO(gatherPointsFromList(particleList));
GL30.glBindVertexArray(vaoID);//bind the vertex array object id so nothing else is rendered or changed
GL20.glEnableVertexAttribArray(0);
this.prepareInstance();
GL11.glDrawArrays(GL11.GL_POINTS, 0,particleList.size());//<- glDrawArray instead of Elements
GL20.glDisableVertexAttribArray(0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
GL30.glDeleteVertexArrays(vaoID);
}