-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 2d light propagation wit monte carlo path tracing.
A sort of baseline, how it could look like
- Loading branch information
Showing
9 changed files
with
575 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/scripts/light_monte_carlo_path_tracing/aces-tone-mapping.wgsl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// ACES tonemapper | ||
fn ACES(x: vec3f) -> vec3f { | ||
const a: f32 = 2.51; | ||
const b: f32 = .03; | ||
const c: f32 = 2.43; | ||
const d: f32 = .59; | ||
const e: f32 = .14; | ||
return (x * (a * x + b)) / (x * (c * x + d) + e); | ||
} | ||
|
||
// ACES fitted | ||
// from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl | ||
|
||
const ACESInputMat = mat3x3f( | ||
0.59719, 0.35458, 0.04823, | ||
0.07600, 0.90834, 0.01566, | ||
0.02840, 0.13383, 0.83777 | ||
); | ||
|
||
// ODT_SAT => XYZ => D60_2_D65 => sRGB | ||
const ACESOutputMat = mat3x3f( | ||
1.60475, -0.53108, -0.07367, | ||
-0.10208, 1.10813, -0.00605, | ||
-0.00327, -0.07276, 1.07602 | ||
); | ||
|
||
fn RRTAndODTFit(v: vec3f) -> vec3f { | ||
let a: vec3f = v * (v + 0.0245786) - 0.000090537; | ||
let b: vec3f = v * (0.983729 * v + 0.4329510) + 0.238081; | ||
return a / b; | ||
} | ||
|
||
fn ACESFitted(_color: vec3f) -> vec3f { | ||
var color: vec3f = _color * ACESInputMat; | ||
|
||
// Apply RRT and ODT | ||
color = RRTAndODTFit(color); | ||
|
||
color = color * ACESOutputMat; | ||
|
||
// Clamp to [0, 1] | ||
color = clamp(color, vec3f(0.0), vec3f(1.0)); | ||
|
||
return color; | ||
} | ||
|
||
//--------------------------------------------------------------------------------- | ||
|
||
fn linear_srgb(x: f32) -> f32 { | ||
return mix(1.055*pow(x, 1./2.4) - 0.055, 12.92*x, step(x,0.0031308)); | ||
} | ||
|
||
fn linear_srgb_vec(x: vec3f) -> vec3f { | ||
return mix(1.055*pow(x, vec3f(1./2.4)) - 0.055, 12.92*x, step(x,vec3f(0.0031308))); | ||
} | ||
|
||
fn srgb_linear(x: f32) -> f32 { | ||
return mix(pow((x + 0.055)/1.055,2.4), x / 12.92, step(x,0.04045)); | ||
} | ||
|
||
fn srgb_linear_vec(x: vec3f) -> vec3f { | ||
return mix(pow((x + 0.055)/1.055,vec3f(2.4)), x / 12.92, step(x,vec3f(0.04045))); | ||
} | ||
|
||
@group(0) @binding(0) var texture: texture_2d_array<f32>; | ||
@group(0) @binding(1) var scene: texture_2d_array<f32>; | ||
|
||
struct VertexOutput { | ||
@builtin(position) Position : vec4f, | ||
@location(0) fragUV : vec2f | ||
}; | ||
|
||
@fragment | ||
fn main(data: VertexOutput) -> @location(0) vec4f { | ||
var iResolution = vec2f(textureDimensions(texture, 0)); | ||
let p = vec2i(data.fragUV*iResolution); | ||
|
||
let color = textureLoad(texture, p, 0, 0).xyz; | ||
let fragColor = vec4f(linear_srgb_vec(ACESFitted(max(color, vec3f(0.0)))), 1.0); | ||
return fragColor; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import {GPU} from "../webgpu/gpu"; | ||
import {Texture} from "../webgpu/texture"; | ||
import {Buffer} from "../webgpu/buffer"; | ||
import {GPUAbstractRunner, RunnerType} from "../AbstractGPURunner"; | ||
import {Render} from "../render/render"; | ||
import {LightScene} from "./scene/scene"; | ||
import {ShowError} from "../ui"; | ||
|
||
export class LightMonteCarloPathTracing extends GPUAbstractRunner { | ||
width: number | ||
height: number | ||
|
||
render: Render | ||
scene: LightScene | ||
|
||
textureDest: Texture | ||
textureSrc: Texture | ||
|
||
bind_group_layout: GPUBindGroupLayout | ||
bind_group_atob: GPUBindGroup | ||
bind_group_btoa: GPUBindGroup | ||
|
||
scene_bind_group_layout: GPUBindGroupLayout | ||
scene_bind_group: GPUBindGroup | ||
|
||
pipeline_layout: GPUPipelineLayout | ||
compute_pipeline: GPUComputePipeline | ||
shader: GPUProgrammableStage | ||
|
||
stagingBuffer: Buffer | ||
stagingData: Float32Array | ||
|
||
constructor() { | ||
super() | ||
this.width = GPU.viewport.width | ||
this.height = GPU.viewport.height | ||
} | ||
|
||
getType(): RunnerType { | ||
return RunnerType.ANIM | ||
} | ||
|
||
async Destroy() { | ||
this.textureDest.destroy() | ||
this.textureSrc.destroy() | ||
} | ||
|
||
async Init() { | ||
console.log("Create Texture") | ||
|
||
this.textureDest = GPU.CreateStorageTextureArray(this.width, this.height, 3, "rgba32float") | ||
this.textureSrc = GPU.CreateStorageTextureArray(this.width, this.height, 3, "rgba32float") | ||
|
||
this.stagingBuffer = GPU.CreateUniformBuffer(4 * 4) // must be a multiple of 16 bytes | ||
this.stagingData = new Float32Array(4) | ||
|
||
this.scene = new LightScene(this.stagingBuffer) | ||
try { | ||
await this.scene.Init() | ||
} catch (e) { | ||
ShowError("Creation of Scene failed", e as Error) | ||
throw e | ||
} | ||
|
||
console.log("Create Render") | ||
this.render = new Render( | ||
[this.textureSrc, this.scene.emitter], | ||
"scripts/light_monte_carlo_path_tracing/aces-tone-mapping.wgsl") | ||
await this.render.Init() | ||
|
||
this.shader = await GPU.CreateShaderFromURL("scripts/light_monte_carlo_path_tracing/propagate.wgsl") | ||
|
||
this.bind_group_layout = GPU.device.createBindGroupLayout({ | ||
entries: [ | ||
{ | ||
binding: 0, | ||
visibility: GPUShaderStage.COMPUTE, | ||
texture: { | ||
sampleType: "unfilterable-float", | ||
viewDimension: "2d-array" | ||
} | ||
}, { | ||
binding: 1, | ||
visibility: GPUShaderStage.COMPUTE, | ||
storageTexture: { | ||
access: "write-only", | ||
format: this.textureDest.format, | ||
viewDimension: "2d-array" | ||
} | ||
}, { | ||
binding: 2, | ||
visibility: GPUShaderStage.COMPUTE, | ||
buffer: { | ||
type: "uniform" | ||
} | ||
}] | ||
}) | ||
|
||
this.bind_group_atob = GPU.device.createBindGroup({ | ||
layout: this.bind_group_layout, | ||
entries: [{ | ||
binding: 0, | ||
resource: this.textureSrc.textureView | ||
}, { | ||
binding: 1, | ||
resource: this.textureDest.textureView | ||
}, { | ||
binding: 2, | ||
resource: this.stagingBuffer.resource | ||
}] | ||
}) | ||
|
||
this.bind_group_btoa = GPU.device.createBindGroup({ | ||
layout: this.bind_group_layout, | ||
entries: [{ | ||
binding: 0, | ||
resource: this.textureDest.textureView | ||
}, { | ||
binding: 1, | ||
resource: this.textureSrc.textureView | ||
}, { | ||
binding: 2, | ||
resource: this.stagingBuffer.resource | ||
}] | ||
}) | ||
|
||
this.scene_bind_group_layout = GPU.device.createBindGroupLayout({ | ||
entries: [ | ||
{ | ||
binding: 0, | ||
visibility: GPUShaderStage.COMPUTE, | ||
texture: { | ||
sampleType: "unfilterable-float", | ||
viewDimension: "2d-array" | ||
} | ||
}] | ||
}) | ||
|
||
this.scene_bind_group = GPU.device.createBindGroup({ | ||
layout: this.scene_bind_group_layout, | ||
entries: [{ | ||
binding: 0, | ||
resource: this.scene.emitter.textureView | ||
}] | ||
}) | ||
|
||
this.pipeline_layout = GPU.device.createPipelineLayout({ | ||
bindGroupLayouts: [this.bind_group_layout, this.scene_bind_group_layout] | ||
}) | ||
|
||
this.compute_pipeline = GPU.device.createComputePipeline({ | ||
layout: this.pipeline_layout, | ||
compute: this.shader | ||
}) | ||
} | ||
|
||
previousMouseCoordinatex: number = 0 | ||
previousMouseCoordinatey: number = 0 | ||
previousMouseWheel: number = 0 | ||
|
||
|
||
GetCommandBuffer(): GPUCommandBuffer { | ||
this.stagingData[0] = GPU.mouseCoordinate.x; // set iMouseX | ||
this.stagingData[1] = GPU.mouseCoordinate.y; // set iMouseY | ||
this.stagingData[2] = GPU.mouseCoordinate.wheel; | ||
this.stagingData[3] += 1.; // increase iFrame | ||
|
||
if (this.previousMouseCoordinatex != GPU.mouseCoordinate.x || this.previousMouseCoordinatey != GPU.mouseCoordinate.y || this.previousMouseWheel != GPU.mouseCoordinate.wheel) { | ||
this.stagingData[3] = 0 // reset iFrame | ||
} | ||
this.previousMouseCoordinatex = GPU.mouseCoordinate.x | ||
this.previousMouseCoordinatey = GPU.mouseCoordinate.y | ||
this.previousMouseWheel = GPU.mouseCoordinate.wheel | ||
|
||
GPU.device.queue.writeBuffer(this.stagingBuffer.buffer, 0, this.stagingData) | ||
|
||
let encoder: GPUCommandEncoder = GPU.device.createCommandEncoder({}); | ||
|
||
let pass: GPUComputePassEncoder = encoder.beginComputePass(); | ||
pass.setBindGroup(0, this.bind_group_atob); | ||
pass.setBindGroup(1, this.scene_bind_group); | ||
pass.setPipeline(this.compute_pipeline); | ||
pass.dispatchWorkgroups(this.width / 8, this.height / 8); | ||
pass.end(); | ||
|
||
encoder.copyTextureToTexture( | ||
{texture: this.textureDest.texture}, | ||
{texture: this.textureSrc.texture}, | ||
[this.width, this.height, this.textureSrc.depth]) | ||
|
||
return encoder.finish(); | ||
} | ||
|
||
async Run() { | ||
GPU.device.queue.submit([this.scene.GetCommandBuffer(), this.GetCommandBuffer(), this.render.getCommandBuffer()]); | ||
await GPU.device.queue.onSubmittedWorkDone(); | ||
} | ||
|
||
} |
Oops, something went wrong.