MetaCore/Source/MetaCoreRender/Private/MetaCoreSceneRenderer.cpp
2026-03-20 10:39:34 +08:00

210 lines
6.7 KiB
C++

#include "MetaCoreRender/MetaCoreSceneRenderer.h"
#include "MetaCoreRender/MetaCoreDebugGeometry.h"
#include "MetaCoreRender/MetaCoreShaderProgram.h"
#include "MetaCoreScene/MetaCoreScene.h"
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <memory>
#include <string>
namespace MetaCore {
class MetaCoreSceneRenderer::MetaCoreSceneRendererImpl {
public:
MetaCoreDebugGeometry DebugGeometry{};
MetaCoreShaderProgram LineShader{};
MetaCoreShaderProgram LitShader{};
};
namespace {
glm::mat4 MetaCoreBuildTransformMatrix(const MetaCoreTransformComponent& transform) {
glm::mat4 model(1.0F);
model = glm::translate(model, transform.Position);
model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.x), glm::vec3(1.0F, 0.0F, 0.0F));
model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.y), glm::vec3(0.0F, 1.0F, 0.0F));
model = glm::rotate(model, glm::radians(transform.RotationEulerDegrees.z), glm::vec3(0.0F, 0.0F, 1.0F));
model = glm::scale(model, transform.Scale);
return model;
}
glm::vec3 MetaCoreResolveLightDirection(const MetaCoreScene& scene) {
for (const MetaCoreGameObject& object : scene.GetGameObjects()) {
if (object.Light.has_value()) {
glm::mat4 rotation(1.0F);
rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.x), glm::vec3(1.0F, 0.0F, 0.0F));
rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.y), glm::vec3(0.0F, 1.0F, 0.0F));
rotation = glm::rotate(rotation, glm::radians(object.Transform.RotationEulerDegrees.z), glm::vec3(0.0F, 0.0F, 1.0F));
return glm::normalize(glm::vec3(rotation * glm::vec4(0.15F, -1.0F, -0.35F, 0.0F)));
}
}
return glm::normalize(glm::vec3(0.15F, -1.0F, -0.35F));
}
float MetaCoreResolveLightIntensity(const MetaCoreScene& scene) {
for (const MetaCoreGameObject& object : scene.GetGameObjects()) {
if (object.Light.has_value()) {
return object.Light->Intensity;
}
}
return 1.5F;
}
glm::vec3 MetaCoreResolveLightColor(const MetaCoreScene& scene) {
for (const MetaCoreGameObject& object : scene.GetGameObjects()) {
if (object.Light.has_value()) {
return object.Light->Color;
}
}
return glm::vec3(1.0F, 1.0F, 1.0F);
}
} // namespace
bool MetaCoreSceneRenderer::Initialize() {
Shutdown();
Impl_ = new MetaCoreSceneRendererImpl();
if (!Impl_->DebugGeometry.Initialize()) {
Shutdown();
return false;
}
std::string errorMessage;
const std::string lineVertexShader = R"(
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 2) in vec4 aColor;
uniform mat4 uView;
uniform mat4 uProjection;
uniform mat4 uModel;
out vec4 vColor;
void main() {
vColor = aColor;
gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0);
}
)";
const std::string lineFragmentShader = R"(
#version 330 core
in vec4 vColor;
out vec4 FragColor;
void main() {
FragColor = vColor;
}
)";
const std::string litVertexShader = R"(
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
uniform mat4 uView;
uniform mat4 uProjection;
uniform mat4 uModel;
out vec3 vWorldPosition;
out vec3 vWorldNormal;
void main() {
vec4 worldPosition = uModel * vec4(aPosition, 1.0);
vWorldPosition = worldPosition.xyz;
vWorldNormal = normalize(mat3(transpose(inverse(uModel))) * aNormal);
gl_Position = uProjection * uView * worldPosition;
}
)";
const std::string litFragmentShader = R"(
#version 330 core
in vec3 vWorldPosition;
in vec3 vWorldNormal;
uniform vec3 uBaseColor;
uniform vec3 uLightDirection;
uniform vec3 uLightColor;
uniform float uLightIntensity;
out vec4 FragColor;
void main() {
vec3 normal = normalize(vWorldNormal);
vec3 lightDirection = normalize(-uLightDirection);
float diffuse = max(dot(normal, lightDirection), 0.0);
vec3 ambient = uBaseColor * 0.28;
vec3 lighting = ambient + (uBaseColor * uLightColor * diffuse * uLightIntensity);
FragColor = vec4(lighting, 1.0);
}
)";
if (!Impl_->LineShader.BuildFromSource(lineVertexShader, lineFragmentShader, errorMessage)) {
Shutdown();
return false;
}
if (!Impl_->LitShader.BuildFromSource(litVertexShader, litFragmentShader, errorMessage)) {
Shutdown();
return false;
}
return true;
}
void MetaCoreSceneRenderer::Shutdown() {
if (Impl_ != nullptr) {
Impl_->DebugGeometry.Shutdown();
Impl_->LineShader.Shutdown();
Impl_->LitShader.Shutdown();
delete Impl_;
Impl_ = nullptr;
}
}
void MetaCoreSceneRenderer::RenderScene(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView) const {
if (Impl_ == nullptr) {
return;
}
Impl_->LineShader.Bind();
Impl_->LineShader.SetMatrix4("uView", sceneView.ViewMatrix);
Impl_->LineShader.SetMatrix4("uProjection", sceneView.ProjectionMatrix);
Impl_->LineShader.SetMatrix4("uModel", glm::mat4(1.0F));
Impl_->DebugGeometry.GetGridMesh().Draw();
Impl_->DebugGeometry.GetAxesMesh().Draw();
const glm::vec3 lightDirection = MetaCoreResolveLightDirection(scene);
const glm::vec3 lightColor = MetaCoreResolveLightColor(scene);
const float lightIntensity = MetaCoreResolveLightIntensity(scene);
Impl_->LitShader.Bind();
Impl_->LitShader.SetMatrix4("uView", sceneView.ViewMatrix);
Impl_->LitShader.SetMatrix4("uProjection", sceneView.ProjectionMatrix);
Impl_->LitShader.SetVector3("uLightDirection", lightDirection);
Impl_->LitShader.SetVector3("uLightColor", lightColor);
Impl_->LitShader.SetFloat("uLightIntensity", lightIntensity);
for (const MetaCoreGameObject& object : scene.GetGameObjects()) {
if (!object.MeshRenderer.has_value() || !object.MeshRenderer->Visible) {
continue;
}
glm::vec3 baseColor = object.MeshRenderer->BaseColor;
if (object.Id == sceneView.SelectedObjectId) {
baseColor = glm::mix(baseColor, glm::vec3(1.0F, 0.62F, 0.18F), 0.55F);
}
Impl_->LitShader.SetMatrix4("uModel", MetaCoreBuildTransformMatrix(object.Transform));
Impl_->LitShader.SetVector3("uBaseColor", baseColor);
Impl_->DebugGeometry.GetCubeMesh().Draw();
}
}
} // namespace MetaCore