fix: 修复PBR纹理属性与材质值混合问题及AO实现

- 将纹理采样从乘法混合改为直接替换
- 添加Material结构的ao字段并在光照计算中正确应用
- 更新demo使用完整的PBR砖墙纹理
master
ternaryop8479 2026-03-07 13:32:25 +08:00
parent 330fdcf43d
commit 8732446237
5 changed files with 92 additions and 38 deletions

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<materialx version="1.38" fileprefix="./">
<standard_surface xpos="6.159420" name="Bricks092_1K_JPG_StandardSurface" ypos="-1.879310" type="surfaceshader">
<input name="specular" value="0" type="float" />
<input name="coat" value="1" type="float" />
<input name="coat_color" value="1, 1, 1" type="color3" />
<input name="base" value="1" type="float" />
<input nodename="Bricks092_1K_JPG_Color" name="base_color" type="color3" />
<input nodename="normalmap" name="normal" type="vector3" />
<input nodename="normalmap" name="coat_normal" type="vector3" />
<input nodename="Bricks092_1K_JPG_Roughness" name="specular_roughness" type="float" />
<input nodename="Bricks092_1K_JPG_Roughness" name="coat_roughness" type="float" />
</standard_surface>
<surfacematerial xpos="8.695652" name="Bricks092_1K_JPG" ypos="0.000000" type="material">
<input nodename="Bricks092_1K_JPG_StandardSurface" name="surfaceshader" type="surfaceshader" />
<input nodename="displacement" name="displacementshader" type="displacementshader" />
</surfacematerial>
<tiledimage xpos="3.623188" name="Bricks092_1K_JPG_Color" ypos="-3.103448" type="color3">
<input name="file" value="Bricks092_1K-JPG_Color.jpg" colorspace="srgb_texture" type="filename" />
<input name="uvtiling" value="1.0, 1.0" type="vector2" />
</tiledimage>
<tiledimage xpos="3.623188" name="Bricks092_1K_JPG_Displacement" ypos="5.163793" type="float">
<input name="file" value="Bricks092_1K-JPG_Displacement.jpg" type="filename" />
<input name="uvtiling" value="1.0, 1.0" type="vector2" />
</tiledimage>
<displacement xpos="6.159420" name="displacement" ypos="1.879310" type="displacementshader">
<input nodename="Bricks092_1K_JPG_Displacement" name="displacement" type="float" />
<input name="scale" value="1.0" type="float" />
</displacement>
<tiledimage xpos="1.086957" name="Bricks092_1K_JPG_NormalGL" ypos="0.879310" type="vector3">
<input name="file" value="Bricks092_1K-JPG_NormalGL.jpg" type="filename" />
<input name="uvtiling" value="1.0, 1.0" type="vector2" />
</tiledimage>
<normalmap xpos="3.623188" name="normalmap" ypos="3.586207" type="vector3">
<input nodename="Bricks092_1K_JPG_NormalGL" name="in" type="vector3" />
<input name="scale" value="1.0" type="float" />
</normalmap>
<tiledimage xpos="3.623188" name="Bricks092_1K_JPG_Roughness" ypos="-0.413793" type="float">
<input name="file" value="Bricks092_1K-JPG_Roughness.jpg" type="filename" />
<input name="uvtiling" value="1.0, 1.0" type="vector2" />
</tiledimage>
</materialx>

View File

