Materials.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m18s

This commit is contained in:
2024-12-16 22:25:36 -05:00
parent 7f5ee5cf0c
commit e33a51b7d4
5 changed files with 111 additions and 65 deletions

View File

@@ -13,14 +13,17 @@ namespace JGL {
class JGL::LightBase {
protected:
/* The 4th number represents whether the light is a positional light.
* In OpenGL, You can have positional lights, Like Point Lights or Spot Lights,
* Or global lights, Like the sun. */
Vector4 position = {0, 0, 0, 1};
Color4 ambient = {0, 0, 0, 0};
Color4 diffuse = {0, 0, 0, 0};
Color4 specular = {0, 0, 0, 0};
float constant_attenuation;
float linear_attenuation;
float quadratic_attenuation;
float constant_attenuation = 1;
float linear_attenuation = 0;
float quadratic_attenuation = 0;
public:
[[nodiscard]] Vector4 GetPosition() const;
[[nodiscard]] Color4 GetAmbient() const;

View File

@@ -1,4 +1,19 @@
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
class Material {
#include <Color4.hpp>
#include <glad/glad.h>
namespace JGL {
class Material;
}
class JGL::Material {
public:
Color4 ambient_ref;
Color4 diffuse_ref;
Color4 specular_ref;
Color4 emission;
float shininess;
public:
Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine);
/// @param material Material to use.
static void SetActiveMaterial(const Material& material);
};

View File

@@ -0,0 +1,54 @@
#include "internals.h"
#include <J3ML/LinearAlgebra/Vector4.hpp>
#include <JGL/types/Light.h>
// TODO handle the case that a required light is in the list of optional lights.
void JGL::J3D::SelectLights(const Vector3& position) {
std::array<const LightBase*, 8> result = required_lights;
unsigned int required_light_count = 0;
for (const auto& i : result)
if (i) required_light_count++;
// If there is optional lights.
if (!optional_lights.empty()) {
// The number of lights we need to solve for
unsigned int remaining_lights = 8 - required_light_count;
std::vector<std::pair<float, const LightBase*>> light_influence;
for (const auto* light: optional_lights)
light_influence.emplace_back(light->GetAttenuationAtPosition(position), light);
// Sort by biggest influence.
std::sort(light_influence.begin(), light_influence.end(),
[](const auto &a, const auto &b) { return a.first > b.first; });
// Add in optional lights.
for (unsigned int i = 0; i < remaining_lights && i < light_influence.size(); i++)
result[required_light_count++] = light_influence[i].second;
}
for (unsigned int i = 0; i < result.size(); i++) {
// Terminate early if we have less than 8 lights.
if (!result[i])
break;
Vector4 ambient = { result[i]->GetAmbient().RN(), result[i]->GetAmbient().BN(), result[i]->GetAmbient().GN(), result[i]->GetAmbient().AN() };
Vector4 diffuse = { result[i]->GetDiffuse().RN(), result[i]->GetDiffuse().BN(), result[i]->GetDiffuse().GN(), result[i]->GetDiffuse().AN() };
Vector4 specular = { result[i]->GetSpecular().RN(), result[i]->GetSpecular().BN(), result[i]->GetSpecular().GN(), result[i]->GetSpecular().AN() };
GLenum current_light = GL_LIGHT0 + i;
glEnable(GL_LIGHT0 + i);
// How the light will affect different materials.
glLightfv(current_light, GL_POSITION, result[i]->GetPosition().ptr());
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
glLightfv(current_light, GL_DIFFUSE, diffuse.ptr());
glLightfv(current_light, GL_SPECULAR, specular.ptr());
// How far the light goes.
glLightf(current_light, GL_CONSTANT_ATTENUATION, result[i]->GetConstantAttenuation());
glLightf(current_light, GL_LINEAR_ATTENUATION, result[i]->GetLinearAttenuation());
glLightf(current_light, GL_QUADRATIC_ATTENUATION, result[i]->GetQuadraticAttenuation());
}
}

View File

@@ -1,9 +1,11 @@
/// Things used in J2D and J3D that should not be exposed to the user of the library.
#pragma once
#include <glad/glad.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <JGL/types/RenderTarget.h>
#include <JGL/types/Light.h>
#include <JGL/logger/logger.h>
#include <glad/glad.h>
namespace JGL {
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
@@ -45,64 +47,5 @@ namespace JGL::J3D {
inline std::vector<const LightBase*> optional_lights;
inline float far_plane = 0;
inline float fov = 0;
// TODO handle the case that a required light is in the list of optional lights.
inline void SelectLights(const Vector3& position) {
std::array<const LightBase*, 8> result = {};
unsigned int required_light_count = 0;
for (const auto* light : required_lights)
if (light)
result[required_light_count++] = light;
else
break;
// If there is optional lights.
if (!optional_lights.empty()) {
// The number of lights we need to solve for
unsigned int remaining_lights = 8 - required_light_count;
std::vector<std::pair<float, const LightBase*>> light_influence;
for (const auto* light: optional_lights) {
float influence = 0.0f;
if (auto *point_light = dynamic_cast<const PointLight*>(light))
influence = point_light->GetAttenuationAtPosition(position);
else if (auto *spot_light = dynamic_cast<const SpotLight*>(light))
influence = spot_light->GetAttenuationAtPosition(position);
else
Logger::Warning("Couldn't determine the light type.");
light_influence.emplace_back(influence, light);
}
// Sort by biggest influence.
std::sort(light_influence.begin(), light_influence.end(),
[](const auto &a, const auto &b) { return a.first > b.first; });
// Add in optional lights.
for (unsigned int i = 0; i < remaining_lights && i < light_influence.size(); i++)
result[required_light_count++] = light_influence[i].second;
}
for (unsigned int i = 0; i < result.size(); i++) {
// If we've reached the end of an array with less than 8 lights.
if (i > required_light_count)
break;
Vector4 ambient = { result[i]->GetAmbient().RN(), result[i]->GetAmbient().BN(), result[i]->GetAmbient().GN(), result[i]->GetAmbient().AN() };
Vector4 diffuse = { result[i]->GetDiffuse().RN(), result[i]->GetDiffuse().BN(), result[i]->GetDiffuse().GN(), result[i]->GetDiffuse().AN() };
Vector4 specular = { result[i]->GetSpecular().RN(), result[i]->GetSpecular().BN(), result[i]->GetSpecular().GN(), result[i]->GetSpecular().AN() };
GLenum current_light = GL_LIGHT0 + i;
glEnable(GL_LIGHT0 + i);
glLightfv(current_light, GL_POSITION, result[i]->GetPosition().ptr());
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
glLightfv(current_light, GL_DIFFUSE, diffuse.ptr());
glLightfv(current_light, GL_SPECULAR, specular.ptr());
}
}
void SelectLights(const Vector3& position);
}

View File

@@ -0,0 +1,31 @@
#include <JGL/types/Material.h>
#include <J3ML/LinearAlgebra/Vector4.hpp>
JGL::Material::Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine) {
ambient_ref = ambient_reflection;
diffuse_ref = diffuse_reflection;
specular_ref = specular_reflection;
emission = light_emission;
shininess = shine;
}
void JGL::Material::SetActiveMaterial(const Material& material) {
Vector4 ambient = { material.ambient_ref.RN(), material.ambient_ref.BN(), material.ambient_ref.GN(), material.ambient_ref.AN() };
Vector4 diffuse = { material.diffuse_ref.RN(), material.diffuse_ref.BN(), material.diffuse_ref.GN(), material.diffuse_ref.AN() };
Vector4 specular = { material.specular_ref.RN(), material.specular_ref.BN(), material.specular_ref.GN(), material.specular_ref.AN() };
Vector4 emission = { material.emission.RN(), material.emission.BN(), material.emission.GN(), material.emission.AN() };
// Determine which faces we're going to apply this material to.
GLenum face = GL_FRONT;
if (glIsEnabled(GL_CULL_FACE)) {
GLint current; glGetIntegerv(GL_CULL_FACE_MODE, &current);
if (current == GL_FRONT)
face = GL_BACK;
}
glMaterialfv(face, GL_AMBIENT, ambient.ptr());
glMaterialfv(face, GL_DIFFUSE, diffuse.ptr());
glMaterialfv(face, GL_SPECULAR, specular.ptr());
glMaterialfv(face, GL_EMISSION, emission.ptr());
glMaterialf(face, GL_SHININESS, material.shininess);
}