Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import FluidDoubleBuffering from './examples/FluidDoubleBuffering';
import FluidWithAtomics from './examples/FluidWithAtomics';
import FunctionVisualizer from './examples/FunctionVisualizer';
import GameOfLife from './examples/GameOfLife';
import StableFluids from './examples/StableFluids/StableFluids';

const examples = ['🐠', '🚰', '🎮', '📈', '🛁', '🐥'];
const examples = ['🐠', '🚰', '🎮', '📈', '🛁', '🐥', '🌊'] as const;

export default function App() {
const [currentExample, setCurrentExample] =
Expand Down Expand Up @@ -37,6 +38,8 @@ export default function App() {
<FunctionVisualizer />
) : currentExample === '🐠' ? (
<Fish />
) : currentExample === '🌊' ? (
<StableFluids />
) : null}
</View>
<View
Expand Down
Binary file added assets/plums.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
152 changes: 73 additions & 79 deletions examples/Boids.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useWebGPU } from '../useWebGPU';
const triangleAmount = 500;
const triangleSize = 0.08;

const rotate = tgpu['~unstable'].fn([d.vec2f, d.f32], d.vec2f).does(/* wgsl */ `
const rotate = tgpu['~unstable'].fn([d.vec2f, d.f32], d.vec2f)`
(v: vec2f, angle: f32) -> vec2f {
let pos = vec2(
(v.x * cos(angle)) - (v.y * sin(angle)),
Expand All @@ -16,14 +16,13 @@ const rotate = tgpu['~unstable'].fn([d.vec2f, d.f32], d.vec2f).does(/* wgsl */ `

return pos;
}
`);
`;

const getRotationFromVelocity = tgpu['~unstable']
.fn([d.vec2f], d.f32)
.does(/* wgsl */ `
.fn([d.vec2f], d.f32)/* wgsl */ `
(velocity: vec2f) -> f32 {
return -atan2(velocity.x, velocity.y);
}`);
}`;

const TriangleData = d.struct({
position: d.vec2f,
Expand All @@ -46,35 +45,31 @@ const mainVert = tgpu['~unstable']
.vertexFn({
in: { v: d.vec2f, center: d.vec2f, velocity: d.vec2f },
out: VertexOutput,
})
.does(/* wgsl */ `(input: VertexInput) -> VertexOutput {
let angle = getRotationFromVelocity(input.velocity);
let rotated = rotate(input.v, angle);
})`{
let angle = getRotationFromVelocity(in.velocity);
let rotated = rotate(in.v, angle);

let pos = vec4(rotated + input.center, 0.0, 1.0);
let pos = vec4(rotated + in.center, 0.0, 1.0);

let color = vec4(
sin(angle + colorPalette.r) * 0.45 + 0.45,
sin(angle + colorPalette.g) * 0.45 + 0.45,
sin(angle + colorPalette.b) * 0.45 + 0.45,
1.0);
let color = vec4(
sin(angle + colorPalette.r) * 0.45 + 0.45,
sin(angle + colorPalette.g) * 0.45 + 0.45,
sin(angle + colorPalette.b) * 0.45 + 0.45,
1.0);

return VertexOutput(pos, color);
}`)
.$uses({
return Out(pos, color);
}
`.$uses({
trianglePos,
colorPalette,
getRotationFromVelocity,
rotate,
});

const mainFrag = tgpu['~unstable']
.fragmentFn({ in: VertexOutput, out: d.vec4f })
.does(/* wgsl */ `
(input: FragmentInput) -> @location(0) vec4f {
return input.color;
}
`);
.fragmentFn({ in: VertexOutput, out: d.vec4f })`{
return in.color;
}`;

const Params = d
.struct({
Expand Down Expand Up @@ -214,62 +209,61 @@ export default function () {
.computeFn({
in: { gid: d.builtin.globalInvocationId },
workgroupSize: [1],
})
.does(/* wgsl */ `(input: ComputeInput) {
let index = input.gid.x;
var instanceInfo = currentTrianglePos[index];
var separation = vec2f();
var alignment = vec2f();
var cohesion = vec2f();
var alignmentCount = 0u;
var cohesionCount = 0u;

for (var i = 0u; i < arrayLength(&currentTrianglePos); i += 1) {
if (i == index) {
continue;
}
var other = currentTrianglePos[i];
var dist = distance(instanceInfo.position, other.position);
if (dist < params.separationDistance) {
separation += instanceInfo.position - other.position;
}
if (dist < params.alignmentDistance) {
alignment += other.velocity;
alignmentCount++;
}
if (dist < params.cohesionDistance) {
cohesion += other.position;
cohesionCount++;
})`{
let index = in.gid.x;
var instanceInfo = currentTrianglePos[index];
var separation = vec2f();
var alignment = vec2f();
var cohesion = vec2f();
var alignmentCount = 0u;
var cohesionCount = 0u;

for (var i = 0u; i < arrayLength(&currentTrianglePos); i += 1) {
if (i == index) {
continue;
}
var other = currentTrianglePos[i];
var dist = distance(instanceInfo.position, other.position);
if (dist < params.separationDistance) {
separation += instanceInfo.position - other.position;
}
if (dist < params.alignmentDistance) {
alignment += other.velocity;
alignmentCount++;
}
if (dist < params.cohesionDistance) {
cohesion += other.position;
cohesionCount++;
}
};
if (alignmentCount > 0u) {
alignment = alignment / f32(alignmentCount);
}
if (cohesionCount > 0u) {
cohesion = (cohesion / f32(cohesionCount)) - instanceInfo.position;
}
instanceInfo.velocity +=
(separation * params.separationStrength)
+ (alignment * params.alignmentStrength)
+ (cohesion * params.cohesionStrength);
instanceInfo.velocity = normalize(instanceInfo.velocity) * clamp(length(instanceInfo.velocity), 0.0, 0.01);

if (instanceInfo.position[0] > 1.0 + triangleSize) {
instanceInfo.position[0] = -1.0 - triangleSize;
}
if (instanceInfo.position[1] > 1.0 + triangleSize) {
instanceInfo.position[1] = -1.0 - triangleSize;
}
if (instanceInfo.position[0] < -1.0 - triangleSize) {
instanceInfo.position[0] = 1.0 + triangleSize;
}
if (instanceInfo.position[1] < -1.0 - triangleSize) {
instanceInfo.position[1] = 1.0 + triangleSize;
}
instanceInfo.position += instanceInfo.velocity;
nextTrianglePos[index] = instanceInfo;
}
};
if (alignmentCount > 0u) {
alignment = alignment / f32(alignmentCount);
}
if (cohesionCount > 0u) {
cohesion = (cohesion / f32(cohesionCount)) - instanceInfo.position;
}
instanceInfo.velocity +=
(separation * params.separationStrength)
+ (alignment * params.alignmentStrength)
+ (cohesion * params.cohesionStrength);
instanceInfo.velocity = normalize(instanceInfo.velocity) * clamp(length(instanceInfo.velocity), 0.0, 0.01);

if (instanceInfo.position[0] > 1.0 + triangleSize) {
instanceInfo.position[0] = -1.0 - triangleSize;
}
if (instanceInfo.position[1] > 1.0 + triangleSize) {
instanceInfo.position[1] = -1.0 - triangleSize;
}
if (instanceInfo.position[0] < -1.0 - triangleSize) {
instanceInfo.position[0] = 1.0 + triangleSize;
}
if (instanceInfo.position[1] < -1.0 - triangleSize) {
instanceInfo.position[1] = 1.0 + triangleSize;
}
instanceInfo.position += instanceInfo.velocity;
nextTrianglePos[index] = instanceInfo;
}`)
.$uses({ currentTrianglePos, nextTrianglePos, params, triangleSize });
`.$uses({ currentTrianglePos, nextTrianglePos, params, triangleSize });

const computePipeline = root['~unstable']
.withCompute(mainCompute)
Expand Down
Loading