1
0
Fork 0

Move backface culling out of Mesh struct

In the future the function will be able to take a list of meshes for a
data-oriented approach.
This commit is contained in:
Austin Morlan 2018-09-10 20:11:52 -07:00
parent 8b9e6b54c8
commit 370fb7bce0
Signed by: austin
GPG Key ID: FD6B27654AF5E348
4 changed files with 100 additions and 95 deletions

View File

@ -28,11 +28,16 @@ struct Vertex
ColorF32 color; ColorF32 color;
}; };
struct MeshRenderData struct Mesh_LocalData
{ {
std::vector<Vertex> vertsTransformed; std::vector<Vertex> verts;
std::vector<Face> culledFaces; std::vector<Face> faces;
bool smooth; };
struct Mesh_TransformedData
{
std::vector<Vertex> verts;
std::vector<Face> faces;
}; };
struct Mesh struct Mesh
@ -50,61 +55,25 @@ struct Mesh
scale = 1.0f; scale = 1.0f;
} }
inline void CullBackfaces(Point camPosition)
{
renderData.culledFaces.clear();
for (size_t f = 0; f < faces.size(); ++f)
{
unsigned int v0 = faces[f].vertIndex[0];
unsigned int v1 = faces[f].vertIndex[1];
unsigned int v2 = faces[f].vertIndex[2];
Vector v01 =
renderData.vertsTransformed[v1].point
- renderData.vertsTransformed[v0].point;
Vector v02 =
renderData.vertsTransformed[v2].point -
renderData.vertsTransformed[v0].point;
Vector normal = Vector::Cross(v01, v02);
// Store normal for flat shading
faces[f].normal = normal;
faces[f].normal.Normalize();
// Invert for Blender-compatibility
normal = -normal;
// Eye vector to viewport
Vector view = camPosition - renderData.vertsTransformed[v0].point;
float dot = Vector::Dot(normal, view);
if (dot < EPSILON_E3)
{
renderData.culledFaces.push_back(faces[f]);
}
}
}
Point position; Point position;
float rotation[3]; float rotation[3];
float scale; float scale;
std::vector<Vertex> verts;
std::vector<Face> faces;
Material material; Material material;
bool smooth;
MeshRenderData renderData; Mesh_LocalData local;
Mesh_TransformedData transformed;
}; };
// PUBLIC FUNCTIONS // PUBLIC FUNCTIONS
void CullBackfaces(
Mesh_LocalData &local, Mesh_TransformedData &transformed,
Point &camPosition);
void RenderMesh( void RenderMesh(
Engine_Buffer &buffer, MeshRenderData &mesh); Engine_Buffer &buffer, Mesh_TransformedData &mesh, bool smooth);
#define GEOMETRY_H #define GEOMETRY_H

View File

