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)
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
#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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 "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);
|
||||||
|
|
Loading…
Reference in New Issue