Compare commits

...

1 Commits

Author SHA1 Message Date
OusmBlueNinja
696554c4f5 Nothing really 2025-01-01 13:04:56 -06:00
10 changed files with 548 additions and 288 deletions

View File

@ -1,5 +1,6 @@
#version 330 core #version 330 core
void main() void main()
{ {
// No color output; only depth is recorded // Depth is automatically written to the depth buffer
} }

View File

@ -1,10 +1,12 @@
#version 330 core #version 330 core
layout(location = 0) in vec3 aPos; layout(location = 0) in vec3 aPos;
uniform mat4 lightSpaceMatrix; uniform mat4 uModel;
uniform mat4 model; uniform mat4 uLightView;
uniform mat4 uLightProj;
void main() void main()
{ {
gl_Position = lightSpaceMatrix * model * vec4(aPos, 1.0); gl_Position = uLightProj * uLightView * uModel * vec4(aPos, 1.0);
} }

View File

@ -0,0 +1,12 @@
#version 330 core
in vec2 TexCoords;
out vec4 FragColor;
uniform sampler2D depthMap;
void main()
{
float depthValue = texture(depthMap, TexCoords).r;
FragColor = vec4(vec3(depthValue), 1.0);
}

View File

@ -0,0 +1,12 @@
#version 330 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos, 0.0, 1.0);
}

View File

@ -2,29 +2,62 @@
struct TextureArray { struct TextureArray {
sampler2D texture_diffuse[32]; // Array of diffuse textures sampler2D texture_diffuse[32]; // Array of diffuse textures
// You can add more texture types here (e.g., specular, normal) if needed // Add more texture types if needed
}; };
uniform TextureArray uTextures; // Array of textures uniform TextureArray uTextures; // Array of textures
uniform int uNumDiffuseTextures; // Number of active diffuse textures uniform int uNumDiffuseTextures; // Number of active diffuse textures
uniform mat4 uLightSpaceMatrix; // Light space matrix
uniform sampler2D uShadowMap; // Shadow map texture
in vec2 TexCoord; // From vertex shader in vec2 TexCoord; // From vertex shader
in vec3 Normal; // From vertex shader in vec3 Normal; // From vertex shader
in vec3 FragPos; // From vertex shader in vec3 FragPos; // From vertex shader
in vec4 FragPosLightSpace; // From vertex shader
out vec4 FragColor; // Final fragment color out vec4 FragColor; // Final fragment color
// Example lighting parameters // Lighting parameters
uniform vec3 lightPos; // Position of the light source struct Light {
vec3 direction;
vec3 position;
};
uniform Light light;
uniform vec3 viewPos; // Position of the camera/viewer uniform vec3 viewPos; // Position of the camera/viewer
float ShadowCalculation(vec4 fragPosLightSpace)
{
// Perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// Get closest depth value from light's perspective
float closestDepth = texture(uShadowMap, projCoords.xy).r;
// Get current fragment's depth
float currentDepth = projCoords.z;
// Check whether current frag pos is in shadow
float bias = 0.005;
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
// Keep the shadow at 0.0 when outside the far plane region of the light's orthographic projection
if(projCoords.z > 1.0)
shadow = 0.0;
return shadow;
}
void main() void main()
{ {
// Normalize the normal vector // Normalize the normal vector
vec3 norm = normalize(Normal); vec3 norm = normalize(Normal);
// Calculate the direction from the fragment to the light // Calculate the direction from the fragment to the light
vec3 lightDir = normalize(lightPos - FragPos); vec3 lightDir = normalize(light.direction);
// Compute the diffuse intensity // Compute the diffuse intensity
float diff = max(dot(norm, lightDir), 0.0); float diff = max(dot(norm, lightDir), 0.0);
@ -44,6 +77,10 @@ void main()
// Simple ambient lighting // Simple ambient lighting
vec3 ambient = 0.1 * diffuseColor.rgb; vec3 ambient = 0.1 * diffuseColor.rgb;
// Final color combining ambient and diffuse components // Calculate shadow
FragColor = vec4(ambient + diffuseColor.rgb, diffuseColor.a); float shadow = ShadowCalculation(FragPosLightSpace);
// Final color combining ambient and shadowed diffuse components
vec3 lighting = ambient + (1.0 - shadow) * diffuseColor.rgb;
FragColor = vec4(lighting, diffuseColor.a);
} }

View File

