aurora-rendering-engine/examples/02_phase3_test/main.cpp

479 lines
14 KiB
C++

/**
* @file main.cpp
* @brief Phase 3 verification program - G-Buffer rendering test
*/
#include <are/core/config.h>
#include <are/core/logger.h>
#include <are/core/profiler.h>
#include <are/geometry/vertex.h>
#include <are/platform/gl_context.h>
#include <are/platform/window.h>
#include <are/rasterizer/gbuffer.h>
#include <are/rasterizer/rasterizer.h>
#include <are/rasterizer/shader_program.h>
#include <are/scene/camera.h>
#include <are/scene/material.h>
#include <are/scene/mesh.h>
#include <are/scene/scene_manager.h>
#include <are/utils/file_utils.h>
#include <cmath>
#include <iostream>
#include <vector>
#include "../lib/glad/glad/glad.h"
#include <GLFW/glfw3.h>
using namespace are;
/**
* @brief Create a simple cube mesh
*/
Mesh create_cube_mesh() {
std::vector<Vertex> vertices = {
// Front face
Vertex(Vec3(-0.5f, -0.5f, 0.5f), Vec3(0, 0, 1), Vec2(0, 0)),
Vertex(Vec3(0.5f, -0.5f, 0.5f), Vec3(0, 0, 1), Vec2(1, 0)),
Vertex(Vec3(0.5f, 0.5f, 0.5f), Vec3(0, 0, 1), Vec2(1, 1)),
Vertex(Vec3(-0.5f, 0.5f, 0.5f), Vec3(0, 0, 1), Vec2(0, 1)),
// Back face
Vertex(Vec3(0.5f, -0.5f, -0.5f), Vec3(0, 0, -1), Vec2(0, 0)),
Vertex(Vec3(-0.5f, -0.5f, -0.5f), Vec3(0, 0, -1), Vec2(1, 0)),
Vertex(Vec3(-0.5f, 0.5f, -0.5f), Vec3(0, 0, -1), Vec2(1, 1)),
Vertex(Vec3(0.5f, 0.5f, -0.5f), Vec3(0, 0, -1), Vec2(0, 1)),
// Top face
Vertex(Vec3(-0.5f, 0.5f, 0.5f), Vec3(0, 1, 0), Vec2(0, 0)),
Vertex(Vec3(0.5f, 0.5f, 0.5f), Vec3(0, 1, 0), Vec2(1, 0)),
Vertex(Vec3(0.5f, 0.5f, -0.5f), Vec3(0, 1, 0), Vec2(1, 1)),
Vertex(Vec3(-0.5f, 0.5f, -0.5f), Vec3(0, 1, 0), Vec2(0, 1)),
// Bottom face
Vertex(Vec3(-0.5f, -0.5f, -0.5f), Vec3(0, -1, 0), Vec2(0, 0)),
Vertex(Vec3(0.5f, -0.5f, -0.5f), Vec3(0, -1, 0), Vec2(1, 0)),
Vertex(Vec3(0.5f, -0.5f, 0.5f), Vec3(0, -1, 0), Vec2(1, 1)),
Vertex(Vec3(-0.5f, -0.5f, 0.5f), Vec3(0, -1, 0), Vec2(0, 1)),
// Right face
Vertex(Vec3(0.5f, -0.5f, 0.5f), Vec3(1, 0, 0), Vec2(0, 0)),
Vertex(Vec3(0.5f, -0.5f, -0.5f), Vec3(1, 0, 0), Vec2(1, 0)),
Vertex(Vec3(0.5f, 0.5f, -0.5f), Vec3(1, 0, 0), Vec2(1, 1)),
Vertex(Vec3(0.5f, 0.5f, 0.5f), Vec3(1, 0, 0), Vec2(0, 1)),
// Left face
Vertex(Vec3(-0.5f, -0.5f, -0.5f), Vec3(-1, 0, 0), Vec2(0, 0)),
Vertex(Vec3(-0.5f, -0.5f, 0.5f), Vec3(-1, 0, 0), Vec2(1, 0)),
Vertex(Vec3(-0.5f, 0.5f, 0.5f), Vec3(-1, 0, 0), Vec2(1, 1)),
Vertex(Vec3(-0.5f, 0.5f, -0.5f), Vec3(-1, 0, 0), Vec2(0, 1))
};
std::vector<uint32_t> indices = {
// Front
0, 1, 2, 2, 3, 0,
// Back
4, 5, 6, 6, 7, 4,
// Top
8, 9, 10, 10, 11, 8,
// Bottom
12, 13, 14, 14, 15, 12,
// Right
16, 17, 18, 18, 19, 16,
// Left
20, 21, 22, 22, 23, 20
};
return Mesh(vertices, indices);
}
/**
* @brief Create a simple triangle mesh (positioned in front of cube)
*/
Mesh create_triangle_mesh() {
std::vector<Vertex> vertices = {
Vertex(Vec3(-0.5f, -0.5f, 1.0f), Vec3(0, 0, 1), Vec2(0, 0)), // Z = 1.0
Vertex(Vec3( 0.5f, -0.5f, 1.0f), Vec3(0, 0, 1), Vec2(1, 0)), // Z = 1.0
Vertex(Vec3( 0.0f, 0.5f, 1.0f), Vec3(0, 0, 1), Vec2(0.5f, 1)) // Z = 1.0
};
std::vector<uint32_t> indices = {0, 1, 2};
return Mesh(vertices, indices);
}
/**
* @brief Fullscreen quad shader for G-Buffer visualization
*/
const char *fullscreen_vert_source = R"(
#version 430 core
layout(location = 0) in vec2 a_position;
layout(location = 1) in vec2 a_texcoord;
out vec2 v_texcoord;
void main() {
v_texcoord = a_texcoord;
gl_Position = vec4(a_position, 0.0, 1.0);
}
)";
const char *visualize_frag_source = R"(
#version 430 core
in vec2 v_texcoord;
out vec4 frag_color;
uniform sampler2D u_texture;
uniform int u_mode; // 0=position, 1=normal, 2=albedo, 3=material
void main() {
vec4 value = texture(u_texture, v_texcoord);
if (u_mode == 0) {
// Position: normalize to [0,1] range for visualization
frag_color = vec4(value.xyz * 0.5 + 0.5, 1.0);
} else if (u_mode == 1) {
// Normal: normalize to [0,1] range
frag_color = vec4(value.xyz * 0.5 + 0.5, 1.0);
} else if (u_mode == 2) {
// Albedo: direct output
frag_color = vec4(value.rgb, 1.0);
} else if (u_mode == 3) {
// Material: roughness in R, AO in G
frag_color = vec4(value.r, value.g, 0.0, 1.0);
} else {
frag_color = value;
}
}
)";
/**
* @brief Create fullscreen quad VAO
*/
uint32_t create_fullscreen_quad() {
float vertices[] = {
// Position // Texcoord
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f
};
uint32_t indices[] = { 0, 1, 2, 2, 3, 0 };
uint32_t vao, vbo, ebo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, 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);
return vao;
}
int main() {
// Initialize logger
Logger::init(LogLevel::ARE_LOG_DEBUG);
Profiler::init();
ARE_LOG_INFO("========================================");
ARE_LOG_INFO("Phase 3 Verification Program");
ARE_LOG_INFO("G-Buffer Rendering Test");
ARE_LOG_INFO("========================================");
// Create window configuration
WindowConfig window_config;
window_config.width = 800;
window_config.height = 600;
window_config.title = "Phase 3 - G-Buffer Test";
window_config.vsync = true;
// Create window
Window window(window_config);
// Initialize OpenGL
if (!GLContext::initialize()) {
ARE_LOG_CRITICAL("Failed to initialize OpenGL context");
return -1;
}
GLContext::print_info();
// Get shader directory (relative to executable)
std::string shader_dir = "shaders/";
// Create rasterizer
int fb_width, fb_height;
window.get_framebuffer_size(fb_width, fb_height);
Rasterizer rasterizer(fb_width, fb_height);
// Initialize shaders
// First, create G-Buffer shader manually for testing
ShaderProgram gbuffer_shader;
// Try to load from file first
bool shader_loaded = false;
if (file_exists(shader_dir + "gbuffer/gbuffer.vert") && file_exists(shader_dir + "gbuffer/gbuffer.frag")) {
if (gbuffer_shader.load_shader(ShaderType::ARE_SHADER_VERTEX, shader_dir + "gbuffer/gbuffer.vert") && gbuffer_shader.load_shader(ShaderType::ARE_SHADER_FRAGMENT, shader_dir + "gbuffer/gbuffer.frag") && gbuffer_shader.link()) {
shader_loaded = true;
ARE_LOG_INFO("Loaded G-Buffer shaders from files");
}
}
// Fallback to embedded shaders
if (!shader_loaded) {
ARE_LOG_WARN("Shader files not found, using embedded shaders");
const char *gbuffer_vert = R"(
#version 430 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec2 a_texcoord;
layout(location = 3) in vec3 a_tangent;
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
uniform mat3 u_normal_matrix;
out vec3 v_world_position;
out vec3 v_world_normal;
out vec2 v_texcoord;
out vec3 v_world_tangent;
void main() {
vec4 world_pos = u_model * vec4(a_position, 1.0);
v_world_position = world_pos.xyz;
v_world_normal = normalize(u_normal_matrix * a_normal);
v_world_tangent = normalize(u_normal_matrix * a_tangent);
v_texcoord = a_texcoord;
gl_Position = u_projection * u_view * world_pos;
}
)";
const char *gbuffer_frag = R"(
#version 430 core
in vec3 v_world_position;
in vec3 v_world_normal;
in vec2 v_texcoord;
in vec3 v_world_tangent;
uniform vec3 u_albedo;
uniform float u_metallic;
uniform float u_roughness;
layout(location = 0) out vec3 g_position;
layout(location = 1) out vec3 g_normal;
layout(location = 2) out vec4 g_albedo_metallic;
layout(location = 3) out vec2 g_roughness_ao;
void main() {
g_position = v_world_position;
g_normal = normalize(v_world_normal);
g_albedo_metallic = vec4(u_albedo, u_metallic);
g_roughness_ao = vec2(u_roughness, 1.0);
}
)";
if (!gbuffer_shader.compile_shader(ShaderType::ARE_SHADER_VERTEX, gbuffer_vert) || !gbuffer_shader.compile_shader(ShaderType::ARE_SHADER_FRAGMENT, gbuffer_frag) || !gbuffer_shader.link()) {
ARE_LOG_CRITICAL("Failed to compile embedded G-Buffer shaders");
return -1;
}
}
// Create visualization shader
ShaderProgram vis_shader;
if (!vis_shader.compile_shader(ShaderType::ARE_SHADER_VERTEX, fullscreen_vert_source) || !vis_shader.compile_shader(ShaderType::ARE_SHADER_FRAGMENT, visualize_frag_source) || !vis_shader.link()) {
ARE_LOG_CRITICAL("Failed to compile visualization shaders");
return -1;
}
// Create fullscreen quad
uint32_t fullscreen_quad_vao = create_fullscreen_quad();
// Create scene
SceneManager scene;
// Create materials
Material red_material;
red_material.set_albedo(Vec3(0.8f, 0.2f, 0.2f));
red_material.set_metallic(0.0f);
red_material.set_roughness(0.5f);
MaterialHandle red_mat_handle = scene.add_material(red_material);
Material green_material;
green_material.set_albedo(Vec3(0.2f, 0.8f, 0.2f));
green_material.set_metallic(0.5f);
green_material.set_roughness(0.3f);
MaterialHandle green_mat_handle = scene.add_material(green_material);
// Create meshes
Mesh cube = create_cube_mesh();
cube.set_material(red_mat_handle);
cube.compute_tangents();
Mesh triangle = create_triangle_mesh();
triangle.set_material(green_mat_handle);
triangle.compute_tangents();
// Upload meshes to GPU
rasterizer.upload_mesh(cube);
rasterizer.upload_mesh(triangle);
// Add meshes to scene
scene.add_mesh(cube);
scene.add_mesh(triangle);
// Create camera
Camera camera(Vec3(0, 0, 3), Vec3(0, 0, 0));
camera.set_perspective(45.0f, static_cast<float>(fb_width) / fb_height, 0.1f, 100.0f);
// Visualization mode (0=position, 1=normal, 2=albedo, 3=material)
int vis_mode = 2; // Start with albedo
ARE_LOG_INFO("Controls:");
ARE_LOG_INFO(" 1 - View Position buffer");
ARE_LOG_INFO(" 2 - View Normal buffer");
ARE_LOG_INFO(" 3 - View Albedo buffer");
ARE_LOG_INFO(" 4 - View Material buffer (Roughness/AO)");
ARE_LOG_INFO(" ESC - Exit");
// Main loop
float time = 0.0f;
while (!window.should_close()) {
ARE_PROFILE_SCOPE("Frame");
// Poll events
window.poll_events();
// Handle input
if (window.is_key_pressed(256)) { // ESC
window.set_should_close(true);
}
if (window.is_key_pressed(49))
vis_mode = 0; // 1 - Position
if (window.is_key_pressed(50))
vis_mode = 1; // 2 - Normal
if (window.is_key_pressed(51))
vis_mode = 2; // 3 - Albedo
if (window.is_key_pressed(52))
vis_mode = 3; // 4 - Material
// Update camera position (orbit around origin)
time += 0.016f;
float cam_x = std::sin(time * 0.5f) * 3.0f;
float cam_z = std::cos(time * 0.5f) * 3.0f;
camera.set_position(Vec3(cam_x, 1.5f, cam_z));
camera.set_target(Vec3(0, 0, 0));
// Render to G-Buffer
{
ARE_PROFILE_SCOPE("Render G-Buffer");
// Manually render since we're using our own shader
GBuffer &gbuffer = rasterizer.get_gbuffer();
gbuffer.bind();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
gbuffer_shader.use();
gbuffer_shader.set_uniform("u_view", camera.get_view_matrix());
gbuffer_shader.set_uniform("u_projection", camera.get_projection_matrix());
// Render all meshes
const auto &meshes = scene.get_all_meshes();
const auto &materials = scene.get_all_materials();
for (const auto &mesh : meshes) {
if (!mesh.has_gpu_resources())
continue;
Mat4 model = Mat4(1.0f);
gbuffer_shader.set_uniform("u_model", model);
Mat3 normal_matrix = glm::transpose(glm::inverse(Mat3(model)));
gbuffer_shader.set_uniform("u_normal_matrix", normal_matrix);
MaterialHandle mat_handle = mesh.get_material();
if (mat_handle != are_invalid_handle && mat_handle <= materials.size()) {
const Material &mat = materials[mat_handle - 1];
gbuffer_shader.set_uniform("u_albedo", mat.get_albedo());
gbuffer_shader.set_uniform("u_metallic", mat.get_metallic());
gbuffer_shader.set_uniform("u_roughness", mat.get_roughness());
} else {
gbuffer_shader.set_uniform("u_albedo", Vec3(0.8f));
gbuffer_shader.set_uniform("u_metallic", 0.0f);
gbuffer_shader.set_uniform("u_roughness", 0.5f);
}
glBindVertexArray(mesh.get_vao());
glDrawElements(GL_TRIANGLES,
static_cast<GLsizei>(mesh.get_index_count()),
GL_UNSIGNED_INT,
nullptr);
}
glBindVertexArray(0);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
gbuffer.unbind();
}
// Visualize G-Buffer
{
ARE_PROFILE_SCOPE("Visualize G-Buffer");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, fb_width, fb_height);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
vis_shader.use();
vis_shader.set_uniform("u_mode", vis_mode);
vis_shader.set_uniform("u_texture", 0);
// Bind appropriate G-Buffer texture
GBuffer &gbuffer = rasterizer.get_gbuffer();
gbuffer.bind_texture(vis_mode, 0);
glBindVertexArray(fullscreen_quad_vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
}
// Swap buffers
window.swap_buffers();
}
// Cleanup
glDeleteVertexArrays(1, &fullscreen_quad_vao);
// Print profiling results
Profiler::print_results();
ARE_LOG_INFO("========================================");
ARE_LOG_INFO("Phase 3 test completed successfully!");
ARE_LOG_INFO("========================================");
Profiler::shutdown();
Logger::shutdown();
return 0;
}