-
-
Notifications
You must be signed in to change notification settings - Fork 21
docs: "Caustics" example #1373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
docs: "Caustics" example #1373
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
436faf0
Initial work on the caustics example
iwoplaza 066680d
Add fog
iwoplaza dd8db2d
Refactor
iwoplaza 98d37ac
More refactor
iwoplaza f6582b1
Readability improvement
iwoplaza e9f6e79
Move "Caustics" to rendering category, thumbnail
iwoplaza 92c64af
Cleanup
iwoplaza 00d5110
Control for tile density
iwoplaza 02fcfde
Cleanup
iwoplaza 0dd1c56
God rays
iwoplaza fe28a1c
Formatting
iwoplaza 69aba0b
Update thumbnail
iwoplaza 8d553da
Made triangle bigger
iwoplaza 046adde
A bit more intense rays
iwoplaza 5f26547
Update apps/typegpu-docs/src/content/examples/rendering/caustics/inde…
iwoplaza File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
apps/typegpu-docs/src/content/examples/rendering/caustics/index.html
This file contains hidden or 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 @@ | ||
<canvas></canvas> |
186 changes: 186 additions & 0 deletions
186
apps/typegpu-docs/src/content/examples/rendering/caustics/index.ts
This file contains hidden or 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,186 @@ | ||
import tgpu from 'typegpu'; | ||
import * as d from 'typegpu/data'; | ||
import * as std from 'typegpu/std'; | ||
import { perlin3d } from '@typegpu/noise'; | ||
|
||
const mainVertex = tgpu['~unstable'].vertexFn({ | ||
in: { vertexIndex: d.builtin.vertexIndex }, | ||
out: { pos: d.builtin.position, uv: d.vec2f }, | ||
})(({ vertexIndex }) => { | ||
const pos = [d.vec2f(0, 0.8), d.vec2f(-0.8, -0.8), d.vec2f(0.8, -0.8)]; | ||
const uv = [d.vec2f(0.5, 1), d.vec2f(0, 0), d.vec2f(1, 0)]; | ||
|
||
return { | ||
pos: d.vec4f(pos[vertexIndex], 0, 1), | ||
uv: uv[vertexIndex], | ||
}; | ||
}); | ||
|
||
/** | ||
* Given a coordinate, it returns a grayscale floor tile pattern at that | ||
* location. | ||
*/ | ||
const tilePattern = tgpu['~unstable'].fn([d.vec2f], d.f32)((uv) => { | ||
const tiledUv = std.fract(uv); | ||
const proximity = std.abs(std.sub(std.mul(tiledUv, 2), 1)); | ||
const maxProximity = std.max(proximity.x, proximity.y); | ||
return std.clamp(std.pow(1 - maxProximity, 0.6) * 5, 0, 1); | ||
}); | ||
|
||
const caustics = tgpu['~unstable'].fn([d.vec2f, d.f32, d.vec3f], d.vec3f)( | ||
(uv, time, profile) => { | ||
const distortion = perlin3d.sample(d.vec3f(std.mul(uv, 0.5), time * 0.2)); | ||
// Distorting UV coordinates | ||
const uv2 = std.add(uv, distortion); | ||
const noise = std.abs(perlin3d.sample(d.vec3f(std.mul(uv2, 5), time))); | ||
return std.pow(d.vec3f(1 - noise), profile); | ||
}, | ||
); | ||
|
||
const clamp01 = tgpu['~unstable'].fn([d.f32], d.f32)((v) => { | ||
return std.clamp(v, 0, 1); | ||
}); | ||
|
||
/** | ||
* Returns a transformation matrix that represents an `angle` rotation | ||
* in the XY plane (around the imaginary Z axis) | ||
*/ | ||
const rotateXY = tgpu['~unstable'].fn([d.f32], d.mat2x2f)((angle) => { | ||
return d.mat2x2f( | ||
/* right */ d.vec2f(std.cos(angle), std.sin(angle)), | ||
/* up */ d.vec2f(-std.sin(angle), std.cos(angle)), | ||
); | ||
}); | ||
|
||
const root = await tgpu.init(); | ||
|
||
const timeUniform = root['~unstable'].createUniform(d.f32); | ||
|
||
/** Controls the angle of rotation for the pool tile texture */ | ||
const angle = 0.2; | ||
/** The bigger the number, the denser the pool tile texture is */ | ||
const tileDensityUniform = root['~unstable'].createUniform(d.f32); | ||
/** The scene fades into this color at a distance */ | ||
const fogColor = d.vec3f(0.05, 0.2, 0.7); | ||
/** The ambient light color */ | ||
const ambientColor = d.vec3f(0.2, 0.5, 1); | ||
|
||
const mainFragment = tgpu['~unstable'].fragmentFn({ | ||
in: { uv: d.vec2f }, | ||
out: d.vec4f, | ||
})(({ uv }) => { | ||
const time = timeUniform.value; | ||
const tileDensity = tileDensityUniform.value; | ||
|
||
/** | ||
* A transformation matrix that skews the perspective a bit | ||
* when applied to UV coordinates | ||
*/ | ||
const skewMat = d.mat2x2f( | ||
d.vec2f(std.cos(angle), std.sin(angle)), | ||
d.vec2f(-std.sin(angle) * 10 + uv.x * 3, std.cos(angle) * 5), | ||
); | ||
const skewedUv = std.mul(skewMat, uv); | ||
const tile = tilePattern(std.mul(skewedUv, tileDensity)); | ||
const albedo = std.mix(d.vec3f(0.1), d.vec3f(1), tile); | ||
|
||
// Transforming coordinates to simulate perspective squash | ||
const cuv = d.vec2f( | ||
uv.x * (std.pow(uv.y * 1.5, 3) + 0.1) * 5, | ||
std.pow((uv.y * 1.5 + 0.1) * 1.5, 3) * 1, | ||
); | ||
// Generating two layers of caustics (large scale, and small scale) | ||
const c1 = std.mul( | ||
caustics(cuv, time * 0.2, /* profile */ d.vec3f(4, 4, 1)), | ||
// Tinting | ||
d.vec3f(0.4, 0.65, 1), | ||
); | ||
const c2 = std.mul( | ||
caustics(std.mul(cuv, 2), time * 0.4, /* profile */ d.vec3f(16, 1, 4)), | ||
// Tinting | ||
d.vec3f(0.18, 0.3, 0.5), | ||
); | ||
|
||
// -- BLEND -- | ||
|
||
const blendCoord = d.vec3f(std.mul(uv, d.vec2f(5, 10)), time * 0.2 + 5); | ||
// A smooth blending factor, so that caustics only appear at certain spots | ||
const blend = clamp01(perlin3d.sample(blendCoord) + 0.3); | ||
|
||
// -- FOG -- | ||
|
||
const noFogColor = std.mul( | ||
albedo, | ||
std.mix(ambientColor, std.add(c1, c2), blend), | ||
); | ||
// Fog blending factor, based on the height of the pixels | ||
const fog = std.min(std.pow(uv.y, 0.5) * 1.2, 1); | ||
|
||
// -- GOD RAYS -- | ||
|
||
const godRayUv = std.mul(std.mul(rotateXY(-0.3), uv), d.vec2f(15, 3)); | ||
const godRayFactor = std.pow(uv.y, 1); | ||
const godRay1 = std.mul( | ||
std.add(perlin3d.sample(d.vec3f(godRayUv, time * 0.5)), 1), | ||
// Tinting | ||
std.mul(d.vec3f(0.18, 0.3, 0.5), godRayFactor), | ||
); | ||
const godRay2 = std.mul( | ||
std.add(perlin3d.sample(d.vec3f(std.mul(godRayUv, 2), time * 0.3)), 1), | ||
// Tinting | ||
std.mul(d.vec3f(0.18, 0.3, 0.5), godRayFactor * 0.4), | ||
); | ||
const godRays = std.add(godRay1, godRay2); | ||
|
||
return d.vec4f(std.add(std.mix(noFogColor, fogColor, fog), godRays), 1); | ||
}); | ||
|
||
const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); | ||
const canvas = document.querySelector('canvas') as HTMLCanvasElement; | ||
const context = canvas.getContext('webgpu') as GPUCanvasContext; | ||
|
||
context.configure({ | ||
device: root.device, | ||
format: presentationFormat, | ||
alphaMode: 'premultiplied', | ||
}); | ||
|
||
const pipeline = root['~unstable'] | ||
.withVertex(mainVertex, {}) | ||
.withFragment(mainFragment, { format: presentationFormat }) | ||
.createPipeline(); | ||
|
||
function draw(timestamp: DOMHighResTimeStamp) { | ||
timeUniform.write((timestamp * 0.001) % 1000); | ||
|
||
pipeline | ||
.withColorAttachment({ | ||
view: context.getCurrentTexture().createView(), | ||
loadOp: 'clear', | ||
storeOp: 'store', | ||
}) | ||
.draw(3); | ||
|
||
requestAnimationFrame(draw); | ||
} | ||
requestAnimationFrame(draw); | ||
|
||
// #region Example controls and cleanup | ||
|
||
export const controls = { | ||
'tile density': { | ||
initial: 10, | ||
min: 5, | ||
max: 20, | ||
step: 1, | ||
onSliderChange: (density: number) => { | ||
tileDensityUniform.write(density); | ||
}, | ||
}, | ||
}; | ||
|
||
export function onCleanup() { | ||
root.destroy(); | ||
} | ||
|
||
// #endregion |
5 changes: 5 additions & 0 deletions
5
apps/typegpu-docs/src/content/examples/rendering/caustics/meta.json
This file contains hidden or 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,5 @@ | ||
{ | ||
"title": "Caustics", | ||
"category": "rendering", | ||
"tags": ["experimental", "fragment shader"] | ||
} |
Binary file added
BIN
+394 KB
apps/typegpu-docs/src/content/examples/rendering/caustics/thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.