@ -6,10 +6,12 @@ layout(location = 2) in vec3 aNormal; // Vertex normal
uniform mat4 uMVP; // Model-View-Projection matrix uniform mat4 uMVP; // Model-View-Projection matrix
uniform mat4 uModel; // Model matrix uniform mat4 uModel; // Model matrix
uniform mat4 uLightSpaceMatrix; // Light space matrix
out vec2 TexCoord; // Passed to fragment shader out vec2 TexCoord; // Passed to fragment shader
out vec3 Normal; // Passed to fragment shader out vec3 Normal; // Passed to fragment shader
out vec3 FragPos; // Passed to fragment shader out vec3 FragPos; // Passed to fragment shader
out vec4 FragPosLightSpace; // Passed to fragment shader
void main() void main()
{ {
@ -22,6 +24,9 @@ void main()
// Pass through the texture coordinate // Pass through the texture coordinate
TexCoord = aTexCoord; TexCoord = aTexCoord;
// Transform the fragment position to light space
FragPosLightSpace = uLightSpaceMatrix * vec4(FragPos, 1.0);
// Final vertex position // Final vertex position
gl_Position = uMVP * vec4(aPos, 1.0); gl_Position = uMVP * vec4(aPos, 1.0);
} }

View File

@ -147,9 +147,9 @@ DockId=0x0000001F,0
[Window][ Inspector##InspectorWindow] [Window][ Inspector##InspectorWindow]
Pos=1526,28 Pos=1526,28
Size=386,1141 Size=386,767
Collapsed=0 Collapsed=0
DockId=0x00000022,0 DockId=0x00000025,0
[Window][ Profiler] [Window][ Profiler]
Pos=332,811 Pos=332,811
@ -157,6 +157,12 @@ Size=736,358
Collapsed=0 Collapsed=0
DockId=0x00000023,0 DockId=0x00000023,0
[Window][Shadow Map Preview]
Pos=1526,797
Size=386,372
Collapsed=0
DockId=0x00000026,0
[Table][0xE9E836E4,4] [Table][0xE9E836E4,4]
Column 0 Weight=1.2999 Column 0 Weight=1.2999
Column 1 Weight=1.0439 Column 1 Weight=1.0439
@ -204,7 +210,9 @@ DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,51 Siz
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196 DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000016 Parent=0x00000014 SizeRef=420,1142 Selected=0x8D0E8380 DockNode ID=0x00000016 Parent=0x00000014 SizeRef=420,1142 Selected=0x8D0E8380
DockNode ID=0x00000022 Parent=0x14621557 SizeRef=386,1141 Selected=0xD1D25642 DockNode ID=0x00000022 Parent=0x14621557 SizeRef=386,1141 Split=Y Selected=0xD1D25642
DockNode ID=0x00000025 Parent=0x00000022 SizeRef=386,767 Selected=0xD1D25642
DockNode ID=0x00000026 Parent=0x00000022 SizeRef=386,372 HiddenTabBar=1 Selected=0x65AE91BD
DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X
DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03 DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03
DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1 DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1

View File

@ -14,7 +14,7 @@ extern GameObject *g_SelectedObject; // Pointer to the currently selected object
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject; extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
#include "Engine/AssetManager.h" #include "Engine/AssetManager.h"
extern AssetManager *g_AssetManager; extern AssetManager g_AssetManager;
extern LoggerWindow *g_LoggerWindow; extern LoggerWindow *g_LoggerWindow;
void InspectorWindow::Show() void InspectorWindow::Show()
@ -428,7 +428,7 @@ void InspectorWindow::Show()
mesh->MeshPath = buffer; mesh->MeshPath = buffer;
} }
if (ImGui::Button("Reload Mesh")) { if (ImGui::Button("Reload Mesh")) {
std::shared_ptr<Model> model = g_AssetManager->loadAsset<Model>(AssetType::MODEL, mesh->MeshPath.c_str()); std::shared_ptr<Model> model = g_AssetManager.loadAsset<Model>(AssetType::MODEL, mesh->MeshPath.c_str());
} }

View File