@ -65,35 +65,35 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
Matrix tScale = Transform_Scale(mesh.scale); Matrix tScale = Transform_Scale(mesh.scale);
for (size_t v = 0; v < mesh.verts.size(); ++v) for (size_t v = 0; v < mesh.local.verts.size(); ++v)
{ {
mesh.renderData.vertsTransformed[v].point = mesh.verts[v].point * tScale * tRotate * tTranslate; mesh.transformed.verts[v].point = mesh.local.verts[v].point * tScale * tRotate * tTranslate;
mesh.renderData.vertsTransformed[v].normal = mesh.verts[v].normal * tScale * tRotate * tTranslate; mesh.transformed.verts[v].normal = mesh.local.verts[v].normal * tScale * tRotate * tTranslate;
} }
// Cull backfaces before computing colors // Cull backfaces before computing colors
mesh.CullBackfaces(camera.position); CullBackfaces(mesh.local, mesh.transformed, camera.position);
// Color the vertices for Gouraud shading // Color the vertices for Gouraud shading
if (mesh.renderData.smooth) if (mesh.smooth)
{ {
for (size_t f = 0; f < mesh.renderData.culledFaces.size(); ++f) for (size_t f = 0; f < mesh.transformed.faces.size(); ++f)
{ {
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{ {
unsigned int v = mesh.renderData.culledFaces[f].vertIndex[i]; unsigned int v = mesh.transformed.faces[f].vertIndex[i];
ColorF32 totalColor = lights.ambient.ComputeColor(mesh.material.kAmbient); ColorF32 totalColor = lights.ambient.ComputeColor(mesh.material.kAmbient);
for (int c = 0; c < lights.diffuseCount; ++c) for (int c = 0; c < lights.diffuseCount; ++c)
{ {
totalColor += lights.diffuse[c].ComputeColor( totalColor += lights.diffuse[c].ComputeColor(
mesh.material.kDiffuse, mesh.renderData.vertsTransformed[v].normal); mesh.material.kDiffuse, mesh.transformed.verts[v].normal);
} }
mesh.renderData.vertsTransformed[v].color = totalColor; mesh.transformed.verts[v].color = totalColor;
} }
} }
} }
@ -101,17 +101,17 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
// Color the face for flat shading // Color the face for flat shading
else else
{ {
for (size_t f = 0; f < mesh.renderData.culledFaces.size(); ++f) for (size_t f = 0; f < mesh.transformed.faces.size(); ++f)
{ {
ColorF32 totalColor = lights.ambient.ComputeColor(mesh.material.kAmbient); ColorF32 totalColor = lights.ambient.ComputeColor(mesh.material.kAmbient);
for (int c = 0; c < lights.diffuseCount; ++c) for (int c = 0; c < lights.diffuseCount; ++c)
{ {
totalColor += lights.diffuse[c].ComputeColor( totalColor += lights.diffuse[c].ComputeColor(
mesh.material.kDiffuse, mesh.renderData.culledFaces[f].normal); mesh.material.kDiffuse, mesh.transformed.faces[f].normal);
} }
mesh.renderData.culledFaces[f].color = totalColor; mesh.transformed.faces[f].color = totalColor;
} }
} }
@ -126,13 +126,13 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
// Perspective to screen // Perspective to screen
Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale); Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale);
for (size_t v = 0; v < mesh.verts.size(); ++v) for (size_t v = 0; v < mesh.transformed.verts.size(); ++v)
{ {
mesh.renderData.vertsTransformed[v].point *= tView * tPersp * tScreen; mesh.transformed.verts[v].point *= tView * tPersp * tScreen;
mesh.renderData.vertsTransformed[v].point /= mesh.renderData.vertsTransformed[v].point.w; mesh.transformed.verts[v].point /= mesh.transformed.verts[v].point.w;
} }
RenderMesh(buffer, mesh.renderData); RenderMesh(buffer, mesh.transformed, mesh.smooth);
} }
void Engine_Shutdown(void) void Engine_Shutdown(void)
@ -208,10 +208,10 @@ static void CheckInputs(uint32_t input)
if (CHECK_BIT(input, SHADING_TOGGLE)) if (CHECK_BIT(input, SHADING_TOGGLE))
{ {
mesh.renderData.smooth = true; mesh.smooth = true;
} }
else else
{ {
mesh.renderData.smooth = false; mesh.smooth = false;
} }
} }

View File

