Reputation: 59
I' trying to implement a renderer which uses only one VBO and one EBO to store all object vertices and indices. For that, I found some tutorials and finally came up with a rather good result.
The problem is that it only works properly with ONE single object. As soon as I want to add another one, the rendering shows weird behaviour.
Can you help me with this?
You can find the full code here: https://github.com/BanditBloodwyn/TerritorySimulator. The important classes are:
This is the initializing method in the Renderer:
public void Initialize(GLShape[] shapeArray)
{
Shapes = shapeArray;
GL.Enable(EnableCap.DepthTest);
GL.ClearColor(0.0f, 0.0f, 0.10f, 1.0f);
InitializeBuffers(Shapes);
InitializeVertexArrayObject(Shapes);
SetupShader();
BindBuffers();
}
The submethods look like this.
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, shape.Indices);
offset += shape.IndexBufferSize;
}
}
private void InitializeVertexArrayObject(GLShape[] shapeArray)
{
foreach (GLShape shape in shapeArray)
{
shape.VertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(shape.VertexArrayObject);
}
}
private void SetupShader()
{
// shader
string vertexPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, @"GLSL\", "Fragment.frag");
shader = new Shader(vertexPath, fragmentPath);
shader.Use();
int vertexLocation = shader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
0);
int texCoordLocation = shader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
3 * sizeof(float));
shader.SetInt("texture0", 0);
shader.SetInt("texture1", 1);
}
private void BindBuffers()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
}
The render function itself looks like this.
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
foreach (var texture in shape.Textures)
{
if (LayerConfiguration.ShowEarthTexture)
texture.Key.Use(texture.Value);
else
texture.Key.MakeTransparent(texture.Value);
}
ApplyModelTransforms(shape, out Matrix4 model);
shader.SetMatrix4("model", model);
shader.SetMatrix4("view", Camera.GetViewMatrix());
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset += shape.IndexBufferSize;
}
shader.SetMatrix4("projection", Camera.GetProjectionMatrix());
shader.Use();
}
Upvotes: 1
Views: 972
Reputation: 210918
As soon as I want to add another one, the rendering shows weird behavior
Of course, because the indices for the 2nd and following objects are wrong. You need to add the sum of the vertices of the previous meshes to the indexes. To the indices of the first mesh you have to add 0, to the indices of the 2nd mesh you have to add the number of vertices of the 1st mesh, to the indices of the 3rd mesh you have to add the sum of the vertices of the 1st and 2nd mesh, ...
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(
BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
Complete method InitializeBuffers
:
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
}
Upvotes: 1