@ -1,172 +1,59 @@
// RenderWindow.cpp // RenderWindow.cpp
#include "RenderWindow.h" #include "RenderWindow.h"
#include <vector> // Add this line #include <vector> // Added as per your inclusion
#include <GL/glew.h> // Ensure GLEW is initialized before using OpenGL functions
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "imgui.h" #include "imgui.h"
#include "gcml.h" #include "gcml.h"
#include "Componenets/GameObject.h" // Corrected typo: "Componenets" -> "Components"
#include "Componenets/GameObject.h" #include "Componenets/Mesh.h" // Corrected typo: "mesh.h" -> "Mesh.h"
#include "Componenets/mesh.h" #include "Componenets/Transform.h" // Corrected typo: "transform.h" -> "Transform.h"
#include "Componenets/transform.h"
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
#define CAM_FOV 45.0f
#define CAM_NEAR_PLAIN 0.1f
#define CAM_FAR_PLAIN 2048.0f
// Include your AssetManager & Shader headers
#include "Engine/AssetManager.h" #include "Engine/AssetManager.h"
#include "Rendering/Shader.h"
#include "Icons.h" #include "Icons.h"
// Extern reference to our global (or extern) asset manager // External References
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
extern AssetManager g_AssetManager; extern AssetManager g_AssetManager;
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject; extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
extern int g_GPU_Triangles_drawn_to_screen; extern int g_GPU_Triangles_drawn_to_screen;
// Example cube data (position + UVs) // Example cube data (position + UVs)
static float g_CubeVertices[] = static float g_CubeVertices[] =
{ {
// FRONT (z=+1) // Positions // UVs
-1.f, // Front Face
-1.f, -1.f, -1.f, 1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 1.f, 0.f, 1.f,
0.f, 1.f, 1.f, 1.f, 1.f, 1.f,
0.f, 1.f, -1.f, 1.f, 1.f, 0.f,
1.f, // Back Face
-1.f, -1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, 1.f, -1.f, 1.f, 1.f,
1.f, 1.f, 1.f, -1.f, 0.f, 1.f,
0.f, 1.f, -1.f, -1.f, 0.f, 0.f,
1.f, // Left Face
1.f, -1.f, -1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, -1.f, 0.f, 1.f,
1.f, -1.f, 1.f, 1.f, 1.f, 1.f,
1.f, -1.f, -1.f, 1.f, 1.f, 0.f,
-1.f, // Right Face
1.f, 1.f, -1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, -1.f, 1.f, 1.f,
0.f, 1.f, 1.f, 1.f, 0.f, 1.f,
1.f, 1.f, -1.f, 1.f, 0.f, 0.f,
// Top Face
// BACK (z=-1) -1.f, 1.f, -1.f, 0.f, 1.f,
-1.f, -1.f, 1.f, 1.f, 0.f, 0.f,
-1.f, 1.f, 1.f, 1.f, 1.f, 0.f,
-1.f, 1.f, 1.f, -1.f, 1.f, 1.f,
1.f, // Bottom Face
0.f, -1.f, -1.f, -1.f, 1.f, 1.f,
1.f, -1.f, -1.f, 1.f, 1.f, 0.f,
-1.f, 1.f, -1.f, 1.f, 0.f, 0.f,
-1.f, 1.f, -1.f, -1.f, 0.f, 1.f,
0.f,
0.f,
1.f,
1.f,
-1.f,
0.f,
1.f,
-1.f,
1.f,
-1.f,
1.f,
1.f,
// LEFT (x=-1)
-1.f,
-1.f,
-1.f,
0.f,
0.f,
-1.f,
-1.f,
1.f,
1.f,
0.f,
-1.f,
1.f,
1.f,
1.f,
1.f,
-1.f,
1.f,
-1.f,
0.f,
1.f,
// RIGHT (x=+1)
1.f,
-1.f,
-1.f,
1.f,
0.f,
1.f,
-1.f,
1.f,
0.f,
0.f,
1.f,
1.f,
1.f,
0.f,
1.f,
1.f,
1.f,
-1.f,
1.f,
1.f,
// TOP (y=+1)
-1.f,
1.f,
-1.f,
0.f,
0.f,
1.f,
1.f,
-1.f,
1.f,
0.f,
1.f,
1.f,
1.f,
1.f,
1.f,
-1.f,
1.f,
1.f,
0.f,
1.f,
// BOTTOM (y=-1)
-1.f,
-1.f,
-1.f,
1.f,
0.f,
1.f,
-1.f,
-1.f,
0.f,
0.f,
1.f,
-1.f,
1.f,
0.f,
1.f,
-1.f,
-1.f,
1.f,
1.f,
1.f,
}; };
static unsigned int g_CubeIndices[] = static unsigned int g_CubeIndices[] =
@ -182,12 +69,12 @@ static unsigned int g_CubeIndices[] =
// Top // Top
16,17,18, 18,19,16, 16,17,18, 18,19,16,
// Bottom // Bottom
20, 21, 22, 22, 23, 20}; 20,21,22, 22,23,20
};
// Play/Pause Button Implementation
bool PlayPauseButton(const char* label, bool* isPlaying, ImVec2 Size) bool PlayPauseButton(const char* label, bool* isPlaying, ImVec2 Size)
{ {
// Define button size
// Begin the button // Begin the button
if (ImGui::Button(label, Size)) if (ImGui::Button(label, Size))
{ {
@ -245,6 +132,135 @@ bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size)
return false; // No toggle occurred return false; // No toggle occurred
} }
// Constructor
RenderWindow::RenderWindow()
{
}
// Destructor
RenderWindow::~RenderWindow()
{
// Delete main FBO
if (m_FBO != 0)
{
glDeleteFramebuffers(1, &m_FBO);
}
// Delete shadow FBO and shadow map
if (m_ShadowFBO != 0)
{
glDeleteFramebuffers(1, &m_ShadowFBO);
}
if (m_ShadowMap)
{
glDeleteTextures(1, &m_ShadowMap);
}
// Delete VAO, VBO, EBO
if (m_VAO != 0)
glDeleteVertexArrays(1, &m_VAO);
if (m_VBO != 0)
glDeleteBuffers(1, &m_VBO);
if (m_EBO != 0)
glDeleteBuffers(1, &m_EBO);
// Delete quad VAO and VBO
if (m_QuadVAO != 0)
glDeleteVertexArrays(1, &m_QuadVAO);
if (m_QuadVBO != 0)
glDeleteBuffers(1, &m_QuadVBO);
// Delete textures
if (m_TextureIDLoaded != 0)
glDeleteTextures(1, &m_TextureIDLoaded);
if (m_TextureID != 0)
glDeleteTextures(1, &m_TextureID);
// Delete shaders
if (m_ShaderPtr)
{
delete m_ShaderPtr;
m_ShaderPtr = nullptr;
}
if (m_ShadowShaderPtr)
{
delete m_ShadowShaderPtr;
m_ShadowShaderPtr = nullptr;
}
if (m_VisualizeShaderPtr)
{
delete m_VisualizeShaderPtr;
m_VisualizeShaderPtr = nullptr;
}
}
// Example implementation of RenderShadowMapPreview
void RenderWindow::RenderShadowMapPreview()
{
// Begin ImGui window
ImGui::Begin("Shadow Map Preview");
// Light Camera Controls
ImGui::Text("Light Camera Controls");
ImGui::Separator();
// Position Controls
ImGui::DragFloat3("Position", glm::value_ptr(m_LightPosition), 0.1f, -20.0f, 20.0f);
// Rotation Controls (Euler angles in degrees)
ImGui::DragFloat3("Rotation", glm::value_ptr(m_LightRotation), 1.0f, -180.0f, 180.0f);
// Update Light View Matrix based on Position and Rotation
// Convert Euler angles to radians
glm::vec3 rotationRad = glm::radians(m_LightRotation);
// Create rotation matrices
glm::mat4 rotX = glm::rotate(glm::mat4(1.0f), rotationRad.x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 rotY = glm::rotate(glm::mat4(1.0f), rotationRad.y, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 rotZ = glm::rotate(glm::mat4(1.0f), rotationRad.z, glm::vec3(0.0f, 0.0f, 1.0f));
// Combined rotation
glm::mat4 rotation = rotZ * rotY * rotX;
// Update Light View Matrix
m_LightViewMatrix = glm::lookAt(m_LightPosition, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)) * rotation;
// Shadow Map Rendering
if (1)
{
// Define the size of the preview image
ImVec2 imageSize = ImVec2(256, 256); // Adjust as needed
// Configure OpenGL state for rendering the quad
glDisable(GL_DEPTH_TEST); // Disable depth test so quad renders over everything
m_VisualizeShaderPtr->Use();
m_VisualizeShaderPtr->SetInt("depthMap", 0); // Texture unit 0
// Bind the depth map texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_ShadowMap);
// Render the quad
glBindVertexArray(m_QuadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// Re-enable depth testing
glEnable(GL_DEPTH_TEST);
// Display the shadow map texture in ImGui
ImGui::Image((intptr_t)m_ShadowMap, imageSize, ImVec2(0, 1), ImVec2(1, 0));
}
else
{
ImGui::Text("Shadow map not available.");
}
ImGui::End();
}
@ -252,11 +268,18 @@ bool PlayPauseButton(const char *label, bool *isPlaying, ImVec2 Size)
void RenderWindow::Show(bool* GameRunning) void RenderWindow::Show(bool* GameRunning)
{ {
ImGui::Begin(ICON_FA_GAMEPAD " Editor##EditorWindow"); ImGui::Begin(ICON_FA_GAMEPAD " Editor##EditorWindow");
if (!m_Initialized) if (!m_Initialized)
{ {
InitGLResources(); InitGLResources();
m_LightProjMatrix = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 20.0f);
m_LightViewMatrix = glm::mat4(1.0f); // Will be updated based on position and rotation
m_Initialized = true; m_Initialized = true;
} }
@ -269,15 +292,50 @@ void RenderWindow::Show(bool *GameRunning)
{ {
if (w != m_LastWidth || h != m_LastHeight) if (w != m_LastWidth || h != m_LastHeight)
{ {
m_FBO.Create(w, h); // Since m_FBO is a GLuint, you cannot call Create() on it directly.
// Instead, you need to delete the existing FBO and recreate it with the new size.
// Delete existing FBO and its attachments
if (m_FBO != 0)
{
glDeleteFramebuffers(1, &m_FBO);
glDeleteTextures(1, &m_TextureID);
}
// Recreate the main FBO with the new size
glGenFramebuffers(1, &m_FBO);
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
// Create a new color attachment texture
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TextureID, 0);
// Create a renderbuffer object for depth and stencil attachment
GLuint rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
// Check if framebuffer is complete
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cerr << "[RenderWindow] Main FBO is not complete after resizing." << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
m_LastWidth = w; m_LastWidth = w;
m_LastHeight = h; m_LastHeight = h;
} }
// Render the scene to the FBO with shadow mapping
RenderSceneToFBO(GameRunning); RenderSceneToFBO(GameRunning);
// Render the image first // Display the main FBO's color texture in ImGui
ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0, 0), ImVec2(1, 1)); ImGui::Image((intptr_t)m_TextureID, size, ImVec2(0, 0), ImVec2(1, 1));
// Calculate button position to place it slightly right and down from the top-left of the image // Calculate button position to place it slightly right and down from the top-left of the image
ImVec2 imagePos = ImGui::GetItemRectMin(); ImVec2 imagePos = ImGui::GetItemRectMin();
@ -290,25 +348,19 @@ void RenderWindow::Show(bool *GameRunning)
ImGui::SetCursorScreenPos(buttonPos); ImGui::SetCursorScreenPos(buttonPos);
// Dynamically calculate button size based on window size // Dynamically calculate button size based on window size
float buttonWidth = size.x * 0.03f; // 5% of the window width float buttonWidth = size.x * 0.03f; // 3% of the window width
ImVec2 buttonSize = ImVec2(buttonWidth, buttonWidth); ImVec2 buttonSize = ImVec2(buttonWidth, buttonWidth);
// Render the Play/Pause button with the calculated size // Render the Play/Pause button with the calculated size
PlayPauseButton("##PlayPauseButton", GameRunning, buttonSize); PlayPauseButton("##PlayPauseButton", GameRunning, buttonSize);
} }
else
{
ImGui::Text("No space to render.");
}
ImGui::End(); ImGui::End();
RenderShadowMapPreview();
} }
void RenderWindow::InitGLResources() void RenderWindow::InitGLResources()
{ {
// ---------------------------------------------------- // ----------------------------------------------------
@ -326,6 +378,28 @@ void RenderWindow::InitGLResources()
m_ShaderPtr = shaderAsset.get(); m_ShaderPtr = shaderAsset.get();
} }
{
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(AssetType::SHADER, "assets/shaders/Depth");
if (!shaderAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load shadow shader via AssetManager.\n");
return;
}
// Cast back to your Shader class
m_ShadowShaderPtr = shaderAsset.get();
}
{
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(AssetType::SHADER, "assets/shaders/DepthVisualize");
if (!shaderAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load visualization shader via AssetManager.\n");
return;
}
// Cast back to your Shader class
m_VisualizeShaderPtr = shaderAsset.get();
}
// ---------------------------------------------------- // ----------------------------------------------------
// 2) Create VAO/VBO/EBO for the cube // 2) Create VAO/VBO/EBO for the cube
// ---------------------------------------------------- // ----------------------------------------------------
@ -362,14 +436,39 @@ void RenderWindow::InitGLResources()
} }
else else
{ {
// Cast from void* to GLuint // Cast from shared_ptr<GLuint> to GLuint
m_TextureID = *texAsset; // Assign the GLuint value m_TextureIDLoaded = *texAsset; // Assign the GLuint value
} }
} }
// ---------------------------------------------------- // ----------------------------------------------------
// 4) Initialize GameObjects // 4) Setup Visualization Quad
// ---------------------------------------------------- // ----------------------------------------------------
{
float quadVertices[] = {
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
glGenVertexArrays(1, &m_QuadVAO);
glGenBuffers(1, &m_QuadVBO);
glBindVertexArray(m_QuadVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_QuadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindVertexArray(0);
}
m_Initialized = true;
} }
void CheckOpenGLError(const std::string& location) void CheckOpenGLError(const std::string& location)
@ -383,39 +482,76 @@ void CheckOpenGLError(const std::string &location)
} }
if (hasError) if (hasError)
{ {
// Optionally, you can throw an exception or handle the error as needed // Optionally, handle the error (e.g., throw an exception, assert, etc.)
} }
} }
#include <glm/gtc/type_ptr.hpp> // For glm::value_ptr // RenderWindow.cpp
#include <algorithm> // Ensure <algorithm> is included
void RenderWindow::RenderSceneToFBO(bool* GameRunning) void RenderWindow::RenderSceneToFBO(bool* GameRunning)
{ {
if (!m_Initialized) {
std::cerr << "[RenderWindow] OpenGL resources not initialized." << std::endl;
return;
}
m_RotationAngle += 0.001f; // Spin per frame m_RotationAngle += 0.001f; // Spin per frame
// Bind the FBO // 1. Shadow Pass: Render the scene from the light's perspective to create the shadow map
m_FBO.Bind(); glViewport(0, 0, 1024, 1024); // Shadow map resolution
glBindFramebuffer(GL_FRAMEBUFFER, m_ShadowFBO);
glClear(GL_DEPTH_BUFFER_BIT);
m_ShadowShaderPtr->Use();
m_ShadowShaderPtr->SetMat4("uLightView", m_LightViewMatrix);
m_ShadowShaderPtr->SetMat4("uLightProj", m_LightProjMatrix);
// Render all objects to the shadow map
for (auto& obj : g_GameObjects)
{
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
if (transform && mesh)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, transform->position);
model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::scale(model, transform->scale);
m_ShadowShaderPtr->SetMat4("uModel", model);
for (const auto& submesh : mesh->submeshes)
{
if (submesh.vao == 0)
{
std::cerr << "[RenderWindow] Warning: Submesh VAO is not initialized." << std::endl;
continue;
}
glBindVertexArray(submesh.vao);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
}
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind shadow FBO
// 2. Render Pass: Render the scene from the camera's perspective using the shadow map
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
glViewport(0, 0, m_LastWidth, m_LastHeight); glViewport(0, 0, m_LastWidth, m_LastHeight);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glClearColor(0.f, 0.f, 0.f, 1.f); glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our loaded shader
if (!m_ShaderPtr)
{
DEBUG_PRINT("[RenderWindow] Shader pointer is null. Cannot render.");
m_FBO.Unbind();
return; // Can't render without a shader
}
m_ShaderPtr->Use(); m_ShaderPtr->Use();
// Define view and projection matrices once // Define view and projection matrices
std::shared_ptr<CameraComponent> activeCamera = nullptr; std::shared_ptr<CameraComponent> activeCamera = nullptr;
glm::mat4 view; glm::mat4 view;
glm::mat4 proj; glm::mat4 proj;
@ -424,79 +560,93 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
activeCamera = g_RuntimeCameraObject; activeCamera = g_RuntimeCameraObject;
} }
// Ensure that an active camera is available
if (activeCamera) if (activeCamera)
{ {
// Obtain view and projection matrices from the active camera
view = activeCamera->GetViewMatrix(); view = activeCamera->GetViewMatrix();
proj = activeCamera->GetProjectionMatrix(); proj = activeCamera->GetProjectionMatrix();
} }
else else
{ {
// Fallback to default view and projection if no camera is available
view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f)); view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f));
float aspect = (m_LastHeight != 0) ? (float)m_LastWidth / (float)m_LastHeight : 1.0f; float aspect = (m_LastHeight != 0) ? static_cast<float>(m_LastWidth) / static_cast<float>(m_LastHeight) : 1.0f;
proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN); proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f); // Replace with your CAM_FOV, CAM_NEAR_PLAIN, CAM_FAR_PLAIN
} }
// Iterate over each GameObject and render it // Set uniforms for the main shader
glm::mat4 lightSpaceMatrix = m_LightProjMatrix * m_LightViewMatrix;
m_ShaderPtr->SetMat4("uLightSpaceMatrix", lightSpaceMatrix);
// Bind shadow map texture to texture unit 1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_ShadowMap);
m_ShaderPtr->SetInt("uShadowMap", 1);
// Set light parameters
glm::vec3 lightDir = glm::normalize(glm::vec3(-2.0f, -4.0f, -1.0f));
m_ShaderPtr->SetVec3("light.direction", lightDir);
m_ShaderPtr->SetVec3("light.position", -lightDir * 10.0f); // Same as lightPos in shadow pass
// Set camera/view position
if (activeCamera && activeCamera->GetOwner())
{
auto transformComp = activeCamera->GetOwner()->GetComponent<TransformComponent>();
if (transformComp)
m_ShaderPtr->SetVec3("viewPos", transformComp->position);
else
m_ShaderPtr->SetVec3("viewPos", glm::vec3(0.f, 0.f, 0.f));
}
else
{
m_ShaderPtr->SetVec3("viewPos", glm::vec3(0.f, 0.f, 0.f));
}
// Render all objects
for (auto& obj : g_GameObjects) for (auto& obj : g_GameObjects)
{ {
glm::mat4 model = glm::mat4(1.f);
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>(); std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>(); std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
if (transform && mesh && mesh) if (transform && mesh)
{ {
// Apply transformations glm::mat4 model = glm::mat4(1.f);
model = glm::translate(model, transform->position); model = glm::translate(model, transform->position);
model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.f, 0.f, 0.f)); model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.f, 0.f, 0.f));
model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.f, 1.f, 0.f)); model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.f, 1.f, 0.f));
model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f)); model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f));
model = glm::scale(model, transform->scale); model = glm::scale(model, transform->scale);
// Compute MVP matrix
glm::mat4 mvp = proj * view * model; glm::mat4 mvp = proj * view * model;
// Pass MVP and Model matrices to the shader
m_ShaderPtr->SetMat4("uMVP", mvp); m_ShaderPtr->SetMat4("uMVP", mvp);
m_ShaderPtr->SetMat4("uModel", model); m_ShaderPtr->SetMat4("uModel", model);
// Iterate through each submesh
for (const auto& submesh : mesh->submeshes) for (const auto& submesh : mesh->submeshes)
{ {
// Validate VAO
if (submesh.vao == 0) if (submesh.vao == 0)
{ {
DEBUG_PRINT("[RenderWindow] Warning: Submesh VAO is not initialized."); std::cerr << "[RenderWindow] Warning: Submesh VAO is not initialized." << std::endl;
continue; continue;
} }
// Update triangle count // Update triangle count
g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3); g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3);
// Bind textures for the submesh // Bind diffuse textures
// Assuming the shader has uniform arrays like uTextures.texture_diffuse[32] const int MAX_DIFFUSE = 32;
const int MAX_DIFFUSE = 32; // Must match the shader's MAX_DIFFUSE
int textureUnit = 0; int textureUnit = 0;
// Iterate through all textures and bind those with type "texture_diffuse"
for (const auto& texture : submesh.textures) for (const auto& texture : submesh.textures)
{ {
if (texture.type == "texture_diffuse") if (texture.type == "texture_diffuse")
{ {
if (textureUnit >= MAX_DIFFUSE) if (textureUnit >= MAX_DIFFUSE)
{ {
DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum number of diffuse textures (%d) for shader.", MAX_DIFFUSE); std::cerr << "[RenderWindow] Warning: Exceeded maximum number of diffuse textures (" << MAX_DIFFUSE << ") for shader." << std::endl;
break; // Prevent exceeding the array bounds in the shader break;
} }
// Activate the appropriate texture unit
glActiveTexture(GL_TEXTURE0 + textureUnit); glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, texture.id); glBindTexture(GL_TEXTURE_2D, texture.id); // Assuming texture.id is GLuint
// Construct the uniform name dynamically (e.g., "uTextures.texture_diffuse[0]")
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]"; std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
m_ShaderPtr->SetInt(uniformName, textureUnit); m_ShaderPtr->SetInt(uniformName, textureUnit);
@ -504,14 +654,14 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
} }
} }
// Assign default texture to unused texture slots to prevent shader errors // Assign default texture to unused slots
for (int i = textureUnit; i < MAX_DIFFUSE; ++i) for (int i = textureUnit; i < MAX_DIFFUSE; ++i)
{ {
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]"; std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]";
m_ShaderPtr->SetInt(uniformName, 0); // Assign texture unit 0 (ensure texture 0 is a valid default) m_ShaderPtr->SetInt(uniformName, 0); // Texture unit 0 should have a default texture bound
} }
// Set the number of active diffuse textures // Set number of active diffuse textures
m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit); m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit);
// Draw the submesh // Draw the submesh
@ -519,15 +669,19 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0); glBindVertexArray(0);
// Reset active texture to default // Reset active texture
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
} }
} }
// Cleanup: Unbind the shader program // Unbind shader and framebuffer
glUseProgram(0); glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Unbind the FBO // 3. Render Shadow Map Preview (if not already rendered in Show)
m_FBO.Unbind(); // If you have integrated RenderShadowMapPreview into Show, you might not need to call it here
// Otherwise, uncomment the following line:
// RenderShadowMapPreview();
} }

