1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 01:37:35 +00:00

LibGL+LibSoftGPU: Implement glColorMaterial and GL_COLOR_MATERIAL

When `GL_COLOR_MATERIAL` is enabled, specific material parameters can
be overwritten by the current color per-vertex during the lighting
calculations. Which parameter is controlled by `glColorMaterial`.

Also move the lighting calculations _before_ clipping, because the spec
says so. As a result, we interpolate the resulting vertex color instead
of the input color.
This commit is contained in:
Jelle Raaijmakers 2022-01-13 03:03:35 +01:00 committed by Andreas Kling
parent 9d4c2f6308
commit 8e935ad3b1
8 changed files with 158 additions and 35 deletions

View file

@ -644,35 +644,38 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const&
triangle.vertices[1].normal = transform_direction(model_view_transform, triangle.vertices[1].normal);
triangle.vertices[2].normal = transform_direction(model_view_transform, triangle.vertices[2].normal);
// Transform eye coordinates into clip coordinates using the projection transform
triangle.vertices[0].clip_coordinates = projection_transform * triangle.vertices[0].eye_coordinates;
triangle.vertices[1].clip_coordinates = projection_transform * triangle.vertices[1].eye_coordinates;
triangle.vertices[2].clip_coordinates = projection_transform * triangle.vertices[2].eye_coordinates;
// At this point, we're in clip space
// Here's where we do the clipping. This is a really crude implementation of the
// https://learnopengl.com/Getting-started/Coordinate-Systems
// "Note that if only a part of a primitive e.g. a triangle is outside the clipping volume OpenGL
// will reconstruct the triangle as one or more triangles to fit inside the clipping range. "
//
// ALL VERTICES ARE DEFINED IN A CLOCKWISE ORDER
// Okay, let's do some face culling first
m_clipped_vertices.clear_with_capacity();
m_clipped_vertices.append(triangle.vertices[0]);
m_clipped_vertices.append(triangle.vertices[1]);
m_clipped_vertices.append(triangle.vertices[2]);
m_clipper.clip_triangle_against_frustum(m_clipped_vertices);
if (m_clipped_vertices.size() < 3)
continue;
// Calculate per-vertex lighting
if (m_options.lighting_enabled) {
auto const& front_material = m_materials.at(0);
// Walk through each vertex
for (auto& vertex : m_clipped_vertices) {
FloatVector4 result_color = front_material.emissive + (front_material.ambient * m_lighting_model.scene_ambient_color);
auto const& material = m_materials.at(0);
for (auto& vertex : triangle.vertices) {
auto ambient = material.ambient;
auto diffuse = material.diffuse;
auto emissive = material.emissive;
auto specular = material.specular;
if (m_options.color_material_enabled
&& (m_options.color_material_face == ColorMaterialFace::Front || m_options.color_material_face == ColorMaterialFace::FrontAndBack)) {
switch (m_options.color_material_mode) {
case ColorMaterialMode::Ambient:
ambient = vertex.color;
break;
case ColorMaterialMode::AmbientAndDiffuse:
ambient = vertex.color;
diffuse = vertex.color;
break;
case ColorMaterialMode::Diffuse:
diffuse = vertex.color;
break;
case ColorMaterialMode::Emissive:
emissive = vertex.color;
break;
case ColorMaterialMode::Specular:
specular = vertex.color;
break;
}
}
FloatVector4 result_color = emissive + (ambient * m_lighting_model.scene_ambient_color);
for (auto const& light : m_lights) {
if (!light.is_enabled)
@ -716,11 +719,11 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const&
(void)m_lighting_model.two_sided_lighting;
// Ambient
auto const ambient_component = front_material.ambient * light.ambient_intensity;
auto const ambient_component = ambient * light.ambient_intensity;
// Diffuse
auto const normal_dot_vertex_to_light = vertex.normal.dot(FloatVector3(vertex_to_light.x(), vertex_to_light.y(), vertex_to_light.z()));
auto const diffuse_component = ((front_material.diffuse * light.diffuse_intensity) * normal_dot_vertex_to_light).clamped(0.0f, 1.0f);
auto const diffuse_component = ((diffuse * light.diffuse_intensity) * normal_dot_vertex_to_light).clamped(0.0f, 1.0f);
FloatVector4 color = ambient_component;
color += diffuse_component;
@ -729,11 +732,35 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const&
}
vertex.color = result_color;
vertex.color.set_w(front_material.diffuse.w()); // OpenGL 1.5 spec, page 59: "The A produced by lighting is the alpha value associated with diffuse color material"
vertex.color.set_w(diffuse.w()); // OpenGL 1.5 spec, page 59: "The A produced by lighting is the alpha value associated with diffuse color material"
vertex.color.clamp(0.0f, 1.0f);
}
}
// Transform eye coordinates into clip coordinates using the projection transform
triangle.vertices[0].clip_coordinates = projection_transform * triangle.vertices[0].eye_coordinates;
triangle.vertices[1].clip_coordinates = projection_transform * triangle.vertices[1].eye_coordinates;
triangle.vertices[2].clip_coordinates = projection_transform * triangle.vertices[2].eye_coordinates;
// At this point, we're in clip space
// Here's where we do the clipping. This is a really crude implementation of the
// https://learnopengl.com/Getting-started/Coordinate-Systems
// "Note that if only a part of a primitive e.g. a triangle is outside the clipping volume OpenGL
// will reconstruct the triangle as one or more triangles to fit inside the clipping range. "
//
// ALL VERTICES ARE DEFINED IN A CLOCKWISE ORDER
// Okay, let's do some face culling first
m_clipped_vertices.clear_with_capacity();
m_clipped_vertices.append(triangle.vertices[0]);
m_clipped_vertices.append(triangle.vertices[1]);
m_clipped_vertices.append(triangle.vertices[2]);
m_clipper.clip_triangle_against_frustum(m_clipped_vertices);
if (m_clipped_vertices.size() < 3)
continue;
for (auto& vec : m_clipped_vertices) {
// To normalized device coordinates (NDC)
auto const one_over_w = 1 / vec.clip_coordinates.w();