Add flat shading with ambient and diffuse light
This commit is contained in:
parent
f642b0ec02
commit
63e8bd1b93
3
Makefile
3
Makefile
|
@ -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)
|
||||
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))
|
||||
|
||||
_OBJS = engine.o geometry.o loader.o main.o platform.o transform.o
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COLOR_H
|
||||
|
||||
#include "util.h"
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
|
@ -9,16 +10,65 @@ struct ColorU32
|
|||
{
|
||||
struct
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
uint8_t a;
|
||||
uint8_t b, g, r, a;
|
||||
};
|
||||
|
||||
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
|
||||
#endif
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
#ifndef GEOMETRY_H
|
||||
|
||||
#include "color.h"
|
||||
#include "point.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// STRUCTURES
|
||||
struct Material
|
||||
{
|
||||
ColorF32 kAmbient;
|
||||
ColorF32 kDiffuse;
|
||||
};
|
||||
|
||||
struct Face
|
||||
{
|
||||
unsigned int vertIndex[3];
|
||||
ColorU32 color;
|
||||
};
|
||||
|
||||
struct Mesh
|
||||
|
@ -26,12 +34,44 @@ struct Mesh
|
|||
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;
|
||||
float rotation[3];
|
||||
float scale;
|
||||
std::vector<Point> verts;
|
||||
std::vector<Point> vertsTransformed;
|
||||
std::vector<Face> faces;
|
||||
std::vector<Face> culledFaces;
|
||||
Material material;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#ifndef POINT_H
|
||||
|
||||
#include "vec.h"
|
||||
|
||||
|
||||
// STRUCTURE
|
||||
struct Point
|
||||
|
@ -34,6 +36,18 @@ inline Point operator/(Point v, float f)
|
|||
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
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,8 @@ const float EPSILON_E3 = 1E-3f;
|
|||
#define CHECK_BIT(x, bit) (x & (1UL << bit))
|
||||
#define DEG_TO_RAD(deg) ((deg * (float)M_PI) / 180.0f)
|
||||
#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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -2,16 +2,19 @@
|
|||
#include "color.h"
|
||||
#include "engine.h"
|
||||
#include "geometry.h"
|
||||
#include "light.h"
|
||||
#include "loader.h"
|
||||
#include "matrix.h"
|
||||
#include "transform.h"
|
||||
#include "util.h"
|
||||
#include "vec.h"
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
// GLOBALS
|
||||
static Mesh mesh;
|
||||
static Camera camera;
|
||||
static LightList lights;
|
||||
|
||||
|
||||
// PRIVATE PROTOTYPES
|
||||
|
@ -29,9 +32,17 @@ int Engine_Init(Engine_Buffer &buffer, char *filename)
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -39,30 +50,69 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
|||
{
|
||||
CheckInputs(input);
|
||||
|
||||
|
||||
// Local space to world space
|
||||
Matrix tTranslate = Transform_Translate(
|
||||
mesh.position.x, mesh.position.y, mesh.position.z);
|
||||
|
||||
Matrix tRotate = Transform_Rotate(
|
||||
mesh.rotation[0], mesh.rotation[1], mesh.rotation[2]);
|
||||
|
||||
Matrix tScale = Transform_Scale(
|
||||
mesh.scale);
|
||||
Matrix tScale = Transform_Scale(mesh.scale);
|
||||
|
||||
Matrix tView = Transform_View(
|
||||
camera.position, camera.rotation);
|
||||
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
||||
{
|
||||
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(
|
||||
camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip);
|
||||
|
||||
for (size_t v = 0; v < mesh.verts.size(); ++v)
|
||||
{
|
||||
mesh.vertsTransformed[v] =
|
||||
mesh.verts[v] * tScale * tRotate * tTranslate * tView * tPersp;
|
||||
mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tView * tPersp;
|
||||
|
||||
mesh.vertsTransformed[v] =
|
||||
mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w;
|
||||
}
|
||||
|
||||
// Perspective to screen
|
||||
Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(
|
||||
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[v1].x, mesh.vertsTransformed[v1].y,
|
||||
mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y);
|
||||
|
|
Loading…
Reference in New Issue