@ -30,17 +30,53 @@ struct BoundingBox
// PUBLIC FUNCTIONS // PUBLIC FUNCTIONS
void RenderMesh(Engine_Buffer &buffer, MeshRenderData &mesh) void CullBackfaces(
Mesh_LocalData &local, Mesh_TransformedData &transformed,
Point &camPosition)
{ {
for(size_t f = 0; f < mesh.culledFaces.size(); ++f) transformed.faces.clear();
{
unsigned int vIndex0 = mesh.culledFaces[f].vertIndex[0];
unsigned int vIndex1 = mesh.culledFaces[f].vertIndex[1];
unsigned int vIndex2 = mesh.culledFaces[f].vertIndex[2];
Vertex v0 = mesh.vertsTransformed[vIndex0]; for (size_t f = 0; f < local.faces.size(); ++f)
Vertex v1 = mesh.vertsTransformed[vIndex1]; {
Vertex v2 = mesh.vertsTransformed[vIndex2]; unsigned int v0 = local.faces[f].vertIndex[0];
unsigned int v1 = local.faces[f].vertIndex[1];
unsigned int v2 = local.faces[f].vertIndex[2];
Vector v01 = transformed.verts[v1].point - transformed.verts[v0].point;
Vector v02 = transformed.verts[v2].point - transformed.verts[v0].point;
Vector normal = Vector::Cross(v01, v02);
// Store normal for flat shading
local.faces[f].normal = normal;
local.faces[f].normal.Normalize();
// Invert for Blender-compatibility
normal = -normal;
// Eye vector to viewport
Vector view = camPosition - transformed.verts[v0].point;
float dot = Vector::Dot(normal, view);
if (dot < EPSILON_E3)
{
transformed.faces.push_back(local.faces[f]);
}
}
}
void RenderMesh(Engine_Buffer &buffer, Mesh_TransformedData &mesh, bool smooth)
{
for(size_t f = 0; f < mesh.faces.size(); ++f)
{
unsigned int vIndex0 = mesh.faces[f].vertIndex[0];
unsigned int vIndex1 = mesh.faces[f].vertIndex[1];
unsigned int vIndex2 = mesh.faces[f].vertIndex[2];
Vertex v0 = mesh.verts[vIndex0];
Vertex v1 = mesh.verts[vIndex1];
Vertex v2 = mesh.verts[vIndex2];
// Bounding box used to for iterating over possible pixels of this triangle // Bounding box used to for iterating over possible pixels of this triangle
BoundingBox box(v0.point, v1.point, v2.point); BoundingBox box(v0.point, v1.point, v2.point);
@ -80,7 +116,7 @@ void RenderMesh(Engine_Buffer &buffer, MeshRenderData &mesh)
{ {
ColorF32 totalColor; ColorF32 totalColor;
if (mesh.smooth) if (smooth)
{ {
totalColor = totalColor =
(barycenter[0] * v0.color) (barycenter[0] * v0.color)
@ -89,7 +125,7 @@ void RenderMesh(Engine_Buffer &buffer, MeshRenderData &mesh)
} }
else else
{ {
totalColor = mesh.culledFaces[f].color; totalColor = mesh.faces[f].color;
} }
ColorU32 color = ColorF32::ConvertToU32(totalColor); ColorU32 color = ColorF32::ConvertToU32(totalColor);

View File

@ -41,7 +41,7 @@ int LoadMesh(char *filename, Mesh &mesh)
&v.point.y, &v.point.y,
&v.point.z); &v.point.z);
mesh.verts.push_back(v); mesh.local.verts.push_back(v);
} }
else if (token[0] == 'f') else if (token[0] == 'f')
{ {
@ -58,7 +58,7 @@ int LoadMesh(char *filename, Mesh &mesh)
f.vertIndex[1] -= 1; f.vertIndex[1] -= 1;
f.vertIndex[2] -= 1; f.vertIndex[2] -= 1;
mesh.faces.push_back(f); mesh.local.faces.push_back(f);
} }
token = GetLine(buffer, sizeof(buffer), fp); token = GetLine(buffer, sizeof(buffer), fp);
@ -67,10 +67,10 @@ int LoadMesh(char *filename, Mesh &mesh)
ComputeNormals(mesh); ComputeNormals(mesh);
printf("OBJ: %s\n", filename); printf("OBJ: %s\n", filename);
printf("Verts: %lu\n", mesh.verts.size()); printf("Verts: %lu\n", mesh.local.verts.size());
printf("Faces: %lu\n", mesh.faces.size()); printf("Faces: %lu\n", mesh.local.faces.size());
mesh.renderData.vertsTransformed.resize(mesh.verts.size()); mesh.transformed.verts.resize(mesh.local.verts.size());
fclose(fp); fclose(fp);
@ -100,36 +100,36 @@ static char *GetLine(char *buffer, int maxLength, FILE *fp)
static void ComputeNormals(Mesh &mesh) static void ComputeNormals(Mesh &mesh)
{ {
int *vertexNormalCount = (int*)calloc((size_t)(mesh.verts.size()), sizeof(int)); int *vertexNormalCount = (int*)calloc((size_t)(mesh.local.verts.size()), sizeof(int));
for (size_t f = 0; f < mesh.faces.size(); ++f) for (size_t f = 0; f < mesh.local.faces.size(); ++f)
{ {
unsigned int v0 = mesh.faces[f].vertIndex[0]; unsigned int v0 = mesh.local.faces[f].vertIndex[0];
unsigned int v1 = mesh.faces[f].vertIndex[1]; unsigned int v1 = mesh.local.faces[f].vertIndex[1];
unsigned int v2 = mesh.faces[f].vertIndex[2]; unsigned int v2 = mesh.local.faces[f].vertIndex[2];
Vector v01 = mesh.verts[v1].point - mesh.verts[v0].point; Vector v01 = mesh.local.verts[v1].point - mesh.local.verts[v0].point;
Vector v02 = mesh.verts[v2].point - mesh.verts[v0].point; Vector v02 = mesh.local.verts[v2].point - mesh.local.verts[v0].point;
Vector normal = Vector::Cross(v01, v02); Vector normal = Vector::Cross(v01, v02);
// Add each vertex's normal to the sum for future averaging // Add each vertex's normal to the sum for future averaging
mesh.verts[v0].normal += normal; mesh.local.verts[v0].normal += normal;
mesh.verts[v1].normal += normal; mesh.local.verts[v1].normal += normal;
mesh.verts[v2].normal += normal; mesh.local.verts[v2].normal += normal;
++vertexNormalCount[v0]; ++vertexNormalCount[v0];
++vertexNormalCount[v1]; ++vertexNormalCount[v1];
++vertexNormalCount[v2]; ++vertexNormalCount[v2];
} }
for (size_t v = 0; v < mesh.verts.size(); ++v) for (size_t v = 0; v < mesh.local.verts.size(); ++v)
{ {
if (vertexNormalCount[v] > 0) if (vertexNormalCount[v] > 0)
{ {
// Compute the average normal for this vertex // Compute the average normal for this vertex
mesh.verts[v].normal /= vertexNormalCount[v]; mesh.local.verts[v].normal /= vertexNormalCount[v];
mesh.verts[v].normal.Normalize(); mesh.local.verts[v].normal.Normalize();
} }
} }
} }