1
0
Fork 0

Add flat shading with ambient and diffuse light

This commit is contained in:
Austin Morlan 2018-09-05 19:26:54 -07:00
parent f642b0ec02
commit 63e8bd1b93
Signed by: austin
GPG Key ID: FD6B27654AF5E348
8 changed files with 308 additions and 18 deletions

View File

@ -36,7 +36,8 @@ WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\
CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR) CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR)
LIBS=-lSDL2 LIBS=-lSDL2
_HEADERS = color.h engine.h geometry.h loader.h platform.h point.h transform.h util.h _HEADERS = color.h engine.h geometry.h light.h loader.h platform.h point.h\
transform.h util.h vec.h
HEADERS = $(patsubst %,$(INCLUDE_DIR)/%,$(_HEADERS)) HEADERS = $(patsubst %,$(INCLUDE_DIR)/%,$(_HEADERS))
_OBJS = engine.o geometry.o loader.o main.o platform.o transform.o _OBJS = engine.o geometry.o loader.o main.o platform.o transform.o

View File

@ -1,5 +1,6 @@
#ifndef COLOR_H #ifndef COLOR_H
#include "util.h"
#include <cstdint> #include <cstdint>
@ -9,16 +10,65 @@ struct ColorU32
{ {
struct struct
{ {
uint8_t b; uint8_t b, g, r, a;
uint8_t g;
uint8_t r;
uint8_t a;
}; };
uint32_t u32; uint32_t u32;
}; };
}; };
struct ColorF32
{
float b, g, r, a;
static inline ColorU32 ConvertToU32(ColorF32 c)
{
ColorU32 result;
result.b = (uint8_t)(c.b * 255);
result.g = (uint8_t)(c.g * 255);
result.r = (uint8_t)(c.r * 255);
result.a = (uint8_t)(c.a * 255);
return result;
}
};
// OPERATORS
// c1 + c2
inline ColorF32 operator+(ColorF32 c1, ColorF32 c2)
{
ColorF32 result;
result.b = MIN((c1.b + c2.b), 1.0f);
result.g = MIN((c1.g + c2.g), 1.0f);
result.r = MIN((c1.r + c2.r), 1.0f);
result.a = MIN((c1.a + c2.a), 1.0f);
return result;
}
// c1 += c2
inline ColorF32 &operator+=(ColorF32 &c1, ColorF32 c2)
{
c1 = c1 + c2;
return(c1);
}
// c * f
inline ColorF32 operator*(ColorF32 c, float f)
{
ColorF32 result;
result.b = MIN((f * c.b), 1.0f);
result.g = MIN((f * c.g), 1.0f);
result.r = MIN((f * c.r), 1.0f);
result.a = MIN((f * c.a), 1.0f);
return result;
}
#define COLOR_H #define COLOR_H
#endif #endif

View File

@ -1,14 +1,22 @@
#ifndef GEOMETRY_H #ifndef GEOMETRY_H
#include "color.h"
#include "point.h" #include "point.h"
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
// STRUCTURES // STRUCTURES
struct Material
{
ColorF32 kAmbient;
ColorF32 kDiffuse;
};
struct Face struct Face
{ {
unsigned int vertIndex[3]; unsigned int vertIndex[3];
ColorU32 color;
}; };
struct Mesh struct Mesh
@ -26,12 +34,44 @@ struct Mesh
scale = 1.0f; scale = 1.0f;
} }
inline void CullBackfaces(Point camPosition)
{
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 = vertsTransformed[v1] - vertsTransformed[v0];
Vector v02 = vertsTransformed[v2] - vertsTransformed[v0];
Vector normal = Vector::Cross(v01, v02);
// Invert for Blender-compatibility
normal = -normal;
// Eye vector to viewport
Vector view = camPosition - vertsTransformed[v0];
float dot = Vector::Dot(normal, view);
if (dot < EPSILON_E3)
{
culledFaces.push_back(faces[f]);
}
}
}
Point position; Point position;
float rotation[3]; float rotation[3];
float scale; float scale;
std::vector<Point> verts; std::vector<Point> verts;
std::vector<Point> vertsTransformed; std::vector<Point> vertsTransformed;
std::vector<Face> faces; std::vector<Face> faces;
std::vector<Face> culledFaces;
Material material;
}; };

