19#include <entt/core/hashed_string.hpp>
37const MAX_POINT_LIGHTS: u32 = 64u;
38const MAX_DIRECTIONAL_LIGHTS: u32 = 64u;
41 @builtin(vertex_index) VertexIndex : u32
44struct VertexToFragment {
45 @builtin(position) coord : vec4f
49 viewProjectionMatrix : mat4x4f,
50 invViewProjectionMatrix : mat4x4f,
54struct DeferredOutput {
55 @location(0) color : vec4f,
74struct PointLightsData {
75 lights: array<GPUPointLight, MAX_POINT_LIGHTS>,
82struct DirectionalLight {
83 viewProjection: mat4x4f,
89struct DirectionalLightsData {
90 lights: array<DirectionalLight, 64>,
97@group(0) @binding(0) var<uniform> camera: Camera;
99@group(1) @binding(0) var gBufferNormal: texture_2d<f32>;
100@group(1) @binding(1) var gBufferAlbedo: texture_2d<f32>;
101@group(1) @binding(2) var gBufferDepth: texture_2d<f32>;
103@group(2) @binding(0) var<uniform> ambientLight : AmbientLight;
104@group(2) @binding(1) var<uniform> pointLights : PointLightsData;
105@group(2) @binding(2) var<uniform> directionalLights : DirectionalLightsData;
106@group(2) @binding(3) var lightsDirectionalTextures: texture_depth_2d_array;
107@group(2) @binding(4) var lightsDirectionalTextureSampler: sampler_comparison;
111 input : DeferredInput
112) -> VertexToFragment {
115 vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, -1.0),
116 vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0)
119 coord = vec4f(pos[input.VertexIndex], 0.9, 1.0);
120 return VertexToFragment(coord);
123fn world_from_screen_coord(coord : vec2f, depth_sample: f32) -> vec3f {
124 let posClip = vec4(coord.x * 2.0 - 1.0, (1.0 - coord.y) * 2.0 - 1.0, depth_sample, 1.0);
125 let posWorldW = camera.invViewProjectionMatrix * posClip;
126 let posWorld = posWorldW.xyz / posWorldW.www;
130// Physically plausible point-light attenuation with finite radius
131// Formula inside the radius: A * (1 - s^2)^2 / (1 + F * s), where s = d / R
132// For s >= 1 (distance >= R) the attenuation is explicitly clamped to 0.0.
133// This yields a compact-support profile that is C1-smooth at distance R (value and derivative are zero there).
134// See https://lisyarus.github.io/blog/posts/point-light-attenuation.html for more details on this model.
135fn attenuate(distance: f32, radius: f32, max_intensity: f32, falloff: f32) -> f32 {
136 let s = distance / radius;
143 let one_minus_s2 = 1.0 - s2;
145 return max_intensity * one_minus_s2 * one_minus_s2 / (1.0 + falloff * s);
148fn calculatePointLight(light: GPUPointLight, worldPos: vec3f, normal: vec3f) -> vec3f {
149 let lightDir = normalize(light.position - worldPos);
150 let distance = length(light.position - worldPos);
151 let attenuation = attenuate(distance, light.radius, light.intensity, light.falloff);
152 let diff = max(dot(normal, lightDir), 0.0);
154 return light.color * diff * attenuation;
157fn calculateDirectionalLight(light: DirectionalLight, N: vec3f, V: vec3f, MatKd: vec3f, MatKs: vec3f, Shiness: f32, position: vec3f, shadowBias: f32) -> vec3f
159 let FragPosLightSpace = light.viewProjection * vec4f(position, 1.0);
160 let shadowCoord = FragPosLightSpace.xyz / FragPosLightSpace.w;
161 let projCoord = shadowCoord * vec3f(0.5, -0.5, 1.0) + vec3f(0.5, 0.5, 0.0);
163 var visibility = 0.0;
164 let oneOverShadowDepthTextureSize = 1.0 / 2048.0;
165 let offsets = array<vec2f, 25>(
166 vec2f(-2, -2), vec2f(-1, -2), vec2f(0, -2), vec2f(1, -2), vec2f(2, -2),
167 vec2f(-2, -1), vec2f(-1, -1), vec2f(0, -1), vec2f(1, -1), vec2f(2, -1),
168 vec2f(-2, 0), vec2f(-1, 0), vec2f(0, 0), vec2f(1, 0), vec2f(2, 0),
169 vec2f(-2, 1), vec2f(-1, 1), vec2f(0, 1), vec2f(1, 1), vec2f(2, 1),
170 vec2f(-2, 2), vec2f(-1, 2), vec2f(0, 2), vec2f(1, 2), vec2f(2, 2)
173 const PCF_SAMPLES: u32 = 25u;
175 for (var i = 0u; i < PCF_SAMPLES; i++) {
176 let offset = offsets[i] * oneOverShadowDepthTextureSize;
177 visibility += textureSampleCompare(
178 lightsDirectionalTextures, lightsDirectionalTextureSampler,
179 projCoord.xy + offset, i32(light.shadowIndex), projCoord.z - shadowBias
183 if (visibility < 0.01) {
187 let L = normalize(light.direction);
188 let R = reflect(-L, N); // equivalent to 2.0 * dot(N, L) * N - L
190 let diffuse = max(0.0, dot(L, N)) * light.color.rgb;
191 // let diffuse = light.color.rgb;
193 // We clamp the dot product to 0 when it is negative
194 let RoV = max(0.0, dot(R, V));
195 let specular = pow(RoV, Shiness) * light.color.rgb;
197 return (MatKd * diffuse + MatKs * specular) * visibility;
202 vertexToFragment : VertexToFragment,
204 var output : DeferredOutput;
205 output.color = vec4(0.0, 0.0, 0.0, 1.0);
206 var coords = vec2i(floor(vertexToFragment.coord.xy));
207 const Shiness = 32.0;
209 let depth = textureLoad(gBufferDepth, coords, 0).x;
215 let bufferSize = textureDimensions(gBufferDepth);
216 let coordUV = floor(vertexToFragment.coord.xy) / vec2f(bufferSize);
217 let position = world_from_screen_coord(coordUV, depth);
219 let normal = textureLoad(gBufferNormal, coords, 0).xyz;
220 let albedo = textureLoad(gBufferAlbedo, coords, 0).rgb;
222 let N = normalize(normal);
223 let V = normalize(camera.position - position);
225 var lighting = ambientLight.color;
227 for (var i = 0u; i < MAX_POINT_LIGHTS; i++) {
228 if (i >= pointLights.count) {
231 lighting += calculatePointLight(pointLights.lights[i], position, N);
233 for (var i = 0u; i < MAX_DIRECTIONAL_LIGHTS; i++) {
234 if (i >= directionalLights.count) {
237 lighting += calculateDirectionalLight(directionalLights.lights[i], N, V, albedo, vec3f(1.0), Shiness, position, 0.007);
240 var color : vec4f = vec4f(albedo * lighting, 1.0);
241 output.color = color;
256 if (cameraView.empty())
258 Log::Error(
"Deferred::UniqueRenderCallback: No camera with GPUCamera component found.");
264 const auto &cameraBindGroup = bindGroupManager.Get(cameraGPUComponent.bindGroup);
265 renderPass.setBindGroup(0, cameraBindGroup.GetBindGroup(), 0,
nullptr);
268 renderPass.setBindGroup(1, texturesBindgroup.GetBindGroup(), 0,
nullptr);
271 renderPass.setBindGroup(2, lightsBindGroup.GetBindGroup(), 0,
nullptr);
273 renderPass.draw(6, 1, 0, 0);
282 .setSampleType(wgpu::TextureSampleType::UnfilterableFloat)
283 .setViewDimension(wgpu::TextureViewDimension::_2D)
284 .setVisibility(wgpu::ShaderStage::Fragment)
287 .setSampleType(wgpu::TextureSampleType::UnfilterableFloat)
288 .setViewDimension(wgpu::TextureViewDimension::_2D)
289 .setVisibility(wgpu::ShaderStage::Fragment)
292 .setSampleType(wgpu::TextureSampleType::UnfilterableFloat)
293 .setViewDimension(wgpu::TextureViewDimension::_2D)
294 .setVisibility(wgpu::ShaderStage::Fragment)
298 .setType(wgpu::BufferBindingType::Uniform)
300 .setVisibility(wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Vertex)
304 .setType(wgpu::BufferBindingType::Uniform)
305 .setMinBindingSize(
sizeof(glm::vec3) +
sizeof(
float))
306 .setVisibility(wgpu::ShaderStage::Fragment)
309 .setType(wgpu::BufferBindingType::Uniform)
311 .setVisibility(wgpu::ShaderStage::Fragment)
314 .setType(wgpu::BufferBindingType::Uniform)
316 .setVisibility(wgpu::ShaderStage::Fragment)
319 .setSampleType(wgpu::TextureSampleType::Depth)
320 .setViewDimension(wgpu::TextureViewDimension::_2DArray)
321 .setVisibility(wgpu::ShaderStage::Fragment)
324 .setType(wgpu::SamplerBindingType::Comparison)
325 .setVisibility(wgpu::ShaderStage::Fragment)
339 const auto validations = shaderDescriptor.
validate();
340 if (!validations.empty())
342 for (
const auto &validation : validations)
346 Log::Error(fmt::format(
"Shader Descriptor Validation Error: {} at {}", validation.message,
347 validation.location));
351 Log::Warning(fmt::format(
"Shader Descriptor Validation Warning: {} at {}", validation.message,
352 validation.location));
Deferred(std::string_view name=DEFERRED_PASS_NAME)
Definition Deferred.hpp:248
static Graphic::Resource::Shader CreateShader(Graphic::Resource::Context &graphicContext)
Definition Deferred.hpp:276
void UniqueRenderCallback(wgpu::RenderPassEncoder &renderPass, Engine::Core &core) override
Definition Deferred.hpp:250
static uint32_t GPUSize()
Definition DirectionalLightsBuffer.hpp:109
static uint32_t GPUSize()
Definition PointLightsBuffer.hpp:113
The core is the place where all the data of the engine is stored. It contains the registry (entities)...
Definition Core.hpp:33
TResource & GetResource()
Get a reference of a resource.
Definition Core.inl:14
Registry & GetRegistry()
Get the entt::registry that contains all components. It should be used to update component through sy...
Definition Core.hpp:50
Wrapper class providing a convenient interface for entity manipulation with the Core....
Definition Entity.hpp:20
decltype(auto) GetComponents()
Get components of type TComponent from the entity.
Definition Entity.hpp:118
Definition ASingleExecutionRenderPass.hpp:9
ASingleExecutionRenderPass(std::string_view name)
Definition ASingleExecutionRenderPass.hpp:11
Definition ShaderDescriptor.hpp:21
ShaderDescriptor & setVertexEntryPoint(std::string_view entryPoint)
Definition ShaderDescriptor.hpp:50
ShaderDescriptor & setName(std::string_view name)
Definition ShaderDescriptor.hpp:108
ShaderDescriptor & setFragmentEntryPoint(std::string_view entryPoint)
Definition ShaderDescriptor.hpp:56
ShaderDescriptor & addBindGroupLayout(const Utils::BindGroupLayout &layout)
Definition ShaderDescriptor.hpp:73
ShaderDescriptor & addOutputColorFormat(const Utils::ColorTargetState &state)
Definition ShaderDescriptor.hpp:84
std::vector< Utils::ValidationError > validate(void) const override
Validate the ShaderDescriptor and all contained layouts/states.
Definition ShaderDescriptor.hpp:127
ShaderDescriptor & setShader(std::string_view source)
Definition ShaderDescriptor.hpp:26
static Shader Create(const ShaderDescriptor &descriptor, Context &context)
Definition Shader.hpp:45
Definition BindGroupLayout.hpp:13
BindGroupLayout & addEntry(const TEntry &entry)
Definition BindGroupLayout.hpp:18
Definition BufferBindGroupLayoutEntry.hpp:7
Definition ColorTargetState.hpp:8
ColorTargetState & setFormat(wgpu::TextureFormat format)
Definition ColorTargetState.hpp:13
Definition SamplerBindGroupLayoutEntry.hpp:7
Definition TextureBindGroupLayoutEntry.hpp:7
Definition AmbientLight.cpp:6
static constexpr std::string_view DEFERRED_PASS_NAME
Definition Deferred.hpp:26
static const entt::hashed_string DEFERRED_PASS_ID
Definition Deferred.hpp:27
static const entt::hashed_string DEFERRED_SHADER_ID
Definition Deferred.hpp:29
static constexpr std::string_view DEFERRED_SHADER_NAME
Definition Deferred.hpp:28
static const entt::hashed_string DEFERRED_PASS_OUTPUT_ID
Definition Deferred.hpp:24
static constexpr std::string_view DEFERRED_BINDGROUP_TEXTURES_NAME
Definition Deferred.hpp:32
static constexpr std::string_view DEFERRED_SHADE_CONTENT
Definition Deferred.hpp:36
static const entt::hashed_string DEFERRED_BINDGROUP_TEXTURES_ID
Definition Deferred.hpp:33
static constexpr std::string_view DEFERRED_PASS_OUTPUT
Definition Deferred.hpp:23
static const entt::hashed_string LIGHTS_BIND_GROUP_ID
Definition Lights.hpp:9
Object::Resource::ResourceManager< std::unique_ptr< AGPUBuffer > > GPUBufferContainer
GPUBufferContainer is a resource that stores GPUBuffer resources.
Definition GPUBufferContainer.hpp:17
Object::Resource::ResourceManager< BindGroup > BindGroupManager
BindGroupManager is a resource that stores BindGroup resources.
Definition BindGroupManager.hpp:17
void Warning(const T &msg) noexcept
Definition Logger.hpp:49
void Error(const T &msg) noexcept
Definition Logger.hpp:51
Definition GPUCamera.hpp:10
static uint32_t GPUSize()
Definition CameraGPUBuffer.hpp:28
@ Warning
Definition IValidable.hpp:13
@ Error
Definition IValidable.hpp:14