Skip to content

Commit

Permalink
Client: Implement vertex fog for terrain surfaces
Browse files Browse the repository at this point in the history
Not sure how accurate this is, but good enough for a first attempt.
  • Loading branch information
rdw-software committed Jan 31, 2024
1 parent 6a37b28 commit e9e8274
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Core/NativeClient/WebGPU/GPU.lua
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function GPU:RequestLogicalDevice(adapter, options)
maxTextureArrayLayers = 1, -- For the depth/stencil texture
maxVertexAttributes = 5, -- Vertex positions, vertex colors, diffuse UVs, normals, lightmap UVs
maxVertexBuffers = 5, -- Vertex positions, vertex colors, diffuse UVs, normals, lightmap UVs
maxInterStageShaderComponents = 10, -- #(vec3f color, vec2f diffuseTextureCoords, float alpha), normal(vec3f), lightmapUV(vec2f)
maxInterStageShaderComponents = 11, -- #(vec3f color, vec2f diffuseTextureCoords, float alpha), normal(vec3f), lightmapUV(vec2f), fogFactor:f32
maxBufferSize = GPU.MAX_BUFFER_SIZE, -- DEFAULT
maxVertexBufferArrayStride = 20, -- #(Rml::Vertex)
maxBindGroups = 3, -- Camera, material, transforms
Expand Down
18 changes: 17 additions & 1 deletion Core/NativeClient/WebGPU/Shaders/TerrainGeometryShader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct VertexOutput {
@location(1) diffuseTextureCoords: vec2f,
@location(2) surfaceNormal: vec3f,
@location(4) lightmapTextureCoords: vec2f,
@location(5) fogFactor: f32,
};

// CameraBindGroup: Updated once per frame
Expand All @@ -25,6 +26,9 @@ struct PerSceneData {
unusedPadding: f32,
directionalLightDirection: vec4f,
directionalLightColor: vec4f,
cameraWorldPosition: vec4f,
fogColor: vec4f,
fogLimits: vec4f,
};

@group(0) @binding(0) var<uniform> uPerSceneData: PerSceneData;
Expand Down Expand Up @@ -119,6 +123,15 @@ fn vs_main(in: VertexInput) -> VertexOutput {
out.surfaceNormal = in.surfaceNormal;
out.diffuseTextureCoords = in.diffuseTextureCoords;
out.lightmapTextureCoords = in.lightmapTextureCoords;

let worldPosition = T1 * S * homogeneousPosition;
let distance = length(worldPosition.xyz - uPerSceneData.cameraWorldPosition.xyz);

let fogNearLimit = uPerSceneData.fogLimits.x;
let fogFarLimit = uPerSceneData.fogLimits.y;
let fogFactor = (fogFarLimit - distance) / (fogFarLimit - fogNearLimit);
out.fogFactor = 1.0 - clamp(fogFactor, 0.0, 1.0);

return out;
}

Expand All @@ -143,9 +156,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let contrastCorrectionColor = clampToUnitRange(ambientColor + sunlightColor - (sunlightColor * ambientColor));
let fragmentColor = clampToUnitRange(in.color * contrastCorrectionColor * combinedLightContribution * diffuseTextureColor.rgb + lightmapTextureColor.rgb);

// Should be a no-op if fog is disabled, since the fogFactor would be zero
let foggedColor = mix(fragmentColor.rgb, uPerSceneData.fogColor.rgb, in.fogFactor);

// Gamma-correction:
// WebGPU assumes that the colors output by the fragment shader are given in linear space
// When setting the surface format to BGRA8UnormSrgb it performs a linear to sRGB conversion
let gammaCorrectedColor = pow(fragmentColor.rgb, vec3f(2.2));
let gammaCorrectedColor = pow(foggedColor.rgb, vec3f(2.2));
return vec4f(gammaCorrectedColor, diffuseTextureColor.a + DEBUG_ALPHA_OFFSET);
}

0 comments on commit e9e8274

Please sign in to comment.