@ -1,13 +1,6 @@
#include <core/renderer.h>
#include <scene/scene.h>
#include <scene/camera.h>
#include <scene/mesh.h>
#include <scene/material.h>
#include <scene/light.h>
#include <resource/texture.h>
#include <utils/logger.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <core/renderer.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
@ -223,31 +216,48 @@ void setup_cornell_box() {
metal_material->set_type(MaterialType::METAL); metal_material->set_type(MaterialType::METAL);
uint metal_id = g_scene->add_material(metal_material); uint metal_id = g_scene->add_material(metal_material);
// 5: Textured material with normal map (for short box) // 5: Textured material with PBR textures (for short box)
auto textured_material = std::make_shared<Material>(); auto textured_material = std::make_shared<Material>();
textured_material->set_albedo(Vec3(1.0f, 1.0f, 1.0f)); textured_material->set_albedo(Vec3(1.0f, 0.0f, 1.0f));
textured_material->set_metallic(1.0f); metal_material->set_metallic(1.0f);
textured_material->set_roughness(1.0f); metal_material->set_roughness(0.0f);
// textured_material->set_type(MaterialType::DIFFUSE); // textured_material->set_metallic(0.0f);
textured_material->set_type(MaterialType::METAL); // textured_material->set_roughness(0.0f);
textured_material->set_type(MaterialType::DIFFUSE);
// Load textures // Load PBR textures
// auto albedo_tex = std::make_shared<are::Texture>(); auto albedo_tex = std::make_shared<are::Texture>();
// if (albedo_tex->load_from_file("examples/assets/normal_map_cornell_box/albedo.png")) { if (albedo_tex->load_from_file("examples/assets/normal_map_cornell_box/Bricks092_1K-JPG_Color.jpg")) {
// textured_material->set_albedo_texture(albedo_tex); textured_material->set_albedo_texture(albedo_tex);
// ARE_LOG_INFO("Loaded albedo texture"); ARE_LOG_INFO("Loaded albedo texture");
// } else { } else {
// ARE_LOG_WARN("Failed to load albedo texture"); ARE_LOG_WARN("Failed to load albedo texture");
// } }
auto normal_tex = std::make_shared<are::Texture>(); auto normal_tex = std::make_shared<are::Texture>();
if (normal_tex->load_from_file("examples/assets/normal_map_cornell_box/normal.png")) { if (normal_tex->load_from_file("examples/assets/normal_map_cornell_box/Bricks092_1K-JPG_NormalGL.jpg")) {
textured_material->set_normal_texture(normal_tex); textured_material->set_normal_texture(normal_tex);
ARE_LOG_INFO("Loaded normal texture"); ARE_LOG_INFO("Loaded normal texture");
} else { } else {
ARE_LOG_WARN("Failed to load normal texture"); ARE_LOG_WARN("Failed to load normal texture");
} }
auto roughness_tex = std::make_shared<are::Texture>();
if (roughness_tex->load_from_file("examples/assets/normal_map_cornell_box/Bricks092_1K-JPG_Roughness.jpg")) {
textured_material->set_roughness_texture(roughness_tex);
ARE_LOG_INFO("Loaded roughness texture");
} else {
ARE_LOG_WARN("Failed to load roughness texture");
}
auto ao_tex = std::make_shared<are::Texture>();
if (ao_tex->load_from_file("examples/assets/normal_map_cornell_box/Bricks092_1K-JPG_AmbientOcclusion.jpg")) {
textured_material->set_ao_texture(ao_tex);
ARE_LOG_INFO("Loaded AO texture");
} else {
ARE_LOG_WARN("Failed to load AO texture");
}
uint textured_id = g_scene->add_material(textured_material); uint textured_id = g_scene->add_material(textured_material);
// 6: Glass/Dielectric (refraction) // 6: Glass/Dielectric (refraction)
@ -298,7 +308,7 @@ 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), Vec3(0.0f, 0.0f, 1.0f),
metal_id); metal_id);
// white_id); // white_id);
back_wall->upload_to_gpu(); back_wall->upload_to_gpu();
g_scene->add_mesh(back_wall); g_scene->add_mesh(back_wall);

View File