51
include/light.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef LIGHT_H
#include "color.h"
#include "vec.h"
#include <cstdint>
// STRUCTURES
struct LightAmbient
{
inline ColorF32 ComputeColor(ColorF32 reflectivity)
{
ColorF32 result;
result = reflectivity * intensity;
return result;
}
float intensity;
};
struct LightDiffuse
{
inline ColorF32 ComputeColor(ColorF32 reflectivity, Vector normal)
{
ColorF32 result;
float dot = Vector::Dot(normal, direction);
result = reflectivity * intensity * dot;
return result;
}
float intensity;
Vector direction;
};
struct LightList
{
LightAmbient ambient;
LightDiffuse *diffuse;
int diffuseCount;
};
#define LIGHT_H
#endif

View File

@ -1,5 +1,7 @@
#ifndef POINT_H #ifndef POINT_H
#include "vec.h"
// STRUCTURE // STRUCTURE
struct Point struct Point
@ -34,6 +36,18 @@ inline Point operator/(Point v, float f)
return result; return result;
} }
// v1 - v2
inline Vector operator-(Point v1, Point v2)
{
Vector result;
result.x = v1.x - v2.x;
result.y = v1.y - v2.y;
result.z = v1.z - v2.z;
return result;
}
#define POINT_H #define POINT_H
#endif #endif

View File

@ -13,6 +13,8 @@ const float EPSILON_E3 = 1E-3f;
#define CHECK_BIT(x, bit) (x & (1UL << bit)) #define CHECK_BIT(x, bit) (x & (1UL << bit))
#define DEG_TO_RAD(deg) ((deg * (float)M_PI) / 180.0f) #define DEG_TO_RAD(deg) ((deg * (float)M_PI) / 180.0f)
#define SWAP(a, b, temp) {temp = a; a = b; b = temp;} #define SWAP(a, b, temp) {temp = a; a = b; b = temp;}
#define MIN(a, b) ((a < b) ? a : b)
#define MAX(a, b) ((a > b) ? a : b)
#define FLOAT_EQUAL(a, b) ((fabsf(a - b) < EPSILON_E3) ? 1 : 0) #define FLOAT_EQUAL(a, b) ((fabsf(a - b) < EPSILON_E3) ? 1 : 0)

