fix: 修复法线贴图计算问题并修复G-Buffer和非Primary Ray的tangent有关bug
- G-Buffer添加tangent上传 - BVH部分附加tangent到Triangle数据 - 删除原tangent近似计算代码并在代码中使用传入的tangentmaster
parent
c88e786deb
commit
330fdcf43d
Binary file not shown.
|
|
@ -226,18 +226,19 @@ void setup_cornell_box() {
|
|||
// 5: Textured material with normal map (for short box)
|
||||
auto textured_material = std::make_shared<Material>();
|
||||
textured_material->set_albedo(Vec3(1.0f, 1.0f, 1.0f));
|
||||
textured_material->set_metallic(0.0f);
|
||||
textured_material->set_roughness(0.8f);
|
||||
textured_material->set_type(MaterialType::DIFFUSE);
|
||||
textured_material->set_metallic(1.0f);
|
||||
textured_material->set_roughness(1.0f);
|
||||
// textured_material->set_type(MaterialType::DIFFUSE);
|
||||
textured_material->set_type(MaterialType::METAL);
|
||||
|
||||
// Load textures
|
||||
auto albedo_tex = std::make_shared<are::Texture>();
|
||||
if (albedo_tex->load_from_file("examples/assets/normal_map_cornell_box/albedo.png")) {
|
||||
textured_material->set_albedo_texture(albedo_tex);
|
||||
ARE_LOG_INFO("Loaded albedo texture");
|
||||
} else {
|
||||
ARE_LOG_WARN("Failed to load albedo texture");
|
||||
}
|
||||
// auto albedo_tex = std::make_shared<are::Texture>();
|
||||
// if (albedo_tex->load_from_file("examples/assets/normal_map_cornell_box/albedo.png")) {
|
||||
// textured_material->set_albedo_texture(albedo_tex);
|
||||
// ARE_LOG_INFO("Loaded albedo texture");
|
||||
// } else {
|
||||
// ARE_LOG_WARN("Failed to load albedo texture");
|
||||
// }
|
||||
|
||||
auto normal_tex = std::make_shared<are::Texture>();
|
||||
if (normal_tex->load_from_file("examples/assets/normal_map_cornell_box/normal.png")) {
|
||||
|
|
@ -296,7 +297,8 @@ void setup_cornell_box() {
|
|||
Vec3(room_size, room_size, -room_size),
|
||||
Vec3(room_size, -room_size, -room_size),
|
||||
Vec3(0.0f, 0.0f, 1.0f),
|
||||
white_id);
|
||||
metal_id);
|
||||
// white_id);
|
||||
back_wall->upload_to_gpu();
|
||||
g_scene->add_mesh(back_wall);
|
||||
|
||||
|
|
@ -361,7 +363,7 @@ void setup_cornell_box() {
|
|||
g_camera->set_position(g_cameraPos);
|
||||
g_camera->set_target(g_cameraTarget);
|
||||
g_camera->set_up(g_cameraUp);
|
||||
g_camera->set_perspective(45.0f, static_cast<float>(WINDOW_WIDTH) / WINDOW_HEIGHT, 0.1f, 100.0f);
|
||||
g_camera->set_perspective(90.0f, static_cast<float>(WINDOW_WIDTH) / WINDOW_HEIGHT, 0.1f, 100.0f);
|
||||
g_scene->set_camera(g_camera);
|
||||
|
||||
// Add point light
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ constexpr int GBUFFER_NORMAL = 1;
|
|||
constexpr int GBUFFER_ALBEDO = 2;
|
||||
constexpr int GBUFFER_MATERIAL = 3;
|
||||
constexpr int GBUFFER_MATERIAL_ID = 4;
|
||||
constexpr int GBUFFER_COUNT = 5;
|
||||
constexpr int GBUFFER_TEXCOORD = 5;
|
||||
constexpr int GBUFFER_TANGENT = 6;
|
||||
constexpr int GBUFFER_COUNT = 7;
|
||||
|
||||
// Compute shader work group size
|
||||
constexpr int COMPUTE_GROUP_SIZE_X = 16;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct Triangle {
|
|||
Vec3 v0_, v1_, v2_;
|
||||
Vec3 n0_, n1_, n2_;
|
||||
Vec2 uv0_, uv1_, uv2_;
|
||||
Vec3 t0_, t1_, t2_; // Tangents for each vertex
|
||||
uint material_id_;
|
||||
|
||||
// Get bounding box of triangle
|
||||
|
|
@ -75,6 +76,8 @@ struct TriangleGpu {
|
|||
Vec4 n2_; ///< xyz = n2, w = reserved
|
||||
Vec4 uv0_uv1_; ///< xy = uv0, zw = uv1
|
||||
Vec4 uv2_; ///< xy = uv2, zw = reserved
|
||||
Vec4 t0_; ///< xyz = t0 (tangent at v0), w = reserved
|
||||
Vec4 t1_; ///< xyz = t1 (tangent at v1), w = reserved
|
||||
};
|
||||
|
||||
// Bounding Volume Hierarchy for ray tracing acceleration
|
||||
|
|
|
|||
|
|
@ -229,6 +229,24 @@ public:
|
|||
return textures_[static_cast<int>(slot)] != nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Set texture array index for a slot (used by RayTracer)
|
||||
* @param slot Texture slot
|
||||
* @param index Index into the texture array
|
||||
*/
|
||||
void set_texture_index(TextureSlot slot, uint32_t index) {
|
||||
texture_indices_[static_cast<int>(slot)] = index;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Get texture array index for a slot
|
||||
* @param slot Texture slot
|
||||
* @return Index into the texture array (0 = no texture)
|
||||
*/
|
||||
uint32_t get_texture_index(TextureSlot slot) const {
|
||||
return texture_indices_[static_cast<int>(slot)];
|
||||
}
|
||||
|
||||
private:
|
||||
Vec3 albedo_;
|
||||
Vec3 emission_;
|
||||
|
|
@ -238,6 +256,7 @@ private:
|
|||
MaterialType type_;
|
||||
|
||||
std::array<std::shared_ptr<Texture>, static_cast<int>(TextureSlot::COUNT)> textures_;
|
||||
std::array<uint32_t, static_cast<int>(TextureSlot::COUNT)> texture_indices_;
|
||||
};
|
||||
|
||||
} // namespace are
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ layout(location = 1) out vec4 g_normal;
|
|||
layout(location = 2) out vec4 g_albedo;
|
||||
layout(location = 3) out vec4 g_material;
|
||||
layout(location = 4) out uint g_material_id;
|
||||
layout(location = 5) out vec4 g_texcoord;
|
||||
layout(location = 6) out vec4 g_tangent;
|
||||
|
||||
uniform vec3 u_albedo;
|
||||
uniform float u_metallic;
|
||||
|
|
@ -38,4 +40,10 @@ void main() {
|
|||
|
||||
g_material = vec4(u_metallic, u_roughness, u_ior, float(u_material_type));
|
||||
g_material_id = u_material_id;
|
||||
|
||||
// Store texcoord
|
||||
g_texcoord = vec4(fs_in.texcoord, 0.0, 0.0);
|
||||
|
||||
// Store tangent (xyz = tangent, w = unused)
|
||||
g_tangent = vec4(fs_in.tangent, 0.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ layout(binding = 2, rgba8) uniform readonly image2D g_albedo;
|
|||
layout(binding = 5, rgba32f) uniform readonly image2D g_material;
|
||||
layout(binding = 6, r32ui) uniform readonly uimage2D g_material_id;
|
||||
|
||||
// Texcoord from G-Buffer
|
||||
layout(binding = 7, rgba32f) uniform readonly image2D g_texcoord;
|
||||
|
||||
// Tangent from G-Buffer
|
||||
layout(binding = 8, rgba32f) uniform readonly image2D g_tangent;
|
||||
|
||||
// Output
|
||||
layout(binding = 3, rgba32f) uniform image2D output_image;
|
||||
layout(binding = 4, rgba32f) uniform image2D accumulation_image;
|
||||
|
|
@ -64,6 +70,7 @@ struct HitInfo {
|
|||
vec3 position;
|
||||
vec3 normal;
|
||||
vec2 texcoord;
|
||||
vec3 tangent;
|
||||
uint material_id;
|
||||
int material_type; // material type from G-Buffer
|
||||
};
|
||||
|
|
@ -88,6 +95,8 @@ struct TriangleGpu {
|
|||
vec4 n2;
|
||||
vec4 uv0_uv1; // xy uv0, zw uv1
|
||||
vec4 uv2; // xy uv2
|
||||
vec4 t0; // tangent at v0
|
||||
vec4 t1; // tangent at v1
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) readonly buffer MaterialBuffer { Material materials[]; };
|
||||
|
|
@ -268,11 +277,21 @@ bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) {
|
|||
vec2 uv1 = tri.uv0_uv1.zw;
|
||||
vec2 uv2 = tri.uv2.xy;
|
||||
|
||||
// Interpolate tangents
|
||||
vec3 t0 = tri.t0.xyz;
|
||||
vec3 t1 = tri.t1.xyz;
|
||||
// Compute t2 from normal and t0 (t2 = cross(n, t0))
|
||||
vec3 t2 = normalize(cross(n0, t0)); // approximate third tangent
|
||||
|
||||
hit.hit = true;
|
||||
hit.t = t;
|
||||
hit.position = ray.origin + t * ray.direction;
|
||||
hit.normal = normalize(n0 * w + n1 * u + n2 * v);
|
||||
hit.texcoord = uv0 * w + uv1 * u + uv2 * v;
|
||||
|
||||
// Interpolate tangent using barycentric coordinates
|
||||
hit.tangent = normalize(t0 * w + t1 * u + t2 * v);
|
||||
|
||||
hit.material_id = as_uint(tri.v0_material.w);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -378,6 +397,7 @@ HitInfo trace_primary_gbuffer(Ray ray, ivec2 pixel_coords) {
|
|||
hit.position = vec3(0.0);
|
||||
hit.normal = vec3(0.0, 1.0, 0.0);
|
||||
hit.texcoord = vec2(0.0);
|
||||
hit.tangent = vec3(0.0);
|
||||
hit.material_id = 0u;
|
||||
hit.material_type = 0;
|
||||
|
||||
|
|
@ -396,9 +416,19 @@ HitInfo trace_primary_gbuffer(Ray ray, ivec2 pixel_coords) {
|
|||
vec4 mat = imageLoad(g_material, pixel_coords);
|
||||
int mtype = int(mat.w);
|
||||
|
||||
// Read texcoord from G-Buffer
|
||||
vec4 texcoord_tangent = imageLoad(g_texcoord, pixel_coords);
|
||||
vec2 texcoord = texcoord_tangent.xy;
|
||||
|
||||
// Read tangent from G-Buffer
|
||||
vec4 tangent_data = imageLoad(g_tangent, pixel_coords);
|
||||
vec3 tangent = tangent_data.xyz;
|
||||
|
||||
hit.hit = true;
|
||||
hit.position = p;
|
||||
hit.normal = n;
|
||||
hit.texcoord = texcoord;
|
||||
hit.tangent = tangent;
|
||||
hit.material_id = mid;
|
||||
hit.material_type = mtype;
|
||||
|
||||
|
|
@ -425,7 +455,7 @@ vec3 apply_normal_map(vec3 normal, vec2 texcoord, vec3 tangent, uint normal_hand
|
|||
}
|
||||
|
||||
// Apply material textures to get final PBR values
|
||||
void apply_material_textures(inout Material mat, vec2 texcoord, vec3 normal, vec3 tangent) {
|
||||
void apply_material_textures(inout Material mat, inout vec3 normal, vec2 texcoord, vec3 tangent) {
|
||||
if (!u_enable_textures) return;
|
||||
|
||||
// Albedo texture
|
||||
|
|
@ -556,7 +586,7 @@ ScatterResult scatter_ray(Ray ray_in, HitInfo hit, Material mat, inout uint seed
|
|||
// Direct lighting (with shadow ray)
|
||||
// ============================================================================
|
||||
|
||||
vec3 eval_direct_lighting(HitInfo hit, Material mat, inout uint seed) {
|
||||
vec3 eval_direct_lighting(inout HitInfo hit, Material mat, inout uint seed) {
|
||||
if (u_light_count == 0u) return vec3(0.0);
|
||||
|
||||
uint light_idx = uint(random_float(seed) * float(u_light_count)) % u_light_count;
|
||||
|
|
@ -652,10 +682,8 @@ vec3 trace_path_primary_gbuffer(ivec2 pixel_coords, ivec2 image_size, inout uint
|
|||
mat0.type = hit0.material_type;
|
||||
}
|
||||
|
||||
// Apply PBR textures
|
||||
vec3 tangent0 = normalize(cross(hit0.normal, vec3(0.0, 1.0, 0.0)));
|
||||
if (length(tangent0) < 0.001) tangent0 = normalize(cross(hit0.normal, vec3(1.0, 0.0, 0.0)));
|
||||
apply_material_textures(mat0, hit0.texcoord, hit0.normal, tangent0);
|
||||
// Apply PBR textures (use tangent from G-Buffer if available)
|
||||
apply_material_textures(mat0, hit0.normal, hit0.texcoord, hit0.tangent);
|
||||
|
||||
radiance += throughput * mat0.emission;
|
||||
if (mat0.type == MATERIAL_DIFFUSE) {
|
||||
|
|
@ -679,10 +707,8 @@ vec3 trace_path_primary_gbuffer(ivec2 pixel_coords, ivec2 image_size, inout uint
|
|||
|
||||
Material mat = fetch_material(hit.material_id);
|
||||
|
||||
// Apply PBR textures
|
||||
vec3 tangent = normalize(cross(hit.normal, vec3(0.0, 1.0, 0.0)));
|
||||
if (length(tangent) < 0.001) tangent = normalize(cross(hit.normal, vec3(1.0, 0.0, 0.0)));
|
||||
apply_material_textures(mat, hit.texcoord, hit.normal, tangent);
|
||||
// Apply PBR textures (use tangent from intersection)
|
||||
apply_material_textures(mat, hit.normal, hit.texcoord, hit.tangent);
|
||||
|
||||
radiance += throughput * mat.emission;
|
||||
if (mat.type == MATERIAL_DIFFUSE) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "core/bvh.h"
|
||||
#include "utils/logger.h"
|
||||
#include "basic/constants.h"
|
||||
#include "utils/logger.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
|
|
@ -76,6 +76,11 @@ bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
|
|||
tri.n1_ = glm::normalize(normal_matrix * vertices[indices[i + 1]].normal_);
|
||||
tri.n2_ = glm::normalize(normal_matrix * vertices[indices[i + 2]].normal_);
|
||||
|
||||
// Transform tangents
|
||||
tri.t0_ = glm::normalize(normal_matrix * vertices[indices[i]].tangent_);
|
||||
tri.t1_ = glm::normalize(normal_matrix * vertices[indices[i + 1]].tangent_);
|
||||
tri.t2_ = glm::normalize(normal_matrix * vertices[indices[i + 2]].tangent_);
|
||||
|
||||
// Copy UVs
|
||||
tri.uv0_ = vertices[indices[i]].texcoord_;
|
||||
tri.uv1_ = vertices[indices[i + 1]].texcoord_;
|
||||
|
|
@ -107,8 +112,7 @@ bool BVH::build(const std::vector<std::shared_ptr<Mesh>>& meshes) {
|
|||
// Build BVH recursively
|
||||
build_recursive_(0, 0, static_cast<uint>(triangles_.size()));
|
||||
|
||||
ARE_LOG_INFO("BVH built: " + std::to_string(nodes_.size()) + " nodes, " +
|
||||
std::to_string(triangles_.size()) + " triangles");
|
||||
ARE_LOG_INFO("BVH built: " + std::to_string(nodes_.size()) + " nodes, " + std::to_string(triangles_.size()) + " triangles");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -192,7 +196,8 @@ float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float&
|
|||
// Try each axis
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
float extent = centroid_bounds.max_[a] - centroid_bounds.min_[a];
|
||||
if (extent < EPSILON) continue;
|
||||
if (extent < EPSILON)
|
||||
continue;
|
||||
|
||||
// Try multiple split positions
|
||||
const int NUM_BINS = 16;
|
||||
|
|
@ -218,10 +223,10 @@ float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float&
|
|||
}
|
||||
|
||||
// Calculate SAH cost
|
||||
if (left_count == 0 || right_count == 0) continue;
|
||||
if (left_count == 0 || right_count == 0)
|
||||
continue;
|
||||
|
||||
float cost = left_count * left_bounds.surface_area() +
|
||||
right_count * right_bounds.surface_area();
|
||||
float cost = left_count * left_bounds.surface_area() + right_count * right_bounds.surface_area();
|
||||
|
||||
if (cost < best_cost) {
|
||||
best_cost = cost;
|
||||
|
|
@ -300,6 +305,10 @@ bool BVH::upload_to_gpu(Buffer& node_buffer, Buffer& triangle_buffer) {
|
|||
g.uv0_uv1_ = Vec4(t.uv0_.x, t.uv0_.y, t.uv1_.x, t.uv1_.y);
|
||||
g.uv2_ = Vec4(t.uv2_.x, t.uv2_.y, 0.0f, 0.0f);
|
||||
|
||||
// Pack tangents
|
||||
g.t0_ = Vec4(t.t0_, 0.0f);
|
||||
g.t1_ = Vec4(t.t1_, 0.0f);
|
||||
|
||||
tri_gpu[i] = g;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ bool GBuffer::initialize() {
|
|||
// New: material id (integer)
|
||||
textures_[GBUFFER_MATERIAL_ID] = create_texture_(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT);
|
||||
|
||||
// New: texcoord + tangent (xy = texcoord, zw = tangent)
|
||||
textures_[GBUFFER_TEXCOORD] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT);
|
||||
|
||||
// New: tangent (xyz = tangent, w = unused)
|
||||
textures_[GBUFFER_TANGENT] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION,
|
||||
GL_TEXTURE_2D, textures_[GBUFFER_POSITION], 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL,
|
||||
|
|
@ -48,6 +54,10 @@ bool GBuffer::initialize() {
|
|||
GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL], 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL_ID,
|
||||
GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL_ID], 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TEXCOORD,
|
||||
GL_TEXTURE_2D, textures_[GBUFFER_TEXCOORD], 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TANGENT,
|
||||
GL_TEXTURE_2D, textures_[GBUFFER_TANGENT], 0);
|
||||
|
||||
glGenTextures(1, &depth_texture_);
|
||||
glBindTexture(GL_TEXTURE_2D, depth_texture_);
|
||||
|
|
@ -63,7 +73,9 @@ bool GBuffer::initialize() {
|
|||
GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL,
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO,
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL,
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL_ID
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL_ID,
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_TEXCOORD,
|
||||
GL_COLOR_ATTACHMENT0 + GBUFFER_TANGENT
|
||||
};
|
||||
glDrawBuffers(GBUFFER_COUNT, draw_buffers);
|
||||
|
||||
|
|
@ -81,7 +93,8 @@ bool GBuffer::initialize() {
|
|||
}
|
||||
|
||||
void GBuffer::release() {
|
||||
if (!initialized_) return;
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
if (fbo_ != INVALID_HANDLE) {
|
||||
glDeleteFramebuffers(1, &fbo_);
|
||||
|
|
@ -203,7 +216,8 @@ void GBuffer::render(const Scene& scene, const Shader& shader) {
|
|||
}
|
||||
|
||||
void GBuffer::resize(uint width, uint height) {
|
||||
if (width == width_ && height == height_) return;
|
||||
if (width == width_ && height == height_)
|
||||
return;
|
||||
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
|
|
|||
|
|
@ -162,7 +162,34 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle
|
|||
rebuild_bvh(scene);
|
||||
}
|
||||
|
||||
// Upload scene data
|
||||
// Build texture arrays BEFORE uploading materials (so indices are available)
|
||||
const auto &materials = scene.get_materials();
|
||||
bool has_textures = false;
|
||||
for (const auto &mat : materials) {
|
||||
if (mat->has_texture(TextureSlot::ALBEDO) || mat->has_texture(TextureSlot::NORMAL) || mat->has_texture(TextureSlot::METALLIC) || mat->has_texture(TextureSlot::ROUGHNESS) || mat->has_texture(TextureSlot::AO) || mat->has_texture(TextureSlot::EMISSION)) {
|
||||
has_textures = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_textures) {
|
||||
build_texture_arrays_(scene);
|
||||
|
||||
// Bind texture arrays
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[0]);
|
||||
glActiveTexture(GL_TEXTURE11);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[1]);
|
||||
glActiveTexture(GL_TEXTURE12);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[2]);
|
||||
glActiveTexture(GL_TEXTURE13);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[3]);
|
||||
glActiveTexture(GL_TEXTURE14);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[4]);
|
||||
glActiveTexture(GL_TEXTURE15);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[5]);
|
||||
}
|
||||
|
||||
// Upload scene data (materials now have correct texture indices)
|
||||
upload_scene_data_(scene);
|
||||
|
||||
// Use compute shader
|
||||
|
|
@ -197,35 +224,8 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle
|
|||
compute_shader_->set_bool("u_enable_accumulation", config_.enable_accumulation_);
|
||||
|
||||
// Enable/disable textures based on material usage
|
||||
const auto &materials = scene.get_materials();
|
||||
bool has_textures = false;
|
||||
for (const auto &mat : materials) {
|
||||
if (mat->has_texture(TextureSlot::ALBEDO) || mat->has_texture(TextureSlot::NORMAL) || mat->has_texture(TextureSlot::METALLIC) || mat->has_texture(TextureSlot::ROUGHNESS) || mat->has_texture(TextureSlot::AO) || mat->has_texture(TextureSlot::EMISSION)) {
|
||||
has_textures = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
compute_shader_->set_bool("u_enable_textures", has_textures);
|
||||
|
||||
// Build texture arrays if needed
|
||||
if (has_textures) {
|
||||
build_texture_arrays_(scene);
|
||||
|
||||
// Bind texture arrays
|
||||
glActiveTexture(GL_TEXTURE10);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[0]);
|
||||
glActiveTexture(GL_TEXTURE11);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[1]);
|
||||
glActiveTexture(GL_TEXTURE12);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[2]);
|
||||
glActiveTexture(GL_TEXTURE13);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[3]);
|
||||
glActiveTexture(GL_TEXTURE14);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[4]);
|
||||
glActiveTexture(GL_TEXTURE15);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[5]);
|
||||
}
|
||||
|
||||
// Set camera data
|
||||
const Camera &camera = scene.get_camera();
|
||||
compute_shader_->set_vec3("u_camera_position", camera.get_position());
|
||||
|
|
@ -323,13 +323,13 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
|
|||
data.type = static_cast<int>(mat->get_type());
|
||||
data.ior = mat->get_ior();
|
||||
|
||||
// Texture handles (0 = no texture)
|
||||
data.texture_handles[0] = mat->get_texture(TextureSlot::ALBEDO) ? mat->get_texture(TextureSlot::ALBEDO)->get_handle() : 0;
|
||||
data.texture_handles[1] = mat->get_texture(TextureSlot::NORMAL) ? mat->get_texture(TextureSlot::NORMAL)->get_handle() : 0;
|
||||
data.texture_handles[2] = mat->get_texture(TextureSlot::METALLIC) ? mat->get_texture(TextureSlot::METALLIC)->get_handle() : 0;
|
||||
data.texture_handles[3] = mat->get_texture(TextureSlot::ROUGHNESS) ? mat->get_texture(TextureSlot::ROUGHNESS)->get_handle() : 0;
|
||||
data.texture_handles[4] = mat->get_texture(TextureSlot::AO) ? mat->get_texture(TextureSlot::AO)->get_handle() : 0;
|
||||
data.texture_handles[5] = mat->get_texture(TextureSlot::EMISSION) ? mat->get_texture(TextureSlot::EMISSION)->get_handle() : 0;
|
||||
// Texture array indices (0 = no texture, 1+ = index into array)
|
||||
data.texture_handles[0] = mat->get_texture_index(TextureSlot::ALBEDO);
|
||||
data.texture_handles[1] = mat->get_texture_index(TextureSlot::NORMAL);
|
||||
data.texture_handles[2] = mat->get_texture_index(TextureSlot::METALLIC);
|
||||
data.texture_handles[3] = mat->get_texture_index(TextureSlot::ROUGHNESS);
|
||||
data.texture_handles[4] = mat->get_texture_index(TextureSlot::AO);
|
||||
data.texture_handles[5] = mat->get_texture_index(TextureSlot::EMISSION);
|
||||
|
||||
material_data.push_back(data);
|
||||
}
|
||||
|
|
@ -408,6 +408,12 @@ void RayTracer::bind_gbuffer_(const GBuffer &gbuffer) {
|
|||
|
||||
glBindImageTexture(5, gbuffer.get_texture(GBUFFER_MATERIAL), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||
glBindImageTexture(6, gbuffer.get_texture(GBUFFER_MATERIAL_ID), 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
|
||||
|
||||
// Texcoord
|
||||
glBindImageTexture(7, gbuffer.get_texture(GBUFFER_TEXCOORD), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||
|
||||
// Tangent
|
||||
glBindImageTexture(8, gbuffer.get_texture(GBUFFER_TANGENT), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||
}
|
||||
|
||||
void RayTracer::build_texture_arrays_(const Scene &scene) {
|
||||
|
|
@ -453,19 +459,72 @@ void RayTracer::build_texture_arrays_(const Scene &scene) {
|
|||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, width, height,
|
||||
static_cast<int>(textures[slot].size()), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
// Copy each texture to array layer
|
||||
// Copy each texture to array layer and set indices on materials
|
||||
for (size_t i = 0; i < textures[slot].size(); i++) {
|
||||
auto &tex = textures[slot][i];
|
||||
GLuint tex_handle = tex->get_handle();
|
||||
if (tex_handle != 0) {
|
||||
// Copy texture data using GetTexImage and CopyTexSubImage3D
|
||||
std::vector<uint8_t> pixels(width * height * 4);
|
||||
// Get original texture format
|
||||
TextureFormat orig_format = tex->get_format();
|
||||
int orig_width = tex->get_width();
|
||||
int orig_height = tex->get_height();
|
||||
|
||||
// Get the correct format for reading
|
||||
GLenum orig_gl_format = GL_RGBA;
|
||||
int channels = 4;
|
||||
switch (orig_format) {
|
||||
case TextureFormat::R8:
|
||||
orig_gl_format = GL_RED;
|
||||
channels = 1;
|
||||
break;
|
||||
case TextureFormat::RG8:
|
||||
orig_gl_format = GL_RG;
|
||||
channels = 2;
|
||||
break;
|
||||
case TextureFormat::RGB8:
|
||||
orig_gl_format = GL_RGB;
|
||||
channels = 3;
|
||||
break;
|
||||
case TextureFormat::RGBA8:
|
||||
orig_gl_format = GL_RGBA;
|
||||
channels = 4;
|
||||
break;
|
||||
default:
|
||||
orig_gl_format = GL_RGBA;
|
||||
channels = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Read texture data with correct format
|
||||
std::vector<uint8_t> orig_pixels(orig_width * orig_height * channels);
|
||||
glBindTexture(GL_TEXTURE_2D, tex_handle);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, orig_gl_format, GL_UNSIGNED_BYTE, orig_pixels.data());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Convert to RGBA for texture array (always RGBA8)
|
||||
std::vector<uint8_t> pixels(orig_width * orig_height * 4, 255);
|
||||
for (int y = 0; y < orig_height; y++) {
|
||||
for (int x = 0; x < orig_width; x++) {
|
||||
int src_idx = (y * orig_width + x) * channels;
|
||||
int dst_idx = (y * orig_width + x) * 4;
|
||||
pixels[dst_idx + 0] = orig_pixels[src_idx + 0];
|
||||
pixels[dst_idx + 1] = (channels >= 2) ? orig_pixels[src_idx + 1] : orig_pixels[src_idx + 0];
|
||||
pixels[dst_idx + 2] = (channels >= 3) ? orig_pixels[src_idx + 2] : orig_pixels[src_idx + 0];
|
||||
pixels[dst_idx + 3] = (channels >= 4) ? orig_pixels[src_idx + 3] : 255;
|
||||
}
|
||||
}
|
||||
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, static_cast<int>(i),
|
||||
width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
// Set texture index on all materials using this texture
|
||||
// Index is i+1 because 0 means "no texture" in the shader
|
||||
uint32_t array_index = static_cast<uint32_t>(i) + 1;
|
||||
for (const auto &mat : materials) {
|
||||
if (mat->get_texture(static_cast<TextureSlot>(slot)).get() == tex.get()) {
|
||||
mat->set_texture_index(static_cast<TextureSlot>(slot), array_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ Material::Material()
|
|||
, roughness_(0.5f)
|
||||
, ior_(1.5f)
|
||||
, type_(MaterialType::DIFFUSE)
|
||||
, textures_() {
|
||||
, textures_()
|
||||
, texture_indices_() {
|
||||
}
|
||||
|
||||
Material::~Material() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue