Skip to content
Open
Show file tree
Hide file tree
Changes from all 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