@ -43,8 +43,8 @@ struct Material {
float roughness; float roughness;
int type; int type;
float ior; float ior;
float ao; // ambient occlusion
float padding1; float padding1;
float padding2;
uint texture_handles[6]; uint texture_handles[6];
}; };
@ -458,9 +458,9 @@ vec3 apply_normal_map(vec3 normal, vec2 texcoord, vec3 tangent, uint normal_hand
void apply_material_textures(inout Material mat, inout vec3 normal, vec2 texcoord, vec3 tangent) { void apply_material_textures(inout Material mat, inout vec3 normal, vec2 texcoord, vec3 tangent) {
if (!u_enable_textures) return; if (!u_enable_textures) return;
// Albedo texture // Albedo texture (replace)
if (mat.texture_handles[0] != 0) { if (mat.texture_handles[0] != 0) {
mat.albedo *= sample_texture_array(0, int(mat.texture_handles[0]), texcoord).rgb; mat.albedo = sample_texture_array(0, int(mat.texture_handles[0]), texcoord).rgb;
} }
// Normal map // Normal map
@ -468,25 +468,24 @@ void apply_material_textures(inout Material mat, inout vec3 normal, vec2 texcoor
normal = apply_normal_map(normal, texcoord, tangent, mat.texture_handles[1]); normal = apply_normal_map(normal, texcoord, tangent, mat.texture_handles[1]);
} }
// Metallic texture // Metallic texture (replace)
if (mat.texture_handles[2] != 0) { if (mat.texture_handles[2] != 0) {
mat.metallic *= sample_texture_array(2, int(mat.texture_handles[2]), texcoord).r; mat.metallic = sample_texture_array(2, int(mat.texture_handles[2]), texcoord).r;
} }
// Roughness texture // Roughness texture (replace)
if (mat.texture_handles[3] != 0) { if (mat.texture_handles[3] != 0) {
mat.roughness *= sample_texture_array(3, int(mat.texture_handles[3]), texcoord).r; mat.roughness = sample_texture_array(3, int(mat.texture_handles[3]), texcoord).r;
} }
// AO texture (multiply) // AO texture (store in material, apply during lighting)
if (mat.texture_handles[4] != 0) { if (mat.texture_handles[4] != 0) {
float ao = sample_texture_array(4, int(mat.texture_handles[4]), texcoord).r; mat.ao = sample_texture_array(4, int(mat.texture_handles[4]), texcoord).r;
mat.albedo *= ao;
} }
// Emission texture (add) // Emission texture (replace)
if (mat.texture_handles[5] != 0) { if (mat.texture_handles[5] != 0) {
mat.emission += sample_texture_array(5, int(mat.texture_handles[5]), texcoord).rgb; mat.emission = sample_texture_array(5, int(mat.texture_handles[5]), texcoord).rgb;
} }
} }
@ -623,7 +622,8 @@ vec3 eval_direct_lighting(inout HitInfo hit, Material mat, inout uint seed) {
float pdf_light = 1.0 / float(u_light_count); float pdf_light = 1.0 / float(u_light_count);
vec3 brdf = mat.albedo * INV_PI; vec3 brdf = mat.albedo * INV_PI;
return brdf * radiance * n_dot_l / max(pdf_light, EPSILON); // Apply AO to the final lighting
return brdf * radiance * n_dot_l * mat.ao / max(pdf_light, EPSILON);
} }
// ============================================================================ // ============================================================================
@ -641,6 +641,7 @@ Material fetch_material(uint material_id) {
m.roughness = 0.5; m.roughness = 0.5;
m.type = MATERIAL_DIFFUSE; m.type = MATERIAL_DIFFUSE;
m.ior = 1.5; m.ior = 1.5;
m.ao = 1.0; // default: no AO
return m; return m;
} }

View File

@ -306,8 +306,8 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
float roughness; float roughness;
int type; int type;
float ior; float ior;
float ao;
float padding1; float padding1;
float padding2;
uint texture_handles[6]; uint texture_handles[6];
}; };
@ -322,6 +322,7 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
data.roughness = mat->get_roughness(); data.roughness = mat->get_roughness();
data.type = static_cast<int>(mat->get_type()); data.type = static_cast<int>(mat->get_type());
data.ior = mat->get_ior(); data.ior = mat->get_ior();
data.ao = 1.0f; // default: no AO
// Texture array indices (0 = no texture, 1+ = index into array) // Texture array indices (0 = no texture, 1+ = index into array)
data.texture_handles[0] = mat->get_texture_index(TextureSlot::ALBEDO); data.texture_handles[0] = mat->get_texture_index(TextureSlot::ALBEDO);