### 文件:src/basic/math.cpp ```cpp #include "basic/math.h" namespace are { Mat4 MathUtils::perspective(float fov, float aspect, float near, float far) { return glm::perspective(fov, aspect, near, far); } Mat4 MathUtils::look_at(const Vec3& eye, const Vec3& center, const Vec3& up) { return glm::lookAt(eye, center, up); } Vec3 MathUtils::normalize(const Vec3& v) { return glm::normalize(v); } float MathUtils::dot(const Vec3& a, const Vec3& b) { return glm::dot(a, b); } Vec3 MathUtils::cross(const Vec3& a, const Vec3& b) { return glm::cross(a, b); } Vec3 MathUtils::reflect(const Vec3& incident, const Vec3& normal) { return glm::reflect(incident, normal); } const float* MathUtils::value_ptr(const Mat4& mat) { return glm::value_ptr(mat); } } // namespace are ``` ### 文件:src/core/bvh.cpp ```cpp #include "core/bvh.h" #include "utils/logger.h" #include "basic/constants.h" #include #include namespace are { // AABB implementation void AABB::expand(const Vec3& point) { min_ = glm::min(min_, point); max_ = glm::max(max_, point); } void AABB::expand(const AABB& other) { min_ = glm::min(min_, other.min_); max_ = glm::max(max_, other.max_); } float AABB::surface_area() const { Vec3 extent = max_ - min_; return 2.0f * (extent.x * extent.y + extent.y * extent.z + extent.z * extent.x); } bool AABB::is_valid() const { return min_.x <= max_.x && min_.y <= max_.y && min_.z <= max_.z; } // Triangle implementation AABB Triangle::get_bounds() const { AABB bounds(v0_, v0_); bounds.expand(v1_); bounds.expand(v2_); return bounds; } Vec3 Triangle::get_centroid() const { return (v0_ + v1_ + v2_) / 3.0f; } // BVH implementation BVH::BVH() { } BVH::~BVH() { clear(); } bool BVH::build(const std::vector>& meshes) { clear(); Logger::info("Building BVH..."); // Extract all triangles from meshes for (const auto& mesh : meshes) { const auto& vertices = mesh->get_vertices(); const auto& indices = mesh->get_indices(); uint material_id = mesh->get_material(); Mat4 transform = mesh->get_transform(); for (size_t i = 0; i < indices.size(); i += 3) { Triangle tri; // Transform vertices Vec4 v0 = transform * Vec4(vertices[indices[i]].position_, 1.0f); Vec4 v1 = transform * Vec4(vertices[indices[i + 1]].position_, 1.0f); Vec4 v2 = transform * Vec4(vertices[indices[i + 2]].position_, 1.0f); tri.v0_ = Vec3(v0) / v0.w; tri.v1_ = Vec3(v1) / v1.w; tri.v2_ = Vec3(v2) / v2.w; // Transform normals Mat3 normal_matrix = glm::transpose(glm::inverse(Mat3(transform))); tri.n0_ = glm::normalize(normal_matrix * vertices[indices[i]].normal_); tri.n1_ = glm::normalize(normal_matrix * vertices[indices[i + 1]].normal_); tri.n2_ = glm::normalize(normal_matrix * vertices[indices[i + 2]].normal_); // Copy UVs tri.uv0_ = vertices[indices[i]].texcoord_; tri.uv1_ = vertices[indices[i + 1]].texcoord_; tri.uv2_ = vertices[indices[i + 2]].texcoord_; tri.material_id_ = material_id; triangles_.push_back(tri); } } if (triangles_.empty()) { Logger::warning("No triangles to build BVH"); return false; } // Initialize triangle indices triangle_indices_.resize(triangles_.size()); for (size_t i = 0; i < triangles_.size(); ++i) { triangle_indices_[i] = static_cast(i); } // Reserve space for nodes (estimate) nodes_.reserve(triangles_.size() * 2); // Create root node nodes_.emplace_back(); // Build BVH recursively build_recursive_(0, 0, static_cast(triangles_.size())); Logger::info("BVH built: " + std::to_string(nodes_.size()) + " nodes, " + std::to_string(triangles_.size()) + " triangles"); return true; } void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) { BVHNode& node = nodes_[node_idx]; // Calculate bounds AABB bounds = calculate_bounds_(first_prim, prim_count); node.aabb_min_ = bounds.min_; node.aabb_max_ = bounds.max_; // Leaf node threshold const uint LEAF_SIZE = 4; if (prim_count <= LEAF_SIZE) { // Create leaf node node.left_first_ = first_prim; node.count_ = prim_count; return; } // Find best split int axis; float split_pos; float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos); // Check if split is beneficial float no_split_cost = prim_count * bounds.surface_area(); if (split_cost >= no_split_cost) { // Create leaf node node.left_first_ = first_prim; node.count_ = prim_count; return; } // Partition primitives uint mid = first_prim; for (uint i = first_prim; i < first_prim + prim_count; ++i) { Triangle& tri = triangles_[triangle_indices_[i]]; float centroid = tri.get_centroid()[axis]; if (centroid < split_pos) { std::swap(triangle_indices_[i], triangle_indices_[mid]); mid++; } } // Ensure we have primitives on both sides if (mid == first_prim || mid == first_prim + prim_count) { mid = first_prim + prim_count / 2; } // Create interior node uint left_count = mid - first_prim; uint right_count = prim_count - left_count; node.left_first_ = static_cast(nodes_.size()); node.count_ = 0; // Create child nodes nodes_.emplace_back(); nodes_.emplace_back(); // Recursively build children build_recursive_(node.left_first_, first_prim, left_count); build_recursive_(node.left_first_ + 1, mid, right_count); } float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float& split_pos) { float best_cost = std::numeric_limits::max(); AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count); // Try each axis for (int a = 0; a < 3; ++a) { float extent = centroid_bounds.max_[a] - centroid_bounds.min_[a]; if (extent < EPSILON) continue; // Try multiple split positions const int NUM_BINS = 16; for (int i = 1; i < NUM_BINS; ++i) { float t = static_cast(i) / NUM_BINS; float pos = centroid_bounds.min_[a] + t * extent; // Count primitives and calculate bounds for each side AABB left_bounds, right_bounds; uint left_count = 0, right_count = 0; for (uint j = first_prim; j < first_prim + prim_count; ++j) { Triangle& tri = triangles_[triangle_indices_[j]]; float centroid = tri.get_centroid()[a]; if (centroid < pos) { left_bounds.expand(tri.get_bounds()); left_count++; } else { right_bounds.expand(tri.get_bounds()); right_count++; } } // Calculate SAH cost if (left_count == 0 || right_count == 0) continue; float cost = left_count * left_bounds.surface_area() + right_count * right_bounds.surface_area(); if (cost < best_cost) { best_cost = cost; axis = a; split_pos = pos; } } } return best_cost; } AABB BVH::calculate_bounds_(uint first_prim, uint prim_count) { AABB bounds{Vec3(std::numeric_limits::max()), Vec3(std::numeric_limits::lowest())}; for (uint i = first_prim; i < first_prim + prim_count; ++i) { Triangle& tri = triangles_[triangle_indices_[i]]; bounds.expand(tri.get_bounds()); } return bounds; } AABB BVH::calculate_centroid_bounds_(uint first_prim, uint prim_count) { AABB bounds{Vec3(std::numeric_limits::max()), Vec3(std::numeric_limits::lowest())}; for (uint i = first_prim; i < first_prim + prim_count; ++i) { Triangle& tri = triangles_[triangle_indices_[i]]; bounds.expand(tri.get_centroid()); } return bounds; } bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) { if (nodes_.empty() || triangles_.empty()) { Logger::error("Cannot upload empty BVH to GPU"); return false; } // Reorder triangles according to BVH layout std::vector ordered_triangles; ordered_triangles.reserve(triangles_.size()); for (uint idx : triangle_indices_) { ordered_triangles.push_back(triangles_[idx]); } // Upload nodes if (!node_buffer.create(BufferType::SHADER_STORAGE_BUFFER, nodes_.size() * sizeof(BVHNode), nodes_.data(), BufferUsage::STATIC_DRAW)) { Logger::error("Failed to upload BVH nodes to GPU"); return false; } // Upload triangles if (!triangle_buffer.create(BufferType::SHADER_STORAGE_BUFFER, ordered_triangles.size() * sizeof(Triangle), ordered_triangles.data(), BufferUsage::STATIC_DRAW)) { Logger::error("Failed to upload BVH triangles to GPU"); return false; } Logger::info("BVH uploaded to GPU successfully"); return true; } void BVH::clear() { nodes_.clear(); triangles_.clear(); triangle_indices_.clear(); } } // namespace are ``` ### 文件:src/core/gbuffer.cpp ```cpp #include "core/gbuffer.h" #include "utils/logger.h" #include namespace are { GBuffer::GBuffer(uint width, uint height) : width_(width) , height_(height) , fbo_(INVALID_HANDLE) , depth_texture_(INVALID_HANDLE) , initialized_(false) { for (int i = 0; i < GBUFFER_COUNT; ++i) { textures_[i] = INVALID_HANDLE; } } GBuffer::~GBuffer() { release(); } bool GBuffer::initialize() { if (initialized_) { Logger::warning("GBuffer already initialized"); return true; } // Create framebuffer glGenFramebuffers(1, &fbo_); glBindFramebuffer(GL_FRAMEBUFFER, fbo_); // Create G-Buffer textures textures_[GBUFFER_POSITION] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); textures_[GBUFFER_NORMAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); textures_[GBUFFER_ALBEDO] = create_texture_(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); // Attach textures to framebuffer glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, GL_TEXTURE_2D, textures_[GBUFFER_POSITION], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, GL_TEXTURE_2D, textures_[GBUFFER_NORMAL], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO, GL_TEXTURE_2D, textures_[GBUFFER_ALBEDO], 0); // Create depth texture glGenTextures(1, &depth_texture_); glBindTexture(GL_TEXTURE_2D, depth_texture_); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width_, height_, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_texture_, 0); // Set draw buffers GLenum draw_buffers[GBUFFER_COUNT] = { GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO }; glDrawBuffers(GBUFFER_COUNT, draw_buffers); // Check framebuffer completeness if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { Logger::error("GBuffer framebuffer is not complete"); glBindFramebuffer(GL_FRAMEBUFFER, 0); return false; } glBindFramebuffer(GL_FRAMEBUFFER, 0); initialized_ = true; Logger::info("GBuffer initialized successfully"); return true; } void GBuffer::release() { if (!initialized_) return; if (fbo_ != INVALID_HANDLE) { glDeleteFramebuffers(1, &fbo_); fbo_ = INVALID_HANDLE; } for (int i = 0; i < GBUFFER_COUNT; ++i) { if (textures_[i] != INVALID_HANDLE) { glDeleteTextures(1, &textures_[i]); textures_[i] = INVALID_HANDLE; } } if (depth_texture_ != INVALID_HANDLE) { glDeleteTextures(1, &depth_texture_); depth_texture_ = INVALID_HANDLE; } initialized_ = false; Logger::info("GBuffer released"); } void GBuffer::render(const Scene& scene, const Shader& shader) { if (!initialized_) { Logger::error("GBuffer not initialized"); return; } // Bind framebuffer glBindFramebuffer(GL_FRAMEBUFFER, fbo_); glViewport(0, 0, width_, height_); // Clear buffers glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Enable depth test glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // Use shader shader.use(); // Set camera matrices const Camera& camera = scene.get_camera(); Mat4 view = camera.get_view_matrix(); Mat4 projection = camera.get_projection_matrix(); shader.set_mat4("u_view", view); shader.set_mat4("u_projection", projection); // Render all meshes const auto& meshes = scene.get_meshes(); const auto& materials = scene.get_materials(); for (const auto& mesh : meshes) { if (!mesh->is_uploaded()) { Logger::warning("Mesh not uploaded to GPU, skipping"); continue; } // Set model matrix Mat4 model = mesh->get_transform(); shader.set_mat4("u_model", model); // Set material properties uint material_id = mesh->get_material(); if (material_id < materials.size()) { const auto& material = materials[material_id]; shader.set_vec3("u_albedo", material->get_albedo()); shader.set_float("u_metallic", material->get_metallic()); shader.set_float("u_roughness", material->get_roughness()); shader.set_uint("u_material_id", material_id); // Bind textures auto albedo_tex = material->get_albedo_texture(); if (albedo_tex && albedo_tex->is_valid()) { albedo_tex->bind(0); shader.set_int("u_albedo_map", 0); shader.set_int("u_has_albedo_map", 1); } else { shader.set_int("u_has_albedo_map", 0); } auto normal_tex = material->get_normal_texture(); if (normal_tex && normal_tex->is_valid()) { normal_tex->bind(1); shader.set_int("u_normal_map", 1); shader.set_int("u_has_normal_map", 1); } else { shader.set_int("u_has_normal_map", 0); } } // Draw mesh glBindVertexArray(mesh->get_vao()); glDrawElements(GL_TRIANGLES, mesh->get_indices().size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); } // Unbind framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); } void GBuffer::resize(uint width, uint height) { if (width == width_ && height == height_) return; width_ = width; height_ = height; if (initialized_) { release(); initialize(); } } TextureHandle GBuffer::get_texture(int index) const { if (index < 0 || index >= GBUFFER_COUNT) { Logger::error("Invalid G-Buffer texture index"); return INVALID_HANDLE; } return textures_[index]; } void GBuffer::get_dimensions(uint& width, uint& height) const { width = width_; height = height_; } TextureHandle GBuffer::create_texture_(uint internal_format, uint format, uint type) { TextureHandle texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_, height_, 0, format, type, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return texture; } } // namespace are ``` ### 文件:src/core/raytracer.cpp ```cpp #include "core/raytracer.h" #include "utils/logger.h" #include "basic/constants.h" #include namespace are { RayTracer::RayTracer(uint width, uint height, const RayTracerConfig& config) : width_(width) , height_(height) , config_(config) , accumulation_texture_(INVALID_HANDLE) , scene_buffer_(INVALID_HANDLE) , material_buffer_(INVALID_HANDLE) , light_buffer_(INVALID_HANDLE) , bvh_(nullptr) , bvh_built_(false) , frame_count_(0) , initialized_(false) { } RayTracer::~RayTracer() { release(); } bool RayTracer::initialize() { if (initialized_) { Logger::warning("RayTracer already initialized"); return true; } // Create accumulation texture glGenTextures(1, &accumulation_texture_); glBindTexture(GL_TEXTURE_2D, accumulation_texture_); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create shader storage buffers glGenBuffers(1, &material_buffer_); glGenBuffers(1, &light_buffer_); // Load compute shader Logger::info("Loading ray tracing compute shader in RayTracer..."); if (!compute_shader_.load_compute("shaders/raytracing.comp")) { Logger::error("Failed to load ray tracing compute shader in RayTracer"); return false; } Logger::info("Ray tracing compute shader loaded in RayTracer"); // Initialize BVH if enabled if (config_.use_bvh_) { bvh_ = std::make_unique(); } initialized_ = true; Logger::info("RayTracer initialized successfully"); return true; } void RayTracer::release() { if (!initialized_) return; if (accumulation_texture_ != INVALID_HANDLE) { glDeleteTextures(1, &accumulation_texture_); accumulation_texture_ = INVALID_HANDLE; } if (material_buffer_ != INVALID_HANDLE) { glDeleteBuffers(1, &material_buffer_); material_buffer_ = INVALID_HANDLE; } if (light_buffer_ != INVALID_HANDLE) { glDeleteBuffers(1, &light_buffer_); light_buffer_ = INVALID_HANDLE; } bvh_node_buffer_.release(); bvh_triangle_buffer_.release(); compute_shader_.release(); bvh_.reset(); bvh_built_ = false; initialized_ = false; Logger::info("RayTracer released"); } bool RayTracer::rebuild_bvh(const Scene& scene) { if (!config_.use_bvh_) { Logger::warning("BVH is disabled in configuration"); return false; } if (!bvh_) { bvh_ = std::make_unique(); } Logger::info("Building BVH for ray tracing..."); if (!bvh_->build(scene.get_meshes())) { Logger::error("Failed to build BVH"); return false; } if (!bvh_->upload_to_gpu(bvh_node_buffer_, bvh_triangle_buffer_)) { Logger::error("Failed to upload BVH to GPU"); return false; } bvh_built_ = true; Logger::info("BVH built and uploaded successfully"); return true; } void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle output_texture) { if (!initialized_) { Logger::error("RayTracer not initialized"); return; } if (!compute_shader_.is_valid()) { Logger::error("Ray tracing compute shader not loaded"); return; } // Build BVH if enabled and not built yet if (config_.use_bvh_ && !bvh_built_) { rebuild_bvh(scene); } // Upload scene data upload_scene_data_(scene); // Use compute shader compute_shader_.use(); // Bind G-Buffer textures bind_gbuffer_(gbuffer); // Bind output and accumulation textures glBindImageTexture(3, output_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); glBindImageTexture(4, accumulation_texture_, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); // Bind BVH buffers if enabled if (config_.use_bvh_ && bvh_built_) { bvh_node_buffer_.bind_base(2); bvh_triangle_buffer_.bind_base(3); compute_shader_.set_bool("u_use_bvh", true); compute_shader_.set_uint("u_bvh_node_count", bvh_->get_node_count()); } else { compute_shader_.set_bool("u_use_bvh", false); } // Set uniforms compute_shader_.set_uint("u_frame_count", frame_count_); compute_shader_.set_uint("u_samples_per_pixel", config_.samples_per_pixel_); compute_shader_.set_uint("u_max_depth", config_.max_depth_); compute_shader_.set_uint("u_light_count", static_cast(scene.get_lights().size())); compute_shader_.set_bool("u_enable_accumulation", config_.enable_accumulation_); // Set camera data const Camera& camera = scene.get_camera(); compute_shader_.set_vec3("u_camera_position", camera.get_position()); Mat4 inv_vp = glm::inverse(camera.get_view_projection_matrix()); compute_shader_.set_mat4("u_inv_view_projection", inv_vp); // Dispatch compute shader uint num_groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X; uint num_groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y; glDispatchCompute(num_groups_x, num_groups_y, 1); // Memory barrier glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); // Increment frame count for accumulation if (config_.enable_accumulation_) { frame_count_++; } } void RayTracer::resize(uint width, uint height) { if (width == width_ && height == height_) return; width_ = width; height_ = height; if (initialized_) { // Recreate accumulation texture if (accumulation_texture_ != INVALID_HANDLE) { glDeleteTextures(1, &accumulation_texture_); } glGenTextures(1, &accumulation_texture_); glBindTexture(GL_TEXTURE_2D, accumulation_texture_); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); reset_accumulation(); } } void RayTracer::reset_accumulation() { frame_count_ = 0; } void RayTracer::set_config(const RayTracerConfig& config) { bool bvh_changed = (config.use_bvh_ != config_.use_bvh_); config_ = config; reset_accumulation(); if (bvh_changed) { if (config_.use_bvh_ && !bvh_) { bvh_ = std::make_unique(); bvh_built_ = false; } else if (!config_.use_bvh_) { bvh_.reset(); bvh_built_ = false; } } } void RayTracer::upload_scene_data_(const Scene& scene) { // Upload materials const auto& materials = scene.get_materials(); if (!materials.empty()) { struct MaterialData { Vec3 albedo; float metallic; Vec3 emission; float roughness; int type; float ior; Vec2 padding; }; std::vector material_data; material_data.reserve(materials.size()); for (const auto& mat : materials) { MaterialData data; data.albedo = mat->get_albedo(); data.metallic = mat->get_metallic(); data.emission = mat->get_emission(); data.roughness = mat->get_roughness(); data.type = static_cast(mat->get_type()); data.ior = mat->get_ior(); material_data.push_back(data); } glBindBuffer(GL_SHADER_STORAGE_BUFFER, material_buffer_); glBufferData(GL_SHADER_STORAGE_BUFFER, material_data.size() * sizeof(MaterialData), material_data.data(), GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, material_buffer_); } // Upload lights const auto& lights = scene.get_lights(); if (!lights.empty()) { struct LightData { Vec3 position; int type; Vec3 direction; float intensity; Vec3 color; float range; Vec2 spot_angles; Vec2 padding; }; std::vector light_data; light_data.reserve(lights.size()); for (const auto& light : lights) { LightData data; data.position = light->get_position(); data.type = static_cast(light->get_type()); data.direction = light->get_direction(); data.intensity = light->get_intensity(); data.color = light->get_color(); data.range = light->get_range(); data.spot_angles = Vec2(light->get_inner_angle(), light->get_outer_angle()); light_data.push_back(data); } glBindBuffer(GL_SHADER_STORAGE_BUFFER, light_buffer_); glBufferData(GL_SHADER_STORAGE_BUFFER, light_data.size() * sizeof(LightData), light_data.data(), GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, light_buffer_); } } void RayTracer::bind_gbuffer_(const GBuffer& gbuffer) { glBindImageTexture(0, gbuffer.get_texture(GBUFFER_POSITION), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); glBindImageTexture(1, gbuffer.get_texture(GBUFFER_NORMAL), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); glBindImageTexture(2, gbuffer.get_texture(GBUFFER_ALBEDO), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8); } void RayTracer::set_compute_shader(const Shader& shader) { compute_shader_ = shader; Logger::info("Compute shader set for RayTracer"); } } // namespace are ``` ### 文件:src/core/renderer.cpp ```cpp #include "core/renderer.h" #include "utils/logger.h" #include #include namespace are { Renderer::Renderer(const RendererConfig &config) : config_(config) , initialized_(false) , frame_count_(0) { } Renderer::~Renderer() { shutdown(); } bool Renderer::initialize() { if (initialized_) { Logger::warning("Renderer already initialized"); return true; } Logger::info("Initializing Aurora Rendering Engine..."); // Initialize shader manager shader_manager_ = std::make_unique(); if (!shader_manager_->initialize()) { Logger::error("Failed to initialize shader manager"); return false; } // Initialize G-Buffer gbuffer_ = std::make_unique(config_.width_, config_.height_); if (!gbuffer_->initialize()) { Logger::error("Failed to initialize G-Buffer"); return false; } // Initialize ray tracer RayTracerConfig rt_config; rt_config.samples_per_pixel_ = config_.samples_per_pixel_; rt_config.max_depth_ = config_.max_ray_depth_; rt_config.enable_shadows_ = true; rt_config.enable_reflections_ = true; rt_config.enable_accumulation_ = config_.enable_accumulation_; rt_config.use_bvh_ = true; raytracer_ = std::make_unique(config_.width_, config_.height_, rt_config); if (!raytracer_->initialize()) { Logger::error("Failed to initialize ray tracer"); return false; } // Pass compute shader to ray tracer const Shader& rt_shader = shader_manager_->get_raytracing_shader(); if (!rt_shader.is_valid()) { Logger::error("Ray tracing shader is invalid"); return false; } raytracer_->set_compute_shader(rt_shader); // Initialize screen blit screen_blit_ = std::make_unique(); if (!screen_blit_->initialize()) { Logger::error("Failed to initialize screen blit"); return false; } initialized_ = true; Logger::info("Aurora Rendering Engine initialized successfully"); return true; } void Renderer::shutdown() { if (!initialized_) return; Logger::info("Shutting down Aurora Rendering Engine..."); if (screen_blit_) { screen_blit_->release(); screen_blit_.reset(); } if (raytracer_) { raytracer_->release(); raytracer_.reset(); } if (gbuffer_) { gbuffer_->release(); gbuffer_.reset(); } if (shader_manager_) { shader_manager_->release(); shader_manager_.reset(); } initialized_ = false; Logger::info("Aurora Rendering Engine shut down"); } RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) { RenderStats stats = {}; if (!initialized_) { Logger::error("Renderer not initialized"); return stats; } // Start timing auto start_time = std::chrono::high_resolution_clock::now(); // Phase 1: G-Buffer pass auto gbuffer_start = std::chrono::high_resolution_clock::now(); const Shader& gbuffer_shader = shader_manager_->get_gbuffer_shader(); gbuffer_->render(scene, gbuffer_shader); auto gbuffer_end = std::chrono::high_resolution_clock::now(); stats.gbuffer_time_ms_ = std::chrono::duration(gbuffer_end - gbuffer_start).count(); // Phase 2: Ray tracing pass auto raytrace_start = std::chrono::high_resolution_clock::now(); // Create output texture if not provided TextureHandle rt_output = output_texture; bool created_temp_texture = false; if (rt_output == 0) { glGenTextures(1, &rt_output); glBindTexture(GL_TEXTURE_2D, rt_output); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, config_.width_, config_.height_, 0, GL_RGBA, GL_FLOAT, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); created_temp_texture = true; } raytracer_->trace(scene, *gbuffer_, rt_output); auto raytrace_end = std::chrono::high_resolution_clock::now(); stats.raytrace_time_ms_ = std::chrono::duration(raytrace_end - raytrace_start).count(); // Phase 3: Blit to screen if output is default framebuffer if (created_temp_texture && output_texture == 0) { screen_blit_->blit_fullscreen(rt_output); glDeleteTextures(1, &rt_output); } // Calculate total frame time auto end_time = std::chrono::high_resolution_clock::now(); stats.frame_time_ms_ = std::chrono::duration(end_time - start_time).count(); // Count triangles const auto& meshes = scene.get_meshes(); for (const auto& mesh : meshes) { stats.triangle_count_ += mesh->get_indices().size() / 3; } // Estimate ray count (very rough) stats.ray_count_ = config_.width_ * config_.height_ * config_.samples_per_pixel_ * config_.max_ray_depth_; frame_count_++; return stats; } void Renderer::resize(uint width, uint height) { if (width == config_.width_ && height == config_.height_) return; config_.width_ = width; config_.height_ = height; if (initialized_) { gbuffer_->resize(width, height); raytracer_->resize(width, height); Logger::info("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height)); } } void Renderer::set_config(const RendererConfig &config) { bool size_changed = (config.width_ != config_.width_ || config.height_ != config_.height_); config_ = config; if (initialized_) { if (size_changed) { resize(config_.width_, config_.height_); } // Update ray tracer config RayTracerConfig rt_config = raytracer_->get_config(); rt_config.samples_per_pixel_ = config_.samples_per_pixel_; rt_config.max_depth_ = config_.max_ray_depth_; rt_config.enable_accumulation_ = config_.enable_accumulation_; raytracer_->set_config(rt_config); } } } // namespace are ``` ### 文件:src/core/screen_blit.cpp ```cpp #include "core/screen_blit.h" #include "utils/logger.h" #include namespace are { namespace { const char* VERTEX_SHADER_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* FRAGMENT_SHADER_SOURCE = R"( #version 430 core in vec2 v_texcoord; out vec4 frag_color; uniform sampler2D u_texture; void main() { frag_color = texture(u_texture, v_texcoord); } )"; } ScreenBlit::ScreenBlit() : vao_(0) , vbo_(0) , initialized_(false) { } ScreenBlit::~ScreenBlit() { release(); } bool ScreenBlit::initialize() { if (initialized_) { Logger::warning("ScreenBlit already initialized"); return true; } // Compile shader if (!shader_.compile(VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)) { Logger::error("Failed to compile screen blit shader"); return false; } // Create fullscreen quad create_quad_(); initialized_ = true; Logger::info("ScreenBlit initialized successfully"); return true; } void ScreenBlit::release() { if (!initialized_) return; shader_.release(); if (vao_ != 0) { glDeleteVertexArrays(1, &vao_); vao_ = 0; } if (vbo_ != 0) { glDeleteBuffers(1, &vbo_); vbo_ = 0; } initialized_ = false; } void ScreenBlit::blit(TextureHandle texture, int x, int y, uint width, uint height) { if (!initialized_) { Logger::error("ScreenBlit not initialized"); return; } // Set viewport glViewport(x, y, width, height); // Disable depth test glDisable(GL_DEPTH_TEST); // Use shader shader_.use(); shader_.set_int("u_texture", 0); // Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); // Draw quad glBindVertexArray(vao_); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); // Re-enable depth test glEnable(GL_DEPTH_TEST); } void ScreenBlit::blit_fullscreen(TextureHandle texture) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); blit(texture, viewport[0], viewport[1], viewport[2], viewport[3]); } void ScreenBlit::create_quad_() { // Fullscreen quad vertices (position + texcoord) 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, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f }; glGenVertexArrays(1, &vao_); glGenBuffers(1, &vbo_); glBindVertexArray(vao_); glBindBuffer(GL_ARRAY_BUFFER, vbo_); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Position attribute glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); // TexCoord attribute glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); glBindVertexArray(0); } } // namespace are ``` ### 文件:src/core/shader_manager.cpp ```cpp #include "core/shader_manager.h" #include "utils/logger.h" namespace are { ShaderManager::ShaderManager() : initialized_(false) { } ShaderManager::~ShaderManager() { release(); } bool ShaderManager::initialize() { if (initialized_) { Logger::warning("ShaderManager already initialized"); return true; } Logger::info("Loading built-in shaders..."); if (!load_builtin_shaders_()) { Logger::error("Failed to load built-in shaders"); return false; } initialized_ = true; Logger::info("ShaderManager initialized successfully"); return true; } void ShaderManager::release() { if (!initialized_) return; gbuffer_shader_.release(); raytracing_shader_.release(); for (auto& pair : shader_cache_) { pair.second.release(); } shader_cache_.clear(); initialized_ = false; Logger::info("ShaderManager released"); } Shader ShaderManager::load_shader(const std::string& name, const std::string& vertex_path, const std::string& fragment_path) { // Check cache auto it = shader_cache_.find(name); if (it != shader_cache_.end()) { Logger::info("Shader '" + name + "' loaded from cache"); return it->second; } // Load shader Shader shader; if (!shader.load(vertex_path, fragment_path)) { Logger::error("Failed to load shader '" + name + "'"); return Shader(); } shader_cache_[name] = shader; Logger::info("Shader '" + name + "' loaded successfully"); return shader; } Shader ShaderManager::load_compute_shader(const std::string& name, const std::string& compute_path) { // Check cache auto it = shader_cache_.find(name); if (it != shader_cache_.end()) { Logger::info("Compute shader '" + name + "' loaded from cache"); return it->second; } // Load shader Shader shader; if (!shader.load_compute(compute_path)) { Logger::error("Failed to load compute shader '" + name + "'"); return Shader(); } shader_cache_[name] = shader; Logger::info("Compute shader '" + name + "' loaded successfully"); return shader; } Shader ShaderManager::get_shader(const std::string& name) const { auto it = shader_cache_.find(name); if (it != shader_cache_.end()) { return it->second; } Logger::warning("Shader '" + name + "' not found in cache"); return Shader(); } bool ShaderManager::load_builtin_shaders_() { // Load G-Buffer shader if (!gbuffer_shader_.load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) { Logger::error("Failed to load G-Buffer shader"); return false; } shader_cache_["gbuffer"] = gbuffer_shader_; // Load ray tracing compute shader if (!raytracing_shader_.load_compute("shaders/raytracing.comp")) { Logger::error("Failed to load ray tracing shader"); return false; } shader_cache_["raytracing"] = raytracing_shader_; // Load ray tracing compute shader Logger::info("Loading ray tracing compute shader..."); if (!raytracing_shader_.load_compute("shaders/raytracing.comp")) { Logger::error("Failed to load ray tracing shader"); return false; } shader_cache_["raytracing"] = raytracing_shader_; Logger::info("Ray tracing shader loaded successfully"); return true; } } // namespace are ``` ### 文件:src/scene/camera.cpp ```cpp #include "scene/camera.h" #include "basic/math.h" #include namespace are { Camera::Camera() : position_(0.0f, 0.0f, 5.0f) , target_(0.0f, 0.0f, 0.0f) , up_(0.0f, 1.0f, 0.0f) , projection_type_(ProjectionType::PERSPECTIVE) , fov_(glm::radians(45.0f)) , aspect_(16.0f / 9.0f) , left_(-1.0f) , right_(1.0f) , bottom_(-1.0f) , top_(1.0f) , near_(0.1f) , far_(100.0f) , view_dirty_(true) , projection_dirty_(true) { } Camera::~Camera() { } void Camera::set_perspective(float fov, float aspect, float near, float far) { projection_type_ = ProjectionType::PERSPECTIVE; fov_ = glm::radians(fov); aspect_ = aspect; near_ = near; far_ = far; projection_dirty_ = true; } void Camera::set_orthographic(float left, float right, float bottom, float top, float near, float far) { projection_type_ = ProjectionType::ORTHOGRAPHIC; left_ = left; right_ = right; bottom_ = bottom; top_ = top; near_ = near; far_ = far; projection_dirty_ = true; } void Camera::set_position(const Vec3& position) { position_ = position; view_dirty_ = true; } void Camera::set_target(const Vec3& target) { target_ = target; view_dirty_ = true; } void Camera::set_up(const Vec3& up) { up_ = up; view_dirty_ = true; } Mat4 Camera::get_view_matrix() const { if (view_dirty_) { view_matrix_ = MathUtils::look_at(position_, target_, up_); view_dirty_ = false; } return view_matrix_; } Mat4 Camera::get_projection_matrix() const { if (projection_dirty_) { if (projection_type_ == ProjectionType::PERSPECTIVE) { projection_matrix_ = MathUtils::perspective(fov_, aspect_, near_, far_); } else { projection_matrix_ = glm::ortho(left_, right_, bottom_, top_, near_, far_); } projection_dirty_ = false; } return projection_matrix_; } Mat4 Camera::get_view_projection_matrix() const { return get_projection_matrix() * get_view_matrix(); } Vec3 Camera::get_forward() const { return MathUtils::normalize(target_ - position_); } Vec3 Camera::get_right() const { Vec3 forward = get_forward(); return MathUtils::normalize(MathUtils::cross(forward, up_)); } Vec3 Camera::get_up() const { Vec3 forward = get_forward(); Vec3 right = get_right(); return MathUtils::cross(right, forward); } } // namespace are ``` ### 文件:src/scene/material.cpp ```cpp #include "scene/material.h" namespace are { Material::Material() : albedo_(1.0f, 1.0f, 1.0f) , emission_(0.0f, 0.0f, 0.0f) , metallic_(0.0f) , roughness_(0.5f) , ior_(1.5f) , type_(MaterialType::DIFFUSE) , albedo_texture_(nullptr) , normal_texture_(nullptr) { } Material::~Material() { } void Material::set_albedo(const Vec3& albedo) { albedo_ = albedo; } void Material::set_emission(const Vec3& emission) { emission_ = emission; } void Material::set_metallic(float metallic) { metallic_ = glm::clamp(metallic, 0.0f, 1.0f); } void Material::set_roughness(float roughness) { roughness_ = glm::clamp(roughness, 0.0f, 1.0f); } void Material::set_ior(float ior) { ior_ = ior; } void Material::set_type(MaterialType type) { type_ = type; } void Material::set_albedo_texture(std::shared_ptr texture) { albedo_texture_ = texture; } void Material::set_normal_texture(std::shared_ptr texture) { normal_texture_ = texture; } } // namespace are ``` ### 文件:src/scene/light.cpp ```cpp #include "scene/light.h" #include namespace are { Light::Light() : type_(LightType::POINT) , position_(0.0f, 5.0f, 0.0f) , direction_(0.0f, -1.0f, 0.0f) , color_(1.0f, 1.0f, 1.0f) , intensity_(1.0f) , range_(10.0f) , inner_angle_(glm::radians(30.0f)) , outer_angle_(glm::radians(45.0f)) { } Light::~Light() { } void Light::set_type(LightType type) { type_ = type; } void Light::set_position(const Vec3& position) { position_ = position; } void Light::set_direction(const Vec3& direction) { direction_ = glm::normalize(direction); } void Light::set_color(const Vec3& color) { color_ = color; } void Light::set_intensity(float intensity) { intensity_ = intensity; } void Light::set_range(float range) { range_ = range; } void Light::set_spot_angles(float inner_angle, float outer_angle) { inner_angle_ = glm::radians(inner_angle); outer_angle_ = glm::radians(outer_angle); } } // namespace are ``` ### 文件:src/scene/scene.cpp ```cpp #include "scene/scene.h" namespace are { Scene::Scene() { // Create default camera camera_ = std::make_shared(); } Scene::~Scene() { clear(); } uint Scene::add_mesh(std::shared_ptr mesh) { meshes_.push_back(mesh); return static_cast(meshes_.size() - 1); } uint Scene::add_material(std::shared_ptr material) { materials_.push_back(material); return static_cast(materials_.size() - 1); } uint Scene::add_light(std::shared_ptr light) { lights_.push_back(light); return static_cast(lights_.size() - 1); } void Scene::set_camera(std::shared_ptr camera) { camera_ = camera; } void Scene::clear() { meshes_.clear(); materials_.clear(); lights_.clear(); } void Scene::update(float delta_time) { // Reserved for future animation/physics updates (void)delta_time; // Suppress unused parameter warning } } // namespace are ``` ### 文件:src/scene/mesh.cpp ```cpp #include "scene/mesh.h" #include "utils/logger.h" #include namespace are { Mesh::Mesh() : material_id_(0) , transform_(1.0f) , vao_(0) , vbo_(0) , ebo_(0) , uploaded_(false) { } Mesh::~Mesh() { release_gpu_resources(); } void Mesh::set_vertices(const std::vector& vertices) { vertices_ = vertices; uploaded_ = false; } void Mesh::set_indices(const std::vector& indices) { indices_ = indices; uploaded_ = false; } void Mesh::set_material(uint material_id) { material_id_ = material_id; } void Mesh::set_transform(const Mat4& transform) { transform_ = transform; } bool Mesh::upload_to_gpu() { if (uploaded_) { Logger::warning("Mesh already uploaded to GPU"); return true; } if (vertices_.empty()) { Logger::error("Cannot upload mesh: no vertices"); return false; } if (indices_.empty()) { Logger::error("Cannot upload mesh: no indices"); return false; } // Generate VAO glGenVertexArrays(1, &vao_); glBindVertexArray(vao_); // Generate and upload VBO glGenBuffers(1, &vbo_); glBindBuffer(GL_ARRAY_BUFFER, vbo_); glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), vertices_.data(), GL_STATIC_DRAW); // Generate and upload EBO glGenBuffers(1, &ebo_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(uint), indices_.data(), GL_STATIC_DRAW); // Set vertex attributes // Location 0: Position glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position_)); // Location 1: Normal glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal_)); // Location 2: TexCoord glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord_)); // Location 3: Tangent glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, tangent_)); glBindVertexArray(0); uploaded_ = true; Logger::info("Mesh uploaded to GPU successfully"); return true; } void Mesh::release_gpu_resources() { if (!uploaded_) return; if (vao_ != 0) { glDeleteVertexArrays(1, &vao_); vao_ = 0; } if (vbo_ != 0) { glDeleteBuffers(1, &vbo_); vbo_ = 0; } if (ebo_ != 0) { glDeleteBuffers(1, &ebo_); ebo_ = 0; } uploaded_ = false; } } // namespace are ``` ### 文件:src/resource/buffer.cpp ```cpp #include "resource/buffer.h" #include "utils/logger.h" #include namespace are { namespace { GLenum get_gl_buffer_type(BufferType type) { switch (type) { case BufferType::VERTEX_BUFFER: return GL_ARRAY_BUFFER; case BufferType::INDEX_BUFFER: return GL_ELEMENT_ARRAY_BUFFER; case BufferType::UNIFORM_BUFFER: return GL_UNIFORM_BUFFER; case BufferType::SHADER_STORAGE_BUFFER: return GL_SHADER_STORAGE_BUFFER; default: return GL_ARRAY_BUFFER; } } GLenum get_gl_usage(BufferUsage usage) { switch (usage) { case BufferUsage::STATIC_DRAW: return GL_STATIC_DRAW; case BufferUsage::DYNAMIC_DRAW: return GL_DYNAMIC_DRAW; case BufferUsage::STREAM_DRAW: return GL_STREAM_DRAW; default: return GL_STATIC_DRAW; } } } Buffer::Buffer() : handle_(INVALID_HANDLE) , type_(BufferType::VERTEX_BUFFER) , size_(0) , usage_(BufferUsage::STATIC_DRAW) { } Buffer::~Buffer() { // Don't auto-release, let user control lifetime } bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) { if (handle_ != INVALID_HANDLE) { Logger::warning("Buffer already created, releasing old buffer"); release(); } type_ = type; size_ = size; usage_ = usage; glGenBuffers(1, &handle_); GLenum gl_type = get_gl_buffer_type(type); GLenum gl_usage = get_gl_usage(usage); glBindBuffer(gl_type, handle_); glBufferData(gl_type, size, data, gl_usage); glBindBuffer(gl_type, 0); Logger::info("Buffer created successfully"); return true; } void Buffer::update(size_t offset, size_t size, const void* data) { if (handle_ == INVALID_HANDLE) { Logger::error("Cannot update invalid buffer"); return; } if (offset + size > size_) { Logger::error("Buffer update out of bounds"); return; } GLenum gl_type = get_gl_buffer_type(type_); glBindBuffer(gl_type, handle_); glBufferSubData(gl_type, offset, size, data); glBindBuffer(gl_type, 0); } void Buffer::bind() const { if (handle_ == INVALID_HANDLE) { Logger::warning("Attempting to bind invalid buffer"); return; } GLenum gl_type = get_gl_buffer_type(type_); glBindBuffer(gl_type, handle_); } void Buffer::bind_base(uint binding_point) const { if (handle_ == INVALID_HANDLE) { Logger::warning("Attempting to bind invalid buffer"); return; } GLenum gl_type = get_gl_buffer_type(type_); glBindBufferBase(gl_type, binding_point, handle_); } void Buffer::unbind() const { GLenum gl_type = get_gl_buffer_type(type_); glBindBuffer(gl_type, 0); } void Buffer::release() { if (handle_ != INVALID_HANDLE) { glDeleteBuffers(1, &handle_); handle_ = INVALID_HANDLE; } size_ = 0; } } // namespace are ``` ### 文件:src/resource/model_loader.cpp ```cpp #include "resource/model_loader.h" #include "utils/logger.h" #include "resource/texture.h" // Note: This is a simplified implementation without Assimp // For full implementation, include Assimp and implement properly namespace are { bool ModelLoader::load(const std::string& path, std::vector>& meshes, std::vector>& materials, bool flip_uvs) { Logger::error("ModelLoader requires Assimp library (not implemented in this version)"); Logger::info("To implement: include , , "); // Placeholder implementation // TODO: Implement with Assimp /* Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_CalcTangentSpace | (flip_uvs ? aiProcess_FlipUVs : 0)); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { Logger::error("Failed to load model: " + std::string(importer.GetErrorString())); return false; } std::string directory = path.substr(0, path.find_last_of('/')); process_node_(scene->mRootNode, scene, meshes, materials, directory); Logger::info("Model loaded: " + path); return true; */ return false; } bool ModelLoader::load_and_upload(const std::string& path, std::vector>& meshes, std::vector>& materials, bool flip_uvs) { if (!load(path, meshes, materials, flip_uvs)) { return false; } // Upload all meshes to GPU for (auto& mesh : meshes) { if (!mesh->upload_to_gpu()) { Logger::error("Failed to upload mesh to GPU"); return false; } } return true; } void ModelLoader::process_node_(void* node, void* scene, std::vector>& meshes, std::vector>& materials, const std::string& directory) { // TODO: Implement with Assimp /* aiNode* ai_node = static_cast(node); const aiScene* ai_scene = static_cast(scene); // Process all meshes in this node for (uint i = 0; i < ai_node->mNumMeshes; ++i) { aiMesh* ai_mesh = ai_scene->mMeshes[ai_node->mMeshes[i]]; meshes.push_back(process_mesh_(ai_mesh, ai_scene, materials, directory)); } // Process children recursively for (uint i = 0; i < ai_node->mNumChildren; ++i) { process_node_(ai_node->mChildren[i], ai_scene, meshes, materials, directory); } */ } std::shared_ptr ModelLoader::process_mesh_(void* mesh, void* scene, std::vector>& materials, const std::string& directory) { // TODO: Implement with Assimp /* aiMesh* ai_mesh = static_cast(mesh); const aiScene* ai_scene = static_cast(scene); std::vector vertices; std::vector indices; // Process vertices for (uint i = 0; i < ai_mesh->mNumVertices; ++i) { Vertex vertex; vertex.position_ = Vec3(ai_mesh->mVertices[i].x, ai_mesh->mVertices[i].y, ai_mesh->mVertices[i].z); if (ai_mesh->HasNormals()) { vertex.normal_ = Vec3(ai_mesh->mNormals[i].x, ai_mesh->mNormals[i].y, ai_mesh->mNormals[i].z); } if (ai_mesh->mTextureCoords[0]) { vertex.texcoord_ = Vec2(ai_mesh->mTextureCoords[0][i].x, ai_mesh->mTextureCoords[0][i].y); } if (ai_mesh->HasTangentsAndBitangents()) { vertex.tangent_ = Vec3(ai_mesh->mTangents[i].x, ai_mesh->mTangents[i].y, ai_mesh->mTangents[i].z); } vertices.push_back(vertex); } // Process indices for (uint i = 0; i < ai_mesh->mNumFaces; ++i) { aiFace face = ai_mesh->mFaces[i]; for (uint j = 0; j < face.mNumIndices; ++j) { indices.push_back(face.mIndices[j]); } } // Process material uint material_id = materials.size(); if (ai_mesh->mMaterialIndex >= 0) { aiMaterial* ai_material = ai_scene->mMaterials[ai_mesh->mMaterialIndex]; auto material = std::make_shared(); // Load diffuse color aiColor3D color; if (ai_material->Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { material->set_albedo(Vec3(color.r, color.g, color.b)); } // Load textures load_material_textures_(ai_material, aiTextureType_DIFFUSE, material, directory); load_material_textures_(ai_material, aiTextureType_NORMALS, material, directory); materials.push_back(material); } auto mesh_obj = std::make_shared(); mesh_obj->set_vertices(vertices); mesh_obj->set_indices(indices); mesh_obj->set_material(material_id); return mesh_obj; */ return nullptr; } void ModelLoader::load_material_textures_(void* material, int type, std::shared_ptr& mat, const std::string& directory) { // TODO: Implement with Assimp /* aiMaterial* ai_material = static_cast(material); aiTextureType ai_type = static_cast(type); for (uint i = 0; i < ai_material->GetTextureCount(ai_type); ++i) { aiString str; ai_material->GetTexture(ai_type, i, &str); std::string filename = directory + "/" + std::string(str.C_Str()); auto texture = std::make_shared(); if (texture->load_from_file(filename)) { if (ai_type == aiTextureType_DIFFUSE) { mat->set_albedo_texture(texture); } else if (ai_type == aiTextureType_NORMALS) { mat->set_normal_texture(texture); } } } */ } } // namespace are ``` ### 文件:src/resource/shader.cpp ```cpp #include "resource/shader.h" #include "utils/logger.h" #include "basic/math.h" // 修改为math.h #include #include #include namespace are { Shader::Shader() : handle_(INVALID_HANDLE) { } Shader::~Shader() { // Don't auto-release, let user control lifetime } bool Shader::load(const std::string& vertex_path, const std::string& fragment_path) { std::string vertex_source = read_file_(vertex_path); std::string fragment_source = read_file_(fragment_path); if (vertex_source.empty() || fragment_source.empty()) { Logger::error("Failed to read shader files"); return false; } return compile(vertex_source, fragment_source); } bool Shader::load_compute(const std::string& compute_path) { std::string compute_source = read_file_(compute_path); if (compute_source.empty()) { Logger::error("Failed to read compute shader file"); return false; } return compile_compute(compute_source); } bool Shader::compile(const std::string& vertex_source, const std::string& fragment_source) { uint vertex_shader = compile_shader_(vertex_source, GL_VERTEX_SHADER); if (vertex_shader == 0) return false; uint fragment_shader = compile_shader_(fragment_source, GL_FRAGMENT_SHADER); if (fragment_shader == 0) { glDeleteShader(vertex_shader); return false; } uint shaders[] = { vertex_shader, fragment_shader }; bool success = link_program_(shaders, 2); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); return success; } bool Shader::compile_compute(const std::string& compute_source) { uint compute_shader = compile_shader_(compute_source, GL_COMPUTE_SHADER); if (compute_shader == 0) return false; uint shaders[] = { compute_shader }; bool success = link_program_(shaders, 1); glDeleteShader(compute_shader); return success; } void Shader::use() const { // 改为const if (handle_ != INVALID_HANDLE) { glUseProgram(handle_); } } void Shader::release() { if (handle_ != INVALID_HANDLE) { glDeleteProgram(handle_); handle_ = INVALID_HANDLE; } uniform_cache_.clear(); } void Shader::set_bool(const std::string& name, bool value) const { // 新增 glUniform1i(get_uniform_location_(name), static_cast(value)); } void Shader::set_int(const std::string& name, int value) const { // 改为const glUniform1i(get_uniform_location_(name), value); } void Shader::set_uint(const std::string& name, uint value) const { // 改为const glUniform1ui(get_uniform_location_(name), value); } void Shader::set_float(const std::string& name, float value) const { // 改为const glUniform1f(get_uniform_location_(name), value); } void Shader::set_vec2(const std::string& name, const Vec2& value) const { // 改为const glUniform2fv(get_uniform_location_(name), 1, &value[0]); } void Shader::set_vec3(const std::string& name, const Vec3& value) const { // 改为const glUniform3fv(get_uniform_location_(name), 1, &value[0]); } void Shader::set_vec4(const std::string& name, const Vec4& value) const { // 改为const glUniform4fv(get_uniform_location_(name), 1, &value[0]); } void Shader::set_mat3(const std::string& name, const Mat3& value) const { // 改为const glUniformMatrix3fv(get_uniform_location_(name), 1, GL_FALSE, &value[0][0]); } void Shader::set_mat4(const std::string& name, const Mat4& value) const { // 改为const glUniformMatrix4fv(get_uniform_location_(name), 1, GL_FALSE, MathUtils::value_ptr(value)); } int Shader::get_uniform_location_(const std::string& name) const { // 改为const auto it = uniform_cache_.find(name); if (it != uniform_cache_.end()) { return it->second; } int location = glGetUniformLocation(handle_, name.c_str()); uniform_cache_[name] = location; // mutable允许修改 if (location == -1) { Logger::warning("Uniform '" + name + "' not found in shader"); } return location; } uint Shader::compile_shader_(const std::string& source, uint type) { uint shader = glCreateShader(type); const char* source_cstr = source.c_str(); glShaderSource(shader, 1, &source_cstr, nullptr); glCompileShader(shader); int success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { char info_log[512]; glGetShaderInfoLog(shader, 512, nullptr, info_log); std::string type_str = (type == GL_VERTEX_SHADER) ? "VERTEX" : (type == GL_FRAGMENT_SHADER) ? "FRAGMENT" : "COMPUTE"; Logger::error("Shader compilation failed (" + type_str + "): " + std::string(info_log)); glDeleteShader(shader); return 0; } return shader; } bool Shader::link_program_(const uint* shaders, uint count) { handle_ = glCreateProgram(); for (uint i = 0; i < count; ++i) { glAttachShader(handle_, shaders[i]); } glLinkProgram(handle_); int success; glGetProgramiv(handle_, GL_LINK_STATUS, &success); if (!success) { char info_log[512]; glGetProgramInfoLog(handle_, 512, nullptr, info_log); Logger::error("Shader linking failed: " + std::string(info_log)); glDeleteProgram(handle_); handle_ = INVALID_HANDLE; return false; } return true; } std::string Shader::read_file_(const std::string& path) { std::ifstream file(path); if (!file.is_open()) { Logger::error("Failed to open file: " + path); return ""; } std::stringstream buffer; buffer << file.rdbuf(); return buffer.str(); } } // namespace are ``` ### 文件:src/resource/texture.cpp ```cpp #include "resource/texture.h" #include "utils/logger.h" #include #include namespace are { namespace { GLenum get_gl_internal_format(TextureFormat format) { switch (format) { case TextureFormat::R8: return GL_R8; case TextureFormat::RG8: return GL_RG8; case TextureFormat::RGB8: return GL_RGB8; case TextureFormat::RGBA8: return GL_RGBA8; case TextureFormat::R16F: return GL_R16F; case TextureFormat::RG16F: return GL_RG16F; case TextureFormat::RGB16F: return GL_RGB16F; case TextureFormat::RGBA16F: return GL_RGBA16F; case TextureFormat::R32F: return GL_R32F; case TextureFormat::RG32F: return GL_RG32F; case TextureFormat::RGB32F: return GL_RGB32F; case TextureFormat::RGBA32F: return GL_RGBA32F; case TextureFormat::DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8; default: return GL_RGBA8; } } GLenum get_gl_format(TextureFormat format) { switch (format) { case TextureFormat::R8: case TextureFormat::R16F: case TextureFormat::R32F: return GL_RED; case TextureFormat::RG8: case TextureFormat::RG16F: case TextureFormat::RG32F: return GL_RG; case TextureFormat::RGB8: case TextureFormat::RGB16F: case TextureFormat::RGB32F: return GL_RGB; case TextureFormat::RGBA8: case TextureFormat::RGBA16F: case TextureFormat::RGBA32F: return GL_RGBA; case TextureFormat::DEPTH24_STENCIL8: return GL_DEPTH_STENCIL; default: return GL_RGBA; } } GLenum get_gl_type(TextureFormat format) { switch (format) { case TextureFormat::R8: case TextureFormat::RG8: case TextureFormat::RGB8: case TextureFormat::RGBA8: return GL_UNSIGNED_BYTE; case TextureFormat::R16F: case TextureFormat::RG16F: case TextureFormat::RGB16F: case TextureFormat::RGBA16F: case TextureFormat::R32F: case TextureFormat::RG32F: case TextureFormat::RGB32F: case TextureFormat::RGBA32F: return GL_FLOAT; case TextureFormat::DEPTH24_STENCIL8: return GL_UNSIGNED_INT_24_8; default: return GL_UNSIGNED_BYTE; } } GLenum get_gl_filter(TextureFilter filter) { switch (filter) { case TextureFilter::NEAREST: return GL_NEAREST; case TextureFilter::LINEAR: return GL_LINEAR; case TextureFilter::NEAREST_MIPMAP_NEAREST: return GL_NEAREST_MIPMAP_NEAREST; case TextureFilter::LINEAR_MIPMAP_NEAREST: return GL_LINEAR_MIPMAP_NEAREST; case TextureFilter::NEAREST_MIPMAP_LINEAR: return GL_NEAREST_MIPMAP_LINEAR; case TextureFilter::LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR; default: return GL_LINEAR; } } GLenum get_gl_wrap(TextureWrap wrap) { switch (wrap) { case TextureWrap::REPEAT: return GL_REPEAT; case TextureWrap::MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; case TextureWrap::CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; case TextureWrap::CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; default: return GL_REPEAT; } } } Texture::Texture() : handle_(INVALID_HANDLE) , width_(0) , height_(0) , format_(TextureFormat::RGBA8) , has_mipmaps_(false) { } Texture::~Texture() { // Don't auto-release, let user control lifetime } bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) { // Load image using stb_image int width, height, channels; stbi_set_flip_vertically_on_load(true); unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0); if (!data) { Logger::error("Failed to load texture: " + path); return false; } // Determine format based on channels TextureFormat format; switch (channels) { case 1: format = TextureFormat::R8; break; case 2: format = TextureFormat::RG8; break; case 3: format = TextureFormat::RGB8; break; case 4: format = TextureFormat::RGBA8; break; default: Logger::error("Unsupported channel count: " + std::to_string(channels)); stbi_image_free(data); return false; } // Create texture bool success = create(width, height, format); if (!success) { stbi_image_free(data); return false; } // Upload data success = upload(data, width, height, format); stbi_image_free(data); if (!success) { return false; } // Generate mipmaps if requested if (generate_mipmaps) { this->generate_mipmaps(); } Logger::info("Texture loaded successfully: " + path); return true; } bool Texture::create(uint width, uint height, TextureFormat format) { if (handle_ != INVALID_HANDLE) { Logger::warning("Texture already created, releasing old texture"); release(); } width_ = width; height_ = height; format_ = format; glGenTextures(1, &handle_); glBindTexture(GL_TEXTURE_2D, handle_); GLenum internal_format = get_gl_internal_format(format); GLenum gl_format = get_gl_format(format); GLenum type = get_gl_type(format); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, gl_format, type, nullptr); // Set default parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBindTexture(GL_TEXTURE_2D, 0); return true; } bool Texture::upload(const void* data, uint width, uint height, TextureFormat format) { if (handle_ == INVALID_HANDLE) { Logger::error("Cannot upload to invalid texture"); return false; } if (width != width_ || height != height_ || format != format_) { Logger::warning("Upload parameters differ from texture creation, recreating texture"); create(width, height, format); } glBindTexture(GL_TEXTURE_2D, handle_); GLenum gl_format = get_gl_format(format); GLenum type = get_gl_type(format); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, gl_format, type, data); glBindTexture(GL_TEXTURE_2D, 0); return true; } void Texture::set_filter(TextureFilter min_filter, TextureFilter mag_filter) { if (handle_ == INVALID_HANDLE) { Logger::error("Cannot set filter on invalid texture"); return; } glBindTexture(GL_TEXTURE_2D, handle_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, get_gl_filter(min_filter)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, get_gl_filter(mag_filter)); glBindTexture(GL_TEXTURE_2D, 0); } void Texture::set_wrap(TextureWrap wrap_s, TextureWrap wrap_t) { if (handle_ == INVALID_HANDLE) { Logger::error("Cannot set wrap mode on invalid texture"); return; } glBindTexture(GL_TEXTURE_2D, handle_); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, get_gl_wrap(wrap_s)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, get_gl_wrap(wrap_t)); glBindTexture(GL_TEXTURE_2D, 0); } void Texture::generate_mipmaps() { if (handle_ == INVALID_HANDLE) { Logger::error("Cannot generate mipmaps for invalid texture"); return; } glBindTexture(GL_TEXTURE_2D, handle_); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); has_mipmaps_ = true; } void Texture::bind(uint unit) const { if (handle_ == INVALID_HANDLE) { Logger::warning("Attempting to bind invalid texture"); return; } glActiveTexture(GL_TEXTURE0 + unit); glBindTexture(GL_TEXTURE_2D, handle_); } void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void Texture::release() { if (handle_ != INVALID_HANDLE) { glDeleteTextures(1, &handle_); handle_ = INVALID_HANDLE; } width_ = 0; height_ = 0; has_mipmaps_ = false; } } // namespace are ``` ### 文件:src/utils/config.cpp ```cpp #include "utils/config.h" #include "utils/logger.h" #include #include #include namespace are { // Static storage static std::unordered_map g_config_map; // Helper function to trim whitespace static std::string trim(const std::string& str) { size_t first = str.find_first_not_of(" \t\r\n"); if (first == std::string::npos) return ""; size_t last = str.find_last_not_of(" \t\r\n"); return str.substr(first, last - first + 1); } bool Config::load(const std::string& path) { std::ifstream file(path); if (!file.is_open()) { Logger::error("Failed to open config file: " + path); return false; } g_config_map.clear(); std::string line; std::string current_section; while (std::getline(file, line)) { line = trim(line); // Skip empty lines and comments if (line.empty() || line[0] == '#' || line[0] == ';') { continue; } // Section header if (line[0] == '[' && line.back() == ']') { current_section = line.substr(1, line.length() - 2); continue; } // Key-value pair size_t pos = line.find('='); if (pos != std::string::npos) { std::string key = trim(line.substr(0, pos)); std::string value = trim(line.substr(pos + 1)); // Add section prefix if in a section if (!current_section.empty()) { key = current_section + "." + key; } g_config_map[key] = value; } } Logger::info("Config loaded: " + path + " (" + std::to_string(g_config_map.size()) + " entries)"); return true; } bool Config::save(const std::string& path) { std::ofstream file(path); if (!file.is_open()) { Logger::error("Failed to open config file for writing: " + path); return false; } for (const auto& pair : g_config_map) { file << pair.first << "=" << pair.second << std::endl; } Logger::info("Config saved: " + path); return true; } std::string Config::get_string(const std::string& key, const std::string& default_value) { auto it = g_config_map.find(key); if (it != g_config_map.end()) { return it->second; } return default_value; } int Config::get_int(const std::string& key, int default_value) { auto it = g_config_map.find(key); if (it != g_config_map.end()) { try { return std::stoi(it->second); } catch (...) { Logger::warning("Failed to parse int for key: " + key); } } return default_value; } float Config::get_float(const std::string& key, float default_value) { auto it = g_config_map.find(key); if (it != g_config_map.end()) { try { return std::stof(it->second); } catch (...) { Logger::warning("Failed to parse float for key: " + key); } } return default_value; } bool Config::get_bool(const std::string& key, bool default_value) { auto it = g_config_map.find(key); if (it != g_config_map.end()) { std::string value = it->second; std::transform(value.begin(), value.end(), value.begin(), ::tolower); if (value == "true" || value == "1" || value == "yes" || value == "on") { return true; } if (value == "false" || value == "0" || value == "no" || value == "off") { return false; } } return default_value; } void Config::set_string(const std::string& key, const std::string& value) { g_config_map[key] = value; } void Config::set_int(const std::string& key, int value) { g_config_map[key] = std::to_string(value); } void Config::set_float(const std::string& key, float value) { g_config_map[key] = std::to_string(value); } void Config::set_bool(const std::string& key, bool value) { g_config_map[key] = value ? "true" : "false"; } } // namespace are ``` ### 文件:src/utils/logger.cpp ```cpp #include "utils/logger.h" #include #include #include #include #include namespace are { // Static members static LogLevel g_min_level = LogLevel::DEBUG; static std::ofstream g_log_file; static bool g_initialized = false; bool Logger::initialize(const std::string& log_file) { if (g_initialized) { return true; } if (!log_file.empty()) { g_log_file.open(log_file, std::ios::out | std::ios::app); if (!g_log_file.is_open()) { std::cerr << "Failed to open log file: " << log_file << std::endl; return false; } } g_initialized = true; return true; } void Logger::shutdown() { if (g_log_file.is_open()) { g_log_file.close(); } g_initialized = false; } static std::string get_current_time() { auto now = std::time(nullptr); auto tm = *std::localtime(&now); std::ostringstream oss; oss << std::put_time(&tm, "%H:%M:%S"); return oss.str(); } static std::string level_to_string(LogLevel level) { switch (level) { case LogLevel::DEBUG: return "DEBUG"; case LogLevel::INFO: return "INFO"; case LogLevel::WARNING: return "WARN"; case LogLevel::ERROR: return "ERROR"; case LogLevel::FATAL: return "FATAL"; default: return "UNKNOWN"; } } void Logger::log(LogLevel level, const std::string& message) { if (level < g_min_level) return; std::string time_str = get_current_time(); std::string level_str = level_to_string(level); std::string formatted = "[" + time_str + "] [" + level_str + "] " + message; // Console output if (level >= LogLevel::ERROR) { std::cerr << formatted << std::endl; } else { std::cout << formatted << std::endl; } // File output if (g_log_file.is_open()) { g_log_file << formatted << std::endl; g_log_file.flush(); } } void Logger::debug(const std::string& message) { log(LogLevel::DEBUG, message); } void Logger::info(const std::string& message) { log(LogLevel::INFO, message); } void Logger::warning(const std::string& message) { log(LogLevel::WARNING, message); } void Logger::error(const std::string& message) { log(LogLevel::ERROR, message); } void Logger::fatal(const std::string& message) { log(LogLevel::FATAL, message); } void Logger::set_level(LogLevel level) { g_min_level = level; } } // namespace are ```