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.
This commit is contained in:
elipzer 2018-09-15 03:46:42 -04:00
parent 5200ba4dbe
commit 1eea92a3af
9 changed files with 147 additions and 91 deletions

View File

@ -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<BasicVertex, BasicIndex> BasicRenderable;
typedef PNSVertex LitVertex;
typedef PNMVertex LitVertex;
typedef Index LitIndex;
typedef Renderable<LitVertex, LitIndex> LitRenderable;
}

View File

@ -40,19 +40,14 @@ namespace charcoal
void uniform_lights(int uniform_index, const std::vector<Light>& 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<Light>::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]);
}
}
}

View File

@ -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);

View File

@ -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);
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;
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 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);
}

View File

@ -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();
}
}
}

View File

@ -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<LitRenderable, LitBatch>
{
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:

View File

@ -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;
}

View File

@ -16,11 +16,11 @@ namespace charcoal
namespace meshgenerator
{
template <typename VertexType, typename IndexType>
Mesh<VertexType, IndexType>* apply_specular_exponent(Mesh<VertexType, IndexType>* mesh, const SpecularExponent& specular_exponent)
Mesh<VertexType, IndexType>* set_material(Mesh<VertexType, IndexType>* 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;
}

View File

@ -7,9 +7,9 @@
MyBuiltinLitScene::MyBuiltinLitScene(Application& application)
: LitScene(application),
m_shape(
meshgenerator::apply_specular_exponent<LitVertex, LitIndex>(
meshgenerator::set_material<LitVertex, LitIndex>(
meshgenerator::gen_cube_pn<LitVertex, LitIndex>(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));
}