View File

@ -1,38 +1,67 @@
// RenderWindow.h
#pragma once #pragma once
#include "../Rendering/FBO.h" #include "Rendering/Shader.h"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vector>
#include "Rendering/Shader.h" // #include "imgui.h"
#define CAM_FOV 45.0f
#define CAM_NEAR_PLAIN 0.1f
#define CAM_FAR_PLAIN 5000.0f
// Forward declarations for Camera and GameObject components
class CameraComponent;
class TransformComponent;
class MeshComponent;
class GameObject;
class RenderWindow class RenderWindow
{ {
public: public:
RenderWindow();
~RenderWindow();
void Show(bool *GameRunning); void Show(bool *GameRunning);
private: private:
void InitGLResources(); void InitGLResources();
void RenderSceneToFBO(bool *GameRunning); void RenderSceneToFBO(bool *GameRunning);
void RenderShadowMapPreview();
// OpenGL Framebuffer Objects and Textures
GLuint m_FBO = 0;
GLuint m_ShadowFBO = 0;
GLuint m_ShadowMap = 0;
GLuint m_TextureID = 0; // Color texture for main FBO
// Shaders
Shader *m_ShaderPtr = nullptr; // Main shader
Shader *m_ShadowShaderPtr = nullptr; // Shadow pass shader
Shader *m_VisualizeShaderPtr = nullptr; // Shader for visualizing shadow map
// Light space matrices
glm::mat4 m_LightViewMatrix;
glm::mat4 m_LightProjMatrix;
glm::vec3 m_LightPosition = glm::vec3(-2.0f, 4.0f, -1.0f); // Default position
glm::vec3 m_LightRotation = glm::vec3(0.0f, 0.0f, 0.0f); // Default rotation (Euler angles in degrees)
// Offscreen render target
FBO m_FBO;
// Keep track if we've initialized // Keep track if we've initialized
bool m_Initialized = false; bool m_Initialized = false;
// GL objects for the cube // GL objects for the cube (example)
unsigned int m_VAO = 0; GLuint m_VAO = 0;
unsigned int m_VBO = 0; GLuint m_VBO = 0;
unsigned int m_EBO = 0; GLuint m_EBO = 0;
// GL objects for visualization quad
GLuint m_QuadVAO = 0, m_QuadVBO = 0;
// Spin // Spin
float m_RotationAngle = 0.f; float m_RotationAngle = 0.f;
int m_LastWidth = 0; int m_LastWidth = 800; // Default width
int m_LastHeight = 0; int m_LastHeight = 600; // Default height
// The loaded texture // The loaded texture
unsigned int m_TextureID = 0; GLuint m_TextureIDLoaded = 0;
// The loaded shader program (via AssetManager)
Shader* m_ShaderPtr = nullptr;
}; };