Fix degenerate tris showing up in certain configs
Occasionally with the right orientation, degenerate triangles will appear as they are no longer zero-area triangles which OGL can cull during rendering. The issue comes from having to manually ensure each primitive in the rendering pipeline sent to the render groups were correctly marked with degenerate vertexes. Instead, we can now just pass the vertex points straight through, using a begin() and end() structure which will append the start and ending degenerate vertexes for us.
This commit is contained in:
parent
064d17d34c
commit
17dc6cc6fc
@ -53,6 +53,7 @@ void initRenderer(GameState *state, v2 windowSize) {
|
|||||||
// NOTE(doyle): Value to map a screen coordinate to NDC coordinate
|
// NOTE(doyle): Value to map a screen coordinate to NDC coordinate
|
||||||
renderer->vertexNdcFactor =
|
renderer->vertexNdcFactor =
|
||||||
V2(1.0f / renderer->size.w, 1.0f / renderer->size.h);
|
V2(1.0f / renderer->size.w, 1.0f / renderer->size.h);
|
||||||
|
renderer->groupIndexForVertexBatch = -1;
|
||||||
|
|
||||||
const mat4 projection =
|
const mat4 projection =
|
||||||
mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f);
|
mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f);
|
||||||
@ -568,6 +569,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
V4(1.0f, 0, 0, 1.0f), flags);
|
V4(1.0f, 0, 0, 1.0f), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
TrianglePoints triangle = {0};
|
TrianglePoints triangle = {0};
|
||||||
triangle.points[0] = V2(100, 200);
|
triangle.points[0] = V2(100, 200);
|
||||||
triangle.points[1] = V2(200, 100);
|
triangle.points[1] = V2(200, 100);
|
||||||
@ -582,6 +584,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
|
|
||||||
debug_drawUi(state, dt);
|
debug_drawUi(state, dt);
|
||||||
debug_clearCounter();
|
debug_clearCounter();
|
||||||
|
#endif
|
||||||
|
|
||||||
renderer_renderGroups(&state->renderer);
|
renderer_renderGroups(&state->renderer);
|
||||||
}
|
}
|
||||||
|
175
src/Renderer.c
175
src/Renderer.c
@ -18,15 +18,68 @@ typedef struct RenderTriangle
|
|||||||
Vertex vertex[3];
|
Vertex vertex[3];
|
||||||
} RenderTriangle_;
|
} RenderTriangle_;
|
||||||
|
|
||||||
INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *tex, v4 color,
|
// NOTE(doyle): A vertex batch is the batch of vertexes comprised to make one
|
||||||
Vertex *vertexList, i32 numVertexes,
|
// shape
|
||||||
enum RenderMode targetRenderMode,
|
INTERNAL void beginVertexBatch(Renderer *renderer)
|
||||||
RenderFlags flags)
|
|
||||||
{
|
{
|
||||||
|
ASSERT(renderer->vertexBatchState == vertexbatchstate_off);
|
||||||
|
ASSERT(renderer->groupIndexForVertexBatch == -1);
|
||||||
|
renderer->vertexBatchState = vertexbatchstate_initial_add;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DENGINE_DEBUG
|
/*
|
||||||
|
NOTE(doyle): Entity rendering is always done in two pairs of
|
||||||
|
triangles, i.e. quad. To batch render quads as a triangle strip, we
|
||||||
|
need to create zero-area triangles which OGL will omit from
|
||||||
|
rendering. Render groups are initialised with 1 degenerate vertex and
|
||||||
|
then the first two vertexes sent to the render group are the same to
|
||||||
|
form 1 zero-area triangle strip.
|
||||||
|
|
||||||
|
A degenerate vertex has to be copied from the last vertex in the
|
||||||
|
rendering quad, to repeat this process as more entities are
|
||||||
|
renderered.
|
||||||
|
|
||||||
|
Alternative implementation is recognising if the rendered
|
||||||
|
entity is the first in its render group, then we don't need to init
|
||||||
|
a degenerate vertex, and only at the end of its vertex list. But on
|
||||||
|
subsequent renders, we need a degenerate vertex at the front to
|
||||||
|
create the zero-area triangle strip.
|
||||||
|
|
||||||
|
The first has been chosen for simplicity of code, at the cost of
|
||||||
|
1 degenerate vertex at the start of each render group. The initial degenrate
|
||||||
|
vertexes are added in the add to vertex group and the ending degenerates at
|
||||||
|
on ending a vertex batch.
|
||||||
|
*/
|
||||||
|
INTERNAL void endVertexBatch(Renderer *renderer)
|
||||||
|
{
|
||||||
|
ASSERT(renderer->vertexBatchState != vertexbatchstate_off);
|
||||||
|
ASSERT(renderer->groupIndexForVertexBatch != -1);
|
||||||
|
|
||||||
|
i32 numDegenerateVertexes = 2;
|
||||||
|
RenderGroup *group = &renderer->groups[renderer->groupIndexForVertexBatch];
|
||||||
|
|
||||||
|
i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex;
|
||||||
|
if (numDegenerateVertexes < freeVertexSlots)
|
||||||
|
{
|
||||||
|
Vertex degenerateVertex = group->vertexList[group->vertexIndex-1];
|
||||||
|
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
||||||
|
group->vertexList[group->vertexIndex++] = degenerateVertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->vertexBatchState = vertexbatchstate_off;
|
||||||
|
renderer->groupIndexForVertexBatch = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL void addVertexToRenderGroup_(Renderer *renderer, Texture *tex,
|
||||||
|
v4 color, Vertex *vertexList,
|
||||||
|
i32 numVertexes,
|
||||||
|
enum RenderMode targetRenderMode,
|
||||||
|
RenderFlags flags)
|
||||||
|
{
|
||||||
|
ASSERT(renderer->vertexBatchState != vertexbatchstate_off);
|
||||||
ASSERT(numVertexes > 0);
|
ASSERT(numVertexes > 0);
|
||||||
|
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
for (i32 i = 0; i < numVertexes; i++)
|
for (i32 i = 0; i < numVertexes; i++)
|
||||||
debug_countIncrement(debugcount_numVertex);
|
debug_countIncrement(debugcount_numVertex);
|
||||||
#endif
|
#endif
|
||||||
@ -72,9 +125,6 @@ INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *tex, v4 color,
|
|||||||
/* New group, unused so initialise it */
|
/* New group, unused so initialise it */
|
||||||
groupIsValid = TRUE;
|
groupIsValid = TRUE;
|
||||||
|
|
||||||
// NOTE(doyle): Mark first vertex as degenerate vertex
|
|
||||||
group->vertexList[group->vertexIndex++] = vertexList[0];
|
|
||||||
|
|
||||||
group->init = TRUE;
|
group->init = TRUE;
|
||||||
group->tex = tex;
|
group->tex = tex;
|
||||||
group->color = color;
|
group->color = color;
|
||||||
@ -89,7 +139,15 @@ INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *tex, v4 color,
|
|||||||
if (groupIsValid)
|
if (groupIsValid)
|
||||||
{
|
{
|
||||||
i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex;
|
i32 freeVertexSlots = renderer->groupCapacity - group->vertexIndex;
|
||||||
if (numVertexes < freeVertexSlots)
|
|
||||||
|
// NOTE(doyle): Two at start, two at end
|
||||||
|
i32 numDegenerateVertexes = 0;
|
||||||
|
if (renderer->vertexBatchState == vertexbatchstate_initial_add)
|
||||||
|
{
|
||||||
|
numDegenerateVertexes = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numDegenerateVertexes + numVertexes) < freeVertexSlots)
|
||||||
{
|
{
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
@ -106,6 +164,18 @@ INTERNAL void addVertexToRenderGroup(Renderer *renderer, Texture *tex, v4 color,
|
|||||||
/* Valid group, add to the render group for rendering */
|
/* Valid group, add to the render group for rendering */
|
||||||
if (targetGroup)
|
if (targetGroup)
|
||||||
{
|
{
|
||||||
|
if (renderer->vertexBatchState == vertexbatchstate_initial_add)
|
||||||
|
{
|
||||||
|
targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[0];
|
||||||
|
targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[0];
|
||||||
|
renderer->vertexBatchState = vertexbatchstate_active;
|
||||||
|
|
||||||
|
// NOTE(doyle): We swap groups to the front if it is valid, so
|
||||||
|
// target group should always be 0
|
||||||
|
ASSERT(renderer->groupIndexForVertexBatch == -1);
|
||||||
|
renderer->groupIndexForVertexBatch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (i32 i = 0; i < numVertexes; i++)
|
for (i32 i = 0; i < numVertexes; i++)
|
||||||
{
|
{
|
||||||
targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[i];
|
targetGroup->vertexList[targetGroup->vertexIndex++] = vertexList[i];
|
||||||
@ -346,33 +416,10 @@ void renderer_rect(Renderer *const renderer, Rect camera, v2 pos, v2 size,
|
|||||||
RenderQuad_ quad = createRenderQuad(renderer, posInCameraSpace, size,
|
RenderQuad_ quad = createRenderQuad(renderer, posInCameraSpace, size,
|
||||||
pivotPoint, rotate, *renderTex);
|
pivotPoint, rotate, *renderTex);
|
||||||
|
|
||||||
/*
|
beginVertexBatch(renderer);
|
||||||
NOTE(doyle): Entity rendering is always done in two pairs of
|
addVertexToRenderGroup_(renderer, renderTex->tex, color, quad.vertex,
|
||||||
triangles, i.e. quad. To batch render quads as a triangle strip, we
|
ARRAY_COUNT(quad.vertex), rendermode_quad, flags);
|
||||||
need to create zero-area triangles which OGL will omit from
|
endVertexBatch(renderer);
|
||||||
rendering. Render groups are initialised with 1 degenerate vertex and
|
|
||||||
then the first two vertexes sent to the render group are the same to
|
|
||||||
form 1 zero-area triangle strip.
|
|
||||||
|
|
||||||
A degenerate vertex has to be copied from the last vertex in the
|
|
||||||
rendering quad, to repeat this process as more entities are
|
|
||||||
renderered.
|
|
||||||
|
|
||||||
Alternative implementation is recognising if the rendered
|
|
||||||
entity is the first in its render group, then we don't need to init
|
|
||||||
a degenerate vertex, and only at the end of its vertex list. But on
|
|
||||||
subsequent renders, we need a degenerate vertex at the front to
|
|
||||||
create the zero-area triangle strip.
|
|
||||||
|
|
||||||
The first has been chosen for simplicity of code, at the cost of
|
|
||||||
1 degenerate vertex at the start of each render group.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Vertex vertexList[6] = {quad.vertex[0], quad.vertex[0], quad.vertex[1],
|
|
||||||
quad.vertex[2], quad.vertex[3], quad.vertex[3]};
|
|
||||||
addVertexToRenderGroup(renderer, renderTex->tex, color, vertexList,
|
|
||||||
ARRAY_COUNT(vertexList), rendermode_quad, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_polygon(Renderer *const renderer, Rect camera,
|
void renderer_polygon(Renderer *const renderer, Rect camera,
|
||||||
@ -395,32 +442,23 @@ void renderer_polygon(Renderer *const renderer, Rect camera,
|
|||||||
Vertex triangulationBaseVertex = {0};
|
Vertex triangulationBaseVertex = {0};
|
||||||
triangulationBaseVertex.pos = triangulationBaseP;
|
triangulationBaseVertex.pos = triangulationBaseP;
|
||||||
|
|
||||||
addVertexToRenderGroup(renderer, renderTex->tex, color,
|
|
||||||
&triangulationBaseVertex, 1, rendermode_polygon,
|
beginVertexBatch(renderer);
|
||||||
flags);
|
|
||||||
RenderTriangle_ lastRenderTriForDegeneration = {0};
|
|
||||||
for (i32 i = 1; triangulationIndex < numTrisInTriangulation; i++)
|
for (i32 i = 1; triangulationIndex < numTrisInTriangulation; i++)
|
||||||
{
|
{
|
||||||
|
ASSERT((i + 1) <= numPoints);
|
||||||
|
|
||||||
RenderTriangle_ tri = {0};
|
RenderTriangle_ tri = {0};
|
||||||
tri.vertex[0].pos = triangulationBaseP;
|
tri.vertex[0].pos = triangulationBaseP;
|
||||||
tri.vertex[1].pos = polygonPoints[i + 1];
|
tri.vertex[1].pos = polygonPoints[i + 1];
|
||||||
tri.vertex[2].pos = polygonPoints[i];
|
tri.vertex[2].pos = polygonPoints[i];
|
||||||
|
|
||||||
addVertexToRenderGroup(renderer, renderTex->tex, color, tri.vertex,
|
addVertexToRenderGroup_(renderer, renderTex->tex, color, tri.vertex,
|
||||||
ARRAY_COUNT(tri.vertex), rendermode_polygon,
|
ARRAY_COUNT(tri.vertex), rendermode_polygon,
|
||||||
flags);
|
flags);
|
||||||
|
triangulationIndex++;
|
||||||
if (triangulationIndex++ >= numTrisInTriangulation)
|
|
||||||
{
|
|
||||||
lastRenderTriForDegeneration = tri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i32 i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
addVertexToRenderGroup(renderer, renderTex->tex, color,
|
|
||||||
&lastRenderTriForDegeneration.vertex[2], 1,
|
|
||||||
rendermode_polygon, flags);
|
|
||||||
}
|
}
|
||||||
|
endVertexBatch(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_triangle(Renderer *const renderer, Rect camera,
|
void renderer_triangle(Renderer *const renderer, Rect camera,
|
||||||
@ -440,13 +478,11 @@ void renderer_triangle(Renderer *const renderer, Rect camera,
|
|||||||
RenderTriangle_ renderTriangle = createRenderTriangle(
|
RenderTriangle_ renderTriangle = createRenderTriangle(
|
||||||
renderer, triangleInCamSpace, pivotPoint, rotate, *renderTex);
|
renderer, triangleInCamSpace, pivotPoint, rotate, *renderTex);
|
||||||
|
|
||||||
// NOTE(doyle): Create degenerate vertex setup
|
beginVertexBatch(renderer);
|
||||||
Vertex vertexList[5] = {renderTriangle.vertex[0], renderTriangle.vertex[0],
|
addVertexToRenderGroup_(
|
||||||
renderTriangle.vertex[1], renderTriangle.vertex[2],
|
renderer, renderTex->tex, color, renderTriangle.vertex,
|
||||||
renderTriangle.vertex[2]};
|
ARRAY_COUNT(renderTriangle.vertex), rendermode_triangle, flags);
|
||||||
|
endVertexBatch(renderer);
|
||||||
addVertexToRenderGroup(renderer, renderTex->tex, color, vertexList,
|
|
||||||
ARRAY_COUNT(vertexList), rendermode_triangle, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
|
void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
|
||||||
@ -499,20 +535,13 @@ void renderer_string(Renderer *const renderer, MemoryArena_ *arena, Rect camera,
|
|||||||
RenderQuad_ quad = createRenderQuad(renderer, pos, font->maxSize,
|
RenderQuad_ quad = createRenderQuad(renderer, pos, font->maxSize,
|
||||||
pivotPoint, rotate, renderTex);
|
pivotPoint, rotate, renderTex);
|
||||||
|
|
||||||
vertexList[vertexIndex++] = quad.vertex[0];
|
beginVertexBatch(renderer);
|
||||||
for (i32 i = 0; i < ARRAY_COUNT(quad.vertex); i++)
|
addVertexToRenderGroup_(renderer, tex, color, quad.vertex,
|
||||||
{
|
ARRAY_COUNT(quad.vertex), rendermode_quad,
|
||||||
vertexList[vertexIndex++] = quad.vertex[i];
|
flags);
|
||||||
}
|
endVertexBatch(renderer);
|
||||||
vertexList[vertexIndex++] = quad.vertex[3];
|
|
||||||
pos.x += metric.advance;
|
pos.x += metric.advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
addVertexToRenderGroup(renderer, tex, color, vertexList,
|
|
||||||
numVertexesToAlloc, rendermode_quad, flags);
|
|
||||||
// TODO(doyle): Mem free
|
|
||||||
// PLATFORM_MEM_FREE(arena, vertexList,
|
|
||||||
// sizeof(Vertex) * numVertexesToAlloc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,12 @@ typedef struct RenderGroup
|
|||||||
|
|
||||||
} RenderGroup;
|
} RenderGroup;
|
||||||
|
|
||||||
|
enum VertexBatchState {
|
||||||
|
vertexbatchstate_off,
|
||||||
|
vertexbatchstate_initial_add,
|
||||||
|
vertexbatchstate_active,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Renderer
|
typedef struct Renderer
|
||||||
{
|
{
|
||||||
u32 shaderList[shaderlist_count];
|
u32 shaderList[shaderlist_count];
|
||||||
@ -69,6 +75,9 @@ typedef struct Renderer
|
|||||||
u32 vao[rendermode_count];
|
u32 vao[rendermode_count];
|
||||||
u32 vbo[rendermode_count];
|
u32 vbo[rendermode_count];
|
||||||
|
|
||||||
|
enum VertexBatchState vertexBatchState;
|
||||||
|
i32 groupIndexForVertexBatch;
|
||||||
|
|
||||||
i32 numVertexesInVbo;
|
i32 numVertexesInVbo;
|
||||||
v2 vertexNdcFactor;
|
v2 vertexNdcFactor;
|
||||||
v2 size;
|
v2 size;
|
||||||
|
Loading…
Reference in New Issue
Block a user