From 1eea92a3afacf336eb7763bb25a6097752d408e7 Mon Sep 17 00:00:00 2001 From: elipzer Date: Sat, 15 Sep 2018 03:46:42 -0400 Subject: [PATCH] LitScene Phong Lighting Complete Now, LitScene allows for simple lighting. (Shadows still to come). Ambient, specular, and diffuse lighting available and each mesh's vertex can define a material that defines its reflectivity. An example scene was added to the MyApplication as the scene for the 6 button. --- OpenGLEngine/BuiltinTypes.h | 79 +++++++++++++++++++++--------- OpenGLEngine/GLUtil.cpp | 17 +++---- OpenGLEngine/LitBatch.cpp | 2 +- OpenGLEngine/LitFS.glsl | 61 ++++++++++++++--------- OpenGLEngine/LitScene.cpp | 13 ++--- OpenGLEngine/LitScene.h | 13 +++-- OpenGLEngine/LitVS.glsl | 33 ++++++++----- OpenGLEngine/MeshGenerator.h | 4 +- OpenGLEngine/MyBuiltinLitScene.cpp | 16 ++++-- 9 files changed, 147 insertions(+), 91 deletions(-) diff --git a/OpenGLEngine/BuiltinTypes.h b/OpenGLEngine/BuiltinTypes.h index 203d214..4e5dbab 100644 --- a/OpenGLEngine/BuiltinTypes.h +++ b/OpenGLEngine/BuiltinTypes.h @@ -16,10 +16,60 @@ namespace charcoal typedef vec4 ColorRGBA; typedef vec3 ColorRGB; typedef vec2 UV; - typedef float SpecularExponent; typedef unsigned int Index; + // Shader Data Types + + struct Light + { + typedef vec3 Power; + typedef vec3 Fade; + + Light( + const Position& position, + const Power& power, + const ColorRGB& ambient, + const ColorRGB& diffuse, + const ColorRGB& specular, + const Fade& fade + ) + : position(position), + power(power), + ambient(ambient), + diffuse(diffuse), + specular(specular), + fade(fade) + {} + + Position position; + Power power; + ColorRGB ambient; + ColorRGB diffuse; + ColorRGB specular; + Fade fade; + }; + + struct Material + { + Material( + float ambient = 1.0f, + float diffuse = 1.0f, + float specular = 0.0f, + float specular_exponent = 1.0f + ) + : ambient(ambient), + diffuse(diffuse), + specular(specular), + specular_exponent(specular_exponent) + {} + + float ambient; + float diffuse; + float specular; + float specular_exponent; + }; + // Generic Vertices struct PVertex @@ -38,34 +88,15 @@ namespace charcoal Normal normal; }; - struct PNSVertex + struct PNMVertex { void set_position(const Position& position) { this->position = position; } void set_normal(const Normal& normal) { this->normal = normal; } - void set_specular_exponent(const SpecularExponent& specular_exponent) { this->specular_exponent = specular_exponent; } + void set_material(const Material& material) { this->material = material; } Position position; Normal normal; - SpecularExponent specular_exponent; - }; - - // Other Data Types - - struct Light - { - Light( - const Position& position, - const ColorRGB& ambient, - const ColorRGB& diffuse - ) - : position(position), - ambient(ambient), - diffuse(diffuse) - {} - - Position position; - ColorRGB ambient; - ColorRGB diffuse; + Material material; }; // typedefs for builtin types @@ -74,7 +105,7 @@ namespace charcoal typedef Index BasicIndex; typedef Renderable BasicRenderable; - typedef PNSVertex LitVertex; + typedef PNMVertex LitVertex; typedef Index LitIndex; typedef Renderable LitRenderable; } diff --git a/OpenGLEngine/GLUtil.cpp b/OpenGLEngine/GLUtil.cpp index ac1cddd..e98b188 100644 --- a/OpenGLEngine/GLUtil.cpp +++ b/OpenGLEngine/GLUtil.cpp @@ -40,19 +40,14 @@ namespace charcoal void uniform_lights(int uniform_index, const std::vector& lights) { - const int position_size = 1; - const int ambient_size = 1; - const int diffuse_size = 1; - const int specular_exponent_size = 1; - int current_location = uniform_index; for (std::vector::size_type i = 0; i < lights.size(); ++i) { - glUniform3fv(current_location, 1, &lights[i].position[0]); - current_location += position_size; - glUniform3fv(current_location, 1, &lights[i].ambient[0]); - current_location += ambient_size; - glUniform3fv(current_location, 1, &lights[i].diffuse[0]); - current_location += diffuse_size; + glUniform3fv(uniform_index++, 1, &lights[i].position[0]); + glUniform3fv(uniform_index++, 1, &lights[i].power[0]); + glUniform3fv(uniform_index++, 1, &lights[i].ambient[0]); + glUniform3fv(uniform_index++, 1, &lights[i].diffuse[0]); + glUniform3fv(uniform_index++, 1, &lights[i].specular[0]); + glUniform3fv(uniform_index++, 1, &lights[i].fade[0]); } } } diff --git a/OpenGLEngine/LitBatch.cpp b/OpenGLEngine/LitBatch.cpp index f511ac3..501c977 100644 --- a/OpenGLEngine/LitBatch.cpp +++ b/OpenGLEngine/LitBatch.cpp @@ -12,7 +12,7 @@ namespace charcoal glEnableVertexAttribArray(2); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(LitVertex), (void*)(offsetof(LitVertex, position))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(LitVertex), (void*)(offsetof(LitVertex, normal))); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(LitVertex), (void*)(offsetof(LitVertex, specular_exponent))); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(LitVertex), (void*)(offsetof(LitVertex, material))); glBindBuffer(GL_ARRAY_BUFFER, m_element_buffers[0]); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); diff --git a/OpenGLEngine/LitFS.glsl b/OpenGLEngine/LitFS.glsl index 5ac787a..b4bd0fb 100644 --- a/OpenGLEngine/LitFS.glsl +++ b/OpenGLEngine/LitFS.glsl @@ -1,43 +1,58 @@ #version 430 +struct Fragment +{ + vec3 position; + vec3 normal; + vec4 material; +}; + struct Light { vec3 position; + vec3 power; // x = ambient, y = diffuse, z = specular vec3 ambient; vec3 diffuse; + vec3 specular; + vec3 fade; // x = constant, y = linear, z = quadratic }; -in vec3 fragment_position; -in vec3 fragment_normal; -in float fragment_specular_exponent; +in Fragment fragment; #define MAX_LIGHTS 16 -layout(location = 4) uniform Light lights[MAX_LIGHTS]; -layout(location = 68) uniform uint num_lights; -layout(location = 69) uniform vec3 eye_position; +layout(location = 4) uniform vec3 eye_position; +layout(location = 5) uniform uint num_lights; +layout(location = 6) uniform Light lights[MAX_LIGHTS]; out vec4 frag_color; void main() { - vec3 hard_eye_position = vec3(0.0f, 0.0f, -5.0f); - vec3 norm_normal = normalize(fragment_normal); - vec3 norm_eye_vector = normalize(eye_position - fragment_position); + vec3 accumulator = vec3(0.0); - vec3 accum = vec3(0.0); + vec3 normal = normalize(fragment.normal); + + for (uint i = 0; i < MAX_LIGHTS && i < num_lights; ++i) + { + vec3 to_eye = eye_position - fragment.position; + vec3 to_light = lights[i].position - fragment.position; - float diffuse_multiplier; - float specular_multiplier; - vec3 light_vector; - vec3 reflected_light_vector; - for (uint i = 0; i < MAX_LIGHTS && i < num_lights; ++i) { - light_vector = normalize(lights[i].position - fragment_position); - reflected_light_vector = reflect(-light_vector, norm_normal); - diffuse_multiplier = clamp(dot(light_vector, norm_normal), 0.0, 1.0); - specular_multiplier = pow(clamp(dot(reflected_light_vector, norm_eye_vector), 0.0, 1.0), fragment_specular_exponent); - accum += lights[i].ambient; - accum += diffuse_multiplier * lights[i].diffuse; - accum += specular_multiplier * lights[i].diffuse; + float dist = length(to_light); + vec3 to_light_norm = to_light / dist; // normalize(to_light); + + vec3 reflected = reflect(-to_light_norm, normal); + + float fade = lights[i].fade.x + lights[i].fade.y * dist + lights[i].fade.z * dist * dist; + + // Multipliers + // a = ambient, d = diffuse, s = specular + float a = lights[i].power.x * fragment.material.x / fade; + float d = lights[i].power.y * fragment.material.y / fade * clamp(dot(to_light_norm, normal), 0.0, 1.0); + float s = lights[i].power.z * fragment.material.z / fade * pow(clamp(dot(reflected, normal), 0.0, 1.0), clamp(fragment.material.w, 1.0, 1000.0)); // Seems like weird things happen if w is set to 0 and not clamped (maybe it is not exactly 0) + + vec3 color = a * lights[i].ambient + d * lights[i].diffuse + s * lights[i].specular; + accumulator += color; } - frag_color = vec4(accum, 1.0); + + frag_color = vec4(accumulator, 1.0); } \ No newline at end of file diff --git a/OpenGLEngine/LitScene.cpp b/OpenGLEngine/LitScene.cpp index e634720..a1e03db 100644 --- a/OpenGLEngine/LitScene.cpp +++ b/OpenGLEngine/LitScene.cpp @@ -35,22 +35,15 @@ namespace charcoal void LitScene::render() { glutil::clear_screen(); - CHECK_GL_ERR(); m_shader_program.use(); - CHECK_GL_ERR(); glutil::uniform_matrix(0, m_p_camera->get_world_to_view_matrix()); - CHECK_GL_ERR(); - glutil::uniform_lights(4, m_lights); - CHECK_GL_ERR(); - glutil::uniform_uint(68, (unsigned int)m_lights.size()); - CHECK_GL_ERR(); - glutil::uniform_vec3(69, m_p_camera->get_position()); - CHECK_GL_ERR(); + glutil::uniform_vec3(4, m_p_camera->get_position()); + glutil::uniform_uint(5, (unsigned int)m_lights.size()); + glutil::uniform_lights(6, m_lights); for (auto iter = m_batches.begin(); iter != m_batches.end(); ++iter) { iter->render(); } - CHECK_GL_ERR(); } } } \ No newline at end of file diff --git a/OpenGLEngine/LitScene.h b/OpenGLEngine/LitScene.h index 511fec8..bbe499c 100644 --- a/OpenGLEngine/LitScene.h +++ b/OpenGLEngine/LitScene.h @@ -13,6 +13,7 @@ namespace charcoal { namespace builtin { + // A scene lit by the Phong Reflection Model (See https://en.wikipedia.org/wiki/Phong_reflection_model ) class LitScene : public AutoPrerenderingScene, public Batched { public: @@ -30,13 +31,17 @@ namespace charcoal protected: void set_camera(const Camera* p_camera) { m_p_camera = p_camera; } - void add_light( + Light& add_light( const Position& position, - const ColorRGB& ambient, - const ColorRGB& diffuse + const Light::Power& power, + const ColorRGB ambient, + const ColorRGB diffuse, + const ColorRGB specular, + const Light::Fade& fade ) { - m_lights.emplace_back(position, ambient, diffuse); + m_lights.emplace_back(position, power, ambient, diffuse, specular, fade); + return m_lights.back(); } private: diff --git a/OpenGLEngine/LitVS.glsl b/OpenGLEngine/LitVS.glsl index 17a06a4..e9a90ba 100644 --- a/OpenGLEngine/LitVS.glsl +++ b/OpenGLEngine/LitVS.glsl @@ -1,21 +1,32 @@ #version 430 -layout(location = 0) in vec3 vertex_position; -layout(location = 1) in vec3 vertex_normal; -layout(location = 2) in float vertex_specular_exponent; + +struct Vertex +{ + vec3 position; + vec3 normal; + vec4 material; +}; + +struct Fragment +{ + vec3 position; + vec3 normal; + vec4 material; +}; + +layout(location = 0) in Vertex vertex; layout(location = 3) in mat4 model_to_world; layout(location = 0) uniform mat4 world_to_projection; -out vec3 fragment_position; -out vec3 fragment_normal; -out float fragment_specular_exponent; +out Fragment fragment; void main() { - vec4 model_position = model_to_world * vec4(vertex_position, 1.0); - vec4 model_normal = model_to_world * vec4(vertex_normal, 0.0); + vec4 model_position = model_to_world * vec4(vertex.position, 1.0); + vec4 model_normal = model_to_world * vec4(vertex.normal, 0.0); gl_Position = world_to_projection * model_position; - fragment_position = model_position.xyz; - fragment_normal = model_normal.xyz; - fragment_specular_exponent = vertex_specular_exponent; + fragment.position = model_position.xyz; + fragment.normal = model_normal.xyz; + fragment.material = vertex.material; } \ No newline at end of file diff --git a/OpenGLEngine/MeshGenerator.h b/OpenGLEngine/MeshGenerator.h index da31ecf..2ee1a3e 100644 --- a/OpenGLEngine/MeshGenerator.h +++ b/OpenGLEngine/MeshGenerator.h @@ -16,11 +16,11 @@ namespace charcoal namespace meshgenerator { template - Mesh* apply_specular_exponent(Mesh* mesh, const SpecularExponent& specular_exponent) + Mesh* set_material(Mesh* mesh, const Material& material) { for (unsigned int i = 0; i < mesh->vertex_count; ++i) { - mesh->vertices[i].set_specular_exponent(specular_exponent); + mesh->vertices[i].set_material(material); } return mesh; } diff --git a/OpenGLEngine/MyBuiltinLitScene.cpp b/OpenGLEngine/MyBuiltinLitScene.cpp index 5552143..9edef45 100644 --- a/OpenGLEngine/MyBuiltinLitScene.cpp +++ b/OpenGLEngine/MyBuiltinLitScene.cpp @@ -7,9 +7,9 @@ MyBuiltinLitScene::MyBuiltinLitScene(Application& application) : LitScene(application), m_shape( - meshgenerator::apply_specular_exponent( + meshgenerator::set_material( meshgenerator::gen_cube_pn(DRAW_TRIANGLES, 2.0f, 2.0f, 2.0f), - 2 + Material(1.0f, 1.0f, 0.2f, 1.0f) ), DrawMode::DRAW_TRIANGLES ), m_camera((float)TAU_1_4, (float)m_screen_size.x / m_screen_size.y, 1.0f, 10.0f, vec3(0.0f, 0.0f, -5.0f)), @@ -18,8 +18,14 @@ MyBuiltinLitScene::MyBuiltinLitScene(Application& application) add_prerenderable(&m_camera); set_camera(&m_camera); - // Something is off here... The light seems to be rotating... - add_light(Position(0.0f, 2.0f, -2.0f), ColorRGB(0.2f, 0.2f, 0.2f), ColorRGB(1.0f, 1.0f, 1.0f)); + add_light( + Position(0.0f, 2.0f, -2.0f), + Light::Power(0.2f, 1.0f, 1.0f), + ColorRGB(1.0f, 1.0f, 1.0f), + ColorRGB(1.0f, 1.0f, 1.0f), + ColorRGB(1.0f, 1.0f, 1.0f), + Light::Fade(1.0f, 0.1f, 0.01f) + ); } void MyBuiltinLitScene::update(float delta_time, clock_t clock) @@ -40,7 +46,7 @@ void MyBuiltinLitScene::update(float delta_time, clock_t clock) { Poseable& pose = m_batch.get_pose(0); - pose.rotate(glm::normalize(vec3(1.0f, 1.0f, 0.0f)), (float)TAU_1_2 * delta_time); + pose.rotate(glm::normalize(vec3(1.0f, 1.0f, 0.0f)), (float)TAU_1_8 * delta_time); pose.update_position(vec3(3 * (float)cos(radians), 0.0f, 0.0f)); }