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