82
include/vec.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef VEC_H
#include "util.h"
#include <cmath>
// STRUCTURE
struct Vector
{
inline Vector(void) : x(0), y(0), z(0), w(0) {}
inline Vector(float x, float y, float z) : x(x), y(y), z(z), w(0) {}
inline void Normalize(void)
{
float length = sqrtf(x*x + y*y + z*z);
// zero length
if (length < EPSILON_E3)
{
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
else
{
float lengthInv = 1.0f / length;
x *= lengthInv;
y *= lengthInv;
z *= lengthInv;
}
}
inline static float Dot(Vector v1, Vector v2)
{
float result;
result = (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
return result;
}
inline static Vector Cross(Vector v1, Vector v2)
{
Vector result;
result.x = (v1.y * v2.z) - (v1.z * v2.y);
result.y = (v1.z * v2.x) - (v1.x * v2.z);
result.z = (v1.x * v2.y) - (v1.y * v2.x);
return result;
}
union
{
float e[4];
struct
{
float x, y, z, w;
};
};
};
// OPERATORS
// -v
inline Vector operator-(Vector v)
{
Vector result;
result.x = -v.x;
result.y = -v.y;
result.z = -v.z;
return result;
}
#define VEC_H
#endif

View File

@ -2,16 +2,19 @@
#include "color.h" #include "color.h"
#include "engine.h" #include "engine.h"
#include "geometry.h" #include "geometry.h"
#include "light.h"
#include "loader.h" #include "loader.h"
#include "matrix.h" #include "matrix.h"
#include "transform.h" #include "transform.h"
#include "util.h" #include "util.h"
#include "vec.h"
#include <cstdio> #include <cstdio>
// GLOBALS // GLOBALS
static Mesh mesh; static Mesh mesh;
static Camera camera; static Camera camera;
static LightList lights;
// PRIVATE PROTOTYPES // PRIVATE PROTOTYPES
@ -29,9 +32,17 @@ int Engine_Init(Engine_Buffer &buffer, char *filename)
} }
mesh.position.z = 250; mesh.position.z = 250;
mesh.material.kDiffuse = {1.0,1.0,1.0,1.0};
mesh.material.kAmbient = {1.0,1.0,1.0,1.0};
camera.SetFOV(90.0f, buffer.width, buffer.height); camera.SetFOV(90.0f, buffer.width, buffer.height);
lights.diffuse = (LightDiffuse*)malloc(sizeof(LightDiffuse));
lights.diffuseCount = 1;
lights.ambient.intensity = 1.0;
lights.diffuse[0].intensity = 0.5;
lights.diffuse[0].direction = Vector(1,1,1);
return 0; return 0;
} }
@ -39,30 +50,69 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
{ {
CheckInputs(input); CheckInputs(input);
// Local space to world space
Matrix tTranslate = Transform_Translate( Matrix tTranslate = Transform_Translate(
mesh.position.x, mesh.position.y, mesh.position.z); mesh.position.x, mesh.position.y, mesh.position.z);
Matrix tRotate = Transform_Rotate( Matrix tRotate = Transform_Rotate(
mesh.rotation[0], mesh.rotation[1], mesh.rotation[2]); mesh.rotation[0], mesh.rotation[1], mesh.rotation[2]);
Matrix tScale = Transform_Scale( Matrix tScale = Transform_Scale(mesh.scale);
mesh.scale);
Matrix tView = Transform_View( for (size_t v = 0; v < mesh.verts.size(); ++v)
camera.position, camera.rotation); {
mesh.vertsTransformed[v] =
mesh.verts[v] * tScale * tRotate * tTranslate;
}
// Cull backfaces before computing colors
mesh.CullBackfaces(camera.position);
// Color the faces (flat shading)
for (size_t f = 0; f < mesh.culledFaces.size(); ++f)
{
unsigned int v0 = mesh.culledFaces[f].vertIndex[0];
unsigned int v1 = mesh.culledFaces[f].vertIndex[1];
unsigned int v2 = mesh.culledFaces[f].vertIndex[2];
Vector v01 = mesh.vertsTransformed[v1] - mesh.vertsTransformed[v0];
Vector v02 = mesh.vertsTransformed[v2] - mesh.vertsTransformed[v0];
Vector normal = Vector::Cross(v01, v02);
normal.Normalize();
ColorF32 totalColor = lights.ambient.ComputeColor(mesh.material.kAmbient);
for (int c = 0; c < lights.diffuseCount; ++c)
{
totalColor += lights.diffuse[c].ComputeColor(
mesh.material.kDiffuse, normal);
}
mesh.faces[f].color = ColorF32::ConvertToU32(totalColor);
}
// World space to camera (view) space
Matrix tView = Transform_View(camera.position, camera.rotation);
// Camera space to perspective
Matrix tPersp = Transform_Perspective( Matrix tPersp = Transform_Perspective(
camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip); camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip);
for (size_t v = 0; v < mesh.verts.size(); ++v) for (size_t v = 0; v < mesh.verts.size(); ++v)
{ {
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tView * tPersp;
mesh.verts[v] * tScale * tRotate * tTranslate * tView * tPersp;
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] =
mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w; mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w;
} }
// 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.verts.size(); ++v)
@ -70,16 +120,16 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tScreen; mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tScreen;
} }
for(size_t f = 0; f < mesh.faces.size(); ++f)
{
unsigned int v0 = mesh.faces[f].vertIndex[0];
unsigned int v1 = mesh.faces[f].vertIndex[1];
unsigned int v2 = mesh.faces[f].vertIndex[2];
ColorU32 white = {0xff,0xff,0xff,0xff}; // Fill each face with its respective color
for(size_t f = 0; f < mesh.culledFaces.size(); ++f)
{
unsigned int v0 = mesh.culledFaces[f].vertIndex[0];
unsigned int v1 = mesh.culledFaces[f].vertIndex[1];
unsigned int v2 = mesh.culledFaces[f].vertIndex[2];
FillTriangle( FillTriangle(
buffer.pixels, buffer.width, white.u32, buffer.pixels, buffer.width, mesh.faces[f].color.u32,
mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y, mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y,
mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y, mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y,
mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y); mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y);