feat(renderer): add ORM and emissive texture map support to PBR pipeline

- Extended bind group 1: albedo + normal + ORM + emissive (8 bindings)
- pbr_shader.wgsl: ORM sampling (R=AO, G=roughness, B=metallic) + emissive
- deferred_gbuffer.wgsl: ORM + emissive luminance in material_data.w
- deferred_lighting.wgsl: emissive contribution from G-Buffer
- All 5 PBR examples updated with default ORM/emissive textures
- Backward compatible: old 4-binding layout preserved

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 20:41:30 +09:00
parent 164eead5ec
commit 6bc77cb777
10 changed files with 248 additions and 27 deletions

View File

@@ -16,7 +16,7 @@ use voltex_renderer::{
gbuffer_camera_bind_group_layout,
lighting_gbuffer_bind_group_layout, lighting_lights_bind_group_layout,
lighting_shadow_bind_group_layout,
pbr_texture_bind_group_layout, create_pbr_texture_bind_group,
pbr_full_texture_bind_group_layout, create_pbr_full_texture_bind_group,
SsgiResources, SsgiUniform,
ssgi_gbuffer_bind_group_layout, ssgi_data_bind_group_layout, create_ssgi_pipeline,
RtAccel, RtInstance, BlasMeshData, RtShadowResources, RtShadowUniform,
@@ -119,6 +119,8 @@ struct AppState {
// Keep textures alive
_albedo_tex: GpuTexture,
_normal_tex: (wgpu::Texture, wgpu::TextureView, wgpu::Sampler),
_orm_tex: GpuTexture,
_emissive_tex: GpuTexture,
_shadow_map: ShadowMap,
_ibl: IblResources,
_shadow_uniform_buffer: wgpu::Buffer,
@@ -171,7 +173,7 @@ impl ApplicationHandler for DeferredDemoApp {
// G-Buffer pass bind group layouts
// ---------------------------------------------------------------
let gbuf_cam_layout = gbuffer_camera_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_texture_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_full_texture_bind_group_layout(&gpu.device);
let mat_layout = MaterialUniform::bind_group_layout(&gpu.device);
// Camera dynamic uniform buffer (one CameraUniform per sphere)
@@ -204,17 +206,23 @@ impl ApplicationHandler for DeferredDemoApp {
}],
});
// PBR textures: white albedo + flat normal
// PBR textures: white albedo + flat normal + ORM + emissive
let old_tex_layout = GpuTexture::bind_group_layout(&gpu.device);
let albedo_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let normal_tex = GpuTexture::flat_normal_1x1(&gpu.device, &gpu.queue);
let pbr_texture_bind_group = create_pbr_texture_bind_group(
let orm_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let emissive_tex = GpuTexture::black_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let pbr_texture_bind_group = create_pbr_full_texture_bind_group(
&gpu.device,
&pbr_tex_layout,
&albedo_tex.view,
&albedo_tex.sampler,
&normal_tex.1,
&normal_tex.2,
&orm_tex.view,
&orm_tex.sampler,
&emissive_tex.view,
&emissive_tex.sampler,
);
// Material bind group (dynamic offset, group 2)
@@ -581,6 +589,8 @@ impl ApplicationHandler for DeferredDemoApp {
shadow_layout,
_albedo_tex: albedo_tex,
_normal_tex: normal_tex,
_orm_tex: orm_tex,
_emissive_tex: emissive_tex,
_shadow_map: shadow_map,
_ibl: ibl,
_shadow_uniform_buffer: shadow_uniform_buffer,

View File

@@ -11,7 +11,7 @@ use voltex_renderer::{
GpuContext, Camera, FpsController, CameraUniform, LightsUniform, LightData,
Mesh, GpuTexture, MaterialUniform, generate_sphere, create_pbr_pipeline,
ShadowMap, ShadowUniform,
IblResources, pbr_texture_bind_group_layout, create_pbr_texture_bind_group,
IblResources, pbr_full_texture_bind_group_layout, create_pbr_full_texture_bind_group,
};
use wgpu::util::DeviceExt;
@@ -36,6 +36,8 @@ struct AppState {
camera_light_bind_group: wgpu::BindGroup,
_albedo_tex: GpuTexture,
_normal_tex: (wgpu::Texture, wgpu::TextureView, wgpu::Sampler),
_orm_tex: GpuTexture,
_emissive_tex: GpuTexture,
pbr_texture_bind_group: wgpu::BindGroup,
material_bind_group: wgpu::BindGroup,
shadow_bind_group: wgpu::BindGroup,
@@ -138,7 +140,7 @@ impl ApplicationHandler for IblDemoApp {
// Bind group layouts
let cl_layout = camera_light_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_texture_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_full_texture_bind_group_layout(&gpu.device);
let mat_layout = MaterialUniform::bind_group_layout(&gpu.device);
// Camera+Light bind group
@@ -163,17 +165,23 @@ impl ApplicationHandler for IblDemoApp {
],
});
// PBR texture bind group (albedo + normal)
// PBR texture bind group (albedo + normal + ORM + emissive)
let old_tex_layout = GpuTexture::bind_group_layout(&gpu.device);
let albedo_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let normal_tex = GpuTexture::flat_normal_1x1(&gpu.device, &gpu.queue);
let pbr_texture_bind_group = create_pbr_texture_bind_group(
let orm_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let emissive_tex = GpuTexture::black_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let pbr_texture_bind_group = create_pbr_full_texture_bind_group(
&gpu.device,
&pbr_tex_layout,
&albedo_tex.view,
&albedo_tex.sampler,
&normal_tex.1,
&normal_tex.2,
&orm_tex.view,
&orm_tex.sampler,
&emissive_tex.view,
&emissive_tex.sampler,
);
// IBL resources
@@ -240,6 +248,8 @@ impl ApplicationHandler for IblDemoApp {
camera_light_bind_group,
_albedo_tex: albedo_tex,
_normal_tex: normal_tex,
_orm_tex: orm_tex,
_emissive_tex: emissive_tex,
pbr_texture_bind_group,
material_bind_group,
shadow_bind_group,

View File

@@ -11,7 +11,7 @@ use voltex_renderer::{
GpuContext, Camera, FpsController, CameraUniform, LightsUniform, LightData,
Mesh, GpuTexture, MaterialUniform, generate_sphere, create_pbr_pipeline, obj,
ShadowMap, ShadowUniform,
IblResources, pbr_texture_bind_group_layout, create_pbr_texture_bind_group,
IblResources, pbr_full_texture_bind_group_layout, create_pbr_full_texture_bind_group,
};
use wgpu::util::DeviceExt;
@@ -35,6 +35,8 @@ struct AppState {
camera_light_bind_group: wgpu::BindGroup,
_albedo_tex: GpuTexture,
_normal_tex: (wgpu::Texture, wgpu::TextureView, wgpu::Sampler),
_orm_tex: GpuTexture,
_emissive_tex: GpuTexture,
pbr_texture_bind_group: wgpu::BindGroup,
material_bind_group: wgpu::BindGroup,
shadow_bind_group: wgpu::BindGroup,
@@ -149,7 +151,7 @@ impl ApplicationHandler for MultiLightApp {
// Bind group layouts
let cl_layout = camera_light_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_texture_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_full_texture_bind_group_layout(&gpu.device);
let mat_layout = MaterialUniform::bind_group_layout(&gpu.device);
// Camera+Light bind group
@@ -174,17 +176,23 @@ impl ApplicationHandler for MultiLightApp {
],
});
// PBR texture bind group (albedo + normal)
// PBR texture bind group (albedo + normal + ORM + emissive)
let old_tex_layout = GpuTexture::bind_group_layout(&gpu.device);
let albedo_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let normal_tex = GpuTexture::flat_normal_1x1(&gpu.device, &gpu.queue);
let pbr_texture_bind_group = create_pbr_texture_bind_group(
let orm_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let emissive_tex = GpuTexture::black_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let pbr_texture_bind_group = create_pbr_full_texture_bind_group(
&gpu.device,
&pbr_tex_layout,
&albedo_tex.view,
&albedo_tex.sampler,
&normal_tex.1,
&normal_tex.2,
&orm_tex.view,
&orm_tex.sampler,
&emissive_tex.view,
&emissive_tex.sampler,
);
// IBL resources
@@ -252,6 +260,8 @@ impl ApplicationHandler for MultiLightApp {
camera_light_bind_group,
_albedo_tex: albedo_tex,
_normal_tex: normal_tex,
_orm_tex: orm_tex,
_emissive_tex: emissive_tex,
pbr_texture_bind_group,
material_bind_group,
shadow_bind_group,

View File

@@ -11,7 +11,7 @@ use voltex_renderer::{
GpuContext, Camera, FpsController, CameraUniform, LightsUniform, LightData,
Mesh, GpuTexture, MaterialUniform, generate_sphere, create_pbr_pipeline,
ShadowMap, ShadowUniform,
IblResources, pbr_texture_bind_group_layout, create_pbr_texture_bind_group,
IblResources, pbr_full_texture_bind_group_layout, create_pbr_full_texture_bind_group,
};
use wgpu::util::DeviceExt;
@@ -36,6 +36,8 @@ struct AppState {
camera_light_bind_group: wgpu::BindGroup,
_albedo_tex: GpuTexture,
_normal_tex: (wgpu::Texture, wgpu::TextureView, wgpu::Sampler),
_orm_tex: GpuTexture,
_emissive_tex: GpuTexture,
pbr_texture_bind_group: wgpu::BindGroup,
material_bind_group: wgpu::BindGroup,
shadow_bind_group: wgpu::BindGroup,
@@ -134,7 +136,7 @@ impl ApplicationHandler for PbrDemoApp {
// Bind group layouts
let cl_layout = camera_light_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_texture_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_full_texture_bind_group_layout(&gpu.device);
let mat_layout = MaterialUniform::bind_group_layout(&gpu.device);
// Camera+Light bind group
@@ -159,17 +161,23 @@ impl ApplicationHandler for PbrDemoApp {
],
});
// PBR texture bind group (albedo + normal)
// PBR texture bind group (albedo + normal + ORM + emissive)
let old_tex_layout = GpuTexture::bind_group_layout(&gpu.device);
let albedo_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let normal_tex = GpuTexture::flat_normal_1x1(&gpu.device, &gpu.queue);
let pbr_texture_bind_group = create_pbr_texture_bind_group(
let orm_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let emissive_tex = GpuTexture::black_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let pbr_texture_bind_group = create_pbr_full_texture_bind_group(
&gpu.device,
&pbr_tex_layout,
&albedo_tex.view,
&albedo_tex.sampler,
&normal_tex.1,
&normal_tex.2,
&orm_tex.view,
&orm_tex.sampler,
&emissive_tex.view,
&emissive_tex.sampler,
);
// IBL resources
@@ -236,6 +244,8 @@ impl ApplicationHandler for PbrDemoApp {
camera_light_bind_group,
_albedo_tex: albedo_tex,
_normal_tex: normal_tex,
_orm_tex: orm_tex,
_emissive_tex: emissive_tex,
pbr_texture_bind_group,
material_bind_group,
shadow_bind_group,

View File

@@ -12,7 +12,7 @@ use voltex_renderer::{
Mesh, GpuTexture, MaterialUniform, generate_sphere, create_pbr_pipeline, obj,
ShadowMap, ShadowUniform, ShadowPassUniform, SHADOW_MAP_SIZE,
create_shadow_pipeline, shadow_pass_bind_group_layout,
IblResources, pbr_texture_bind_group_layout, create_pbr_texture_bind_group,
IblResources, pbr_full_texture_bind_group_layout, create_pbr_full_texture_bind_group,
};
use wgpu::util::DeviceExt;
@@ -39,6 +39,8 @@ struct AppState {
camera_light_bind_group: wgpu::BindGroup,
_albedo_tex: GpuTexture,
_normal_tex: (wgpu::Texture, wgpu::TextureView, wgpu::Sampler),
_orm_tex: GpuTexture,
_emissive_tex: GpuTexture,
pbr_texture_bind_group: wgpu::BindGroup,
material_bind_group: wgpu::BindGroup,
// Shadow resources
@@ -188,7 +190,7 @@ impl ApplicationHandler for ShadowDemoApp {
// Bind group layouts
let cl_layout = camera_light_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_texture_bind_group_layout(&gpu.device);
let pbr_tex_layout = pbr_full_texture_bind_group_layout(&gpu.device);
let mat_layout = MaterialUniform::bind_group_layout(&gpu.device);
// Camera+Light bind group
@@ -211,17 +213,23 @@ impl ApplicationHandler for ShadowDemoApp {
],
});
// PBR texture bind group (albedo + normal)
// PBR texture bind group (albedo + normal + ORM + emissive)
let old_tex_layout = GpuTexture::bind_group_layout(&gpu.device);
let albedo_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let normal_tex = GpuTexture::flat_normal_1x1(&gpu.device, &gpu.queue);
let pbr_texture_bind_group = create_pbr_texture_bind_group(
let orm_tex = GpuTexture::white_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let emissive_tex = GpuTexture::black_1x1(&gpu.device, &gpu.queue, &old_tex_layout);
let pbr_texture_bind_group = create_pbr_full_texture_bind_group(
&gpu.device,
&pbr_tex_layout,
&albedo_tex.view,
&albedo_tex.sampler,
&normal_tex.1,
&normal_tex.2,
&orm_tex.view,
&orm_tex.sampler,
&emissive_tex.view,
&emissive_tex.sampler,
);
// IBL resources
@@ -311,6 +319,8 @@ impl ApplicationHandler for ShadowDemoApp {
camera_light_bind_group,
_albedo_tex: albedo_tex,
_normal_tex: normal_tex,
_orm_tex: orm_tex,
_emissive_tex: emissive_tex,
pbr_texture_bind_group,
material_bind_group,
shadow_map,