From 3c9b7c937638aa59c3a946cf0f2670517f11ea0b Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Tue, 25 Jan 2022 11:45:53 -0500 Subject: [PATCH] add full lighting shader with debug values --- data/full_lighting.frag | 60 +++++++++++++++++++++++++ data/full_lighting.vert | 27 +++++++++++ data/{shader.frag => texture_only.frag} | 1 + data/{shader.vert => texture_only.vert} | 0 src/main.cpp | 40 ++++++++++++++--- src/shader.h | 2 +- src/tangerine.cpp | 17 ++++--- src/tangerine.h | 27 +++++++---- 8 files changed, 152 insertions(+), 22 deletions(-) create mode 100644 data/full_lighting.frag create mode 100644 data/full_lighting.vert rename data/{shader.frag => texture_only.frag} (99%) rename data/{shader.vert => texture_only.vert} (100%) diff --git a/data/full_lighting.frag b/data/full_lighting.frag new file mode 100644 index 0000000..68457fd --- /dev/null +++ b/data/full_lighting.frag @@ -0,0 +1,60 @@ +#version 330 core + +in vec3 frag_pos; +in vec3 frag_normal; +in vec2 frag_uv; + +out vec4 color; + +layout (std140) uniform matrices +{ + mat4 view_xform; + mat4 proj_xform; + mat4 normal_xform; +}; + +uniform mat4 node_xform; +uniform sampler2D sampler; + +struct PointLight +{ + vec3 pos; + vec3 color; + float intensity; +}; + +struct DirectionalLight +{ + vec3 direction; + vec3 color; + float intensity; +}; + +// FIXME: probably want a buffer-backed UBO for lights in case we have more +// than one shader that does lighting calculations +//uniform PointLight lights[32]; +// FIXME: hard-coded values for testing +const DirectionalLight dl1 = + DirectionalLight(vec3(-2, 1, 3), vec3(1,1,1), 1); +const vec4 ambient_color = vec4(0.1, 0.1, 0.1, 1); + +const PointLight pl1 = PointLight(vec3(-20, 10, 30), vec3(1, 1, 1), 800); + + +void main() +{ +#if 1 // directional light + vec3 light_direction = normalize(dl1.direction); + float diffuse_factor = clamp(dot(frag_normal, light_direction), 0, 1); + vec4 diffuse_color = dl1.intensity * vec4(dl1.color * diffuse_factor, 1); +#else // point light + vec3 light_direction = pl1.pos - frag_pos; + float len = length(light_direction); + light_direction = normalize(light_direction); + float diffuse_factor = dot(frag_normal, light_direction) / pow(len, 2); + diffuse_factor = clamp(diffuse_factor, 0, 1); + vec4 diffuse_color = pl1.intensity * vec4(pl1.color * diffuse_factor, 1); +#endif + + color = (ambient_color + diffuse_color) * texture(sampler, frag_uv.st); +} diff --git a/data/full_lighting.vert b/data/full_lighting.vert new file mode 100644 index 0000000..f6fe8be --- /dev/null +++ b/data/full_lighting.vert @@ -0,0 +1,27 @@ +#version 330 core + +layout (location = 0) in vec3 position; +layout (location = 1) in vec3 normal; +layout (location = 2) in vec2 uv; + +out vec3 frag_pos; +out vec3 frag_normal; +out vec2 frag_uv; + +layout (std140) uniform matrices +{ + mat4 view_xform; + mat4 proj_xform; + mat4 normal_xform; +}; + +uniform mat4 node_xform; + + +void main() +{ + frag_pos = (node_xform * vec4(position, 1)).xyz; + frag_uv = uv; + frag_normal = normalize(mat3(node_xform) * normal); + gl_Position = proj_xform * view_xform * node_xform * vec4(position, 1); +} diff --git a/data/shader.frag b/data/texture_only.frag similarity index 99% rename from data/shader.frag rename to data/texture_only.frag index f1c37f3..311fa02 100644 --- a/data/shader.frag +++ b/data/texture_only.frag @@ -14,6 +14,7 @@ layout (std140) uniform matrices uniform mat4 node_xform; uniform sampler2D sampler; + void main() { color = texture(sampler, frag_uv.st); diff --git a/data/shader.vert b/data/texture_only.vert similarity index 100% rename from data/shader.vert rename to data/texture_only.vert diff --git a/src/main.cpp b/src/main.cpp index 5c491e8..8efd81e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,13 +15,13 @@ loadScene(RenderState* rs) // NOTE: the default shaders already have their attribute mappings created // in initRenderState, but if you use a custom shader, you will need to // create a GLBufferToAttribMapping manually - ShaderProgram* s_default = getShaderByName("default", rs->gl_ctx); - if (!s_default) return false; + ShaderProgram* shader_lit = getShaderByName("full_lighting", rs->gl_ctx); + if (!shader_lit) return false; // NOTE: init new render group RenderGroup* textured_cubes = getFreeRenderGroup(rs); assert(textured_cubes); - initRenderGroup(textured_cubes, rs->rg_arena, s_default, 256, + initRenderGroup(textured_cubes, rs->rg_arena, shader_lit, 256, "textured_cubes"); // NOTE: init entities @@ -45,8 +45,8 @@ loadScene(RenderState* rs) rs->gl_ctx, rs->rg_arena, tex_cube, - s_default->num_vertex_attribs, - s_default->attrib_mappings, + shader_lit->num_vertex_attribs, + shader_lit->attrib_mappings, cube_name)) { return false; @@ -56,6 +56,36 @@ loadScene(RenderState* rs) scaleEntity(e, 3); } + // NOTE: add a point light + PointLight* l1 = &rs->lights[rs->num_lights++]; + l1->position = glm::vec3(-20, 10, 30); + l1->color = glm::vec3(1, 1, 1); + l1->intensity = 256; + + // NOTE: add a debug mesh to view the light source + RenderGroup* debug_group = getFreeRenderGroup(rs); + assert(debug_group); + ShaderProgram* s_debug = getShaderByName("debug", rs->gl_ctx); + assert(s_debug); + initRenderGroup(debug_group, rs->rg_arena, s_debug, 256, "debug_lights"); + + for (u32 i = 0; i < rs->num_lights; i++) { + PointLight* l = &rs->lights[i]; + Entity* e = getFreeEntity(debug_group); + assert(e); + if (!initEntity(e, + rs->gl_ctx, + rs->rg_arena, + tex_cube, + s_debug->num_vertex_attribs, + s_debug->attrib_mappings)) + { + return false; + } + + setEntityPosition(e, l->position); + } + return true; } diff --git a/src/shader.h b/src/shader.h index 9dff3a4..0ce575f 100644 --- a/src/shader.h +++ b/src/shader.h @@ -158,7 +158,7 @@ struct Transforms const float DEFAULT_FOV = 60.f; const float NEAR_CLIP_PLANE = 5.f; const float DEFAULT_ASPECT_RATIO = 16.f / 9.f; -const glm::vec3 DEFAULT_CAM_POS = { 0, 0, 30.f }; +const glm::vec3 DEFAULT_CAM_POS = { 0, 0, 50.f }; const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 }; diff --git a/src/tangerine.cpp b/src/tangerine.cpp index 0115e54..4d3ebaf 100644 --- a/src/tangerine.cpp +++ b/src/tangerine.cpp @@ -41,6 +41,10 @@ initRenderState(u32 max_models, rs->render_groups = ARENA_ALLOC(rs->rg_arena, RenderGroup, DEFAULT_RENDER_GROUP_COUNT); + // FIXME: revisit for 'Scene' abstraction + rs->max_lights = 32; + rs->lights = ARENA_ALLOC(rs->rg_arena, PointLight, rs->max_lights); + rs->gl_ctx = initGLContext(rs->assets.arena, max_shaders, max_textures, @@ -188,18 +192,17 @@ loadDefaultShaders(RenderState* rs, { for (u32 i = 0; i < num_shaders; i++) { const ShaderInit& si = shaders[i]; - bool ret = addShaderProgram(rs->assets.arena, - rs->gl_ctx, - si.vert_path, - si.frag_path, - si.name); - if (!ret) { + if (!addShaderProgram(rs->assets.arena, + rs->gl_ctx, + si.vert_path, + si.frag_path, + si.name)) + { LOG(Error) << "failed to load shader " << si.name << "\n"; return false; } - // TODO: need to set the mappings here ShaderProgram* shader = getShaderByName(si.name, rs->gl_ctx); assert(shader); diff --git a/src/tangerine.h b/src/tangerine.h index 00063a2..2a3b8cc 100644 --- a/src/tangerine.h +++ b/src/tangerine.h @@ -15,8 +15,12 @@ /* * === TODO: === * - full lighting model +* - add buffer backed storage for light arrays in GLSL +* - remove hard-coded values in full_lighting.frag * - test complex entities * - need a separate GLBufferToAttribMapping for each mesh on an entity +* - maybe fixed now with MeshBufferType enum and getMeshData() +* - add an example of dynamically switching shaders for an entity * - fix debug load times (either by using cgltf, or hiding tinygltf.h) * - RenderGroups and Entities need to come into and out of existence during * gameplay. So, we need to extend MemoryArena to be a pool allocator @@ -79,6 +83,7 @@ struct GLClearColor struct RenderState { bool running; + GLClearColor clear_col; Transforms* xforms; // NOTE: would be part of camera in libTangerine SDLHandles* handles; GLContext* gl_ctx; @@ -89,13 +94,13 @@ struct RenderState u32 max_render_groups; RenderGroup* render_groups; - GLClearColor clear_col; - // TODO: full lighting -#if 0 + // TODO: should we have a 'scene' abstraction here? + // could have render groups, lights, camera + // could match up with gltf scene graph where everyting is part of a node + // TODO: will also need other types of lights: directional, spotlight u32 num_lights; u32 max_lights; PointLight* lights; -#endif }; @@ -149,19 +154,23 @@ struct ShaderInit const char* frag_path; }; -#define DEFAULT_SHADER_INIT { "default", \ - "../data/shader.vert", \ - "../data/shader.frag" } +#define SHADER_INIT_COUNT 4 +#define TEXTURE_ONLY_SHADER_INIT { "texture_only", \ + "../data/texture_only.vert", \ + "../data/texture_only.frag" } +#define FULL_LIGHTING_SHADER_INIT { "full_lighting", \ + "../data/full_lighting.vert", \ + "../data/full_lighting.frag" } #define DEBUG_SHADER_INIT { "debug", \ "../data/debug.vert", \ "../data/debug.frag", } #define COLORED_VERT_SHADER_INIT { "colored_vertices", \ "../data/colored_vertices.vert", \ "../data/colored_vertices.frag", } -#define SHADER_INIT_COUNT 3 const ShaderInit SHADER_INIT_LIST[SHADER_INIT_COUNT] { - DEFAULT_SHADER_INIT, + TEXTURE_ONLY_SHADER_INIT, + FULL_LIGHTING_SHADER_INIT, DEBUG_SHADER_INIT, COLORED_VERT_SHADER_INIT };