Skip to content
Draft
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
2,505 changes: 2,505 additions & 0 deletions apps/typegpu-docs/public/assets/genetic-car/car-hatchback-blue.obj

Large diffs are not rendered by default.

178 changes: 178 additions & 0 deletions apps/typegpu-docs/src/examples/algorithms/genetic-racing/draw-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { createTrackOverlay } from './overlay.ts';

const MAX_CONTROL_POINTS = 512;

type DrawModeControllerOptions = {
canvas: HTMLCanvasElement;
onEnter?: () => void;
onExit?: () => void;
onPreviewTrack: (points: Float32Array) => void;
onClearPreview?: () => void;
};

export function createDrawModeController({
canvas,
onEnter,
onExit,
onPreviewTrack,
onClearPreview,
}: DrawModeControllerOptions) {
const overlay = createTrackOverlay(canvas);
const controlPoints = new Float32Array(MAX_CONTROL_POINTS * 2);

let active = false;
let pointCount = 0;
let dragIndex: number | null = null;

function currentPoints() {
return controlPoints.subarray(0, pointCount * 2);
}

function render() {
overlay.render(controlPoints, pointCount, dragIndex);
}

function clearPoints() {
pointCount = 0;
dragIndex = null;
}

function refreshPreview() {
if (!active) {
return;
}
render();
if (pointCount < 4) {
return;
}
onPreviewTrack(currentPoints());
}

function enter() {
if (active) {
return;
}
active = true;
clearPoints();
onEnter?.();
onClearPreview?.();
canvas.style.cursor = 'crosshair';
overlay.show();
render();
}

function exit() {
if (!active) {
return;
}
active = false;
dragIndex = null;
canvas.style.cursor = '';
overlay.hide();
onExit?.();
}

function confirm() {
if (!active || pointCount < 4) {
return null;
}
return new Float32Array(currentPoints());
}

function handleAspectChange() {
if (!active) {
return;
}
clearPoints();
onClearPreview?.();
render();
}

const handleMouseDown = (event: MouseEvent) => {
if (!active || event.button !== 0) {
return;
}
event.preventDefault();
const [trackX, trackY] = overlay.clientToTrack(event.clientX, event.clientY);
const hitIndex = overlay.findNearest(controlPoints, pointCount, trackX, trackY);
if (hitIndex !== null) {
dragIndex = hitIndex;
canvas.style.cursor = 'grabbing';
return;
}
if (pointCount >= MAX_CONTROL_POINTS) {
return;
}
controlPoints[pointCount * 2] = trackX;
controlPoints[pointCount * 2 + 1] = trackY;
pointCount++;
dragIndex = null;
refreshPreview();
};

const handleMouseMove = (event: MouseEvent) => {
if (!active) {
return;
}
const [trackX, trackY] = overlay.clientToTrack(event.clientX, event.clientY);
if (dragIndex !== null) {
controlPoints[dragIndex * 2] = trackX;
controlPoints[dragIndex * 2 + 1] = trackY;
refreshPreview();
return;
}
canvas.style.cursor =
overlay.findNearest(controlPoints, pointCount, trackX, trackY) !== null
? 'grab'
: 'crosshair';
};

const handleMouseUp = (event: MouseEvent) => {
if (!active || event.button !== 0) {
return;
}
dragIndex = null;
canvas.style.cursor = 'crosshair';
};

const handleContextMenu = (event: MouseEvent) => {
if (!active) {
return;
}
event.preventDefault();
if (pointCount === 0) {
return;
}
pointCount--;
refreshPreview();
};

canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
canvas.addEventListener('contextmenu', handleContextMenu);

return {
get active() {
return active;
},

get pointCount() {
return pointCount;
},

enter,
exit,
confirm,
refreshPreview,
handleAspectChange,

destroy() {
canvas.removeEventListener('mousedown', handleMouseDown);
canvas.removeEventListener('mousemove', handleMouseMove);
canvas.removeEventListener('mouseup', handleMouseUp);
canvas.removeEventListener('contextmenu', handleContextMenu);
overlay.destroy();
},
};
}
18 changes: 8 additions & 10 deletions apps/typegpu-docs/src/examples/algorithms/genetic-racing/ga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export const SimParams = d.struct({
mutationRate: d.f32,
mutationStrength: d.f32,
carSize: d.f32,
trackScale: d.f32,
trackLength: d.f32,
spawnX: d.f32,
spawnY: d.f32,
Expand All @@ -65,7 +64,6 @@ export const SimParams = d.struct({

export const CarStateArray = d.arrayOf(CarState, MAX_POP);
export const GenomeArray = d.arrayOf(Genome, MAX_POP);
export const CarStateLayout = d.arrayOf(CarState);

export const paramsAccess = tgpu.accessor(SimParams);

Expand Down Expand Up @@ -98,7 +96,7 @@ const randSignedMat4x4 = () => {

const makeSpawnState = () => {
'use gpu';
const spawn = d.vec2f(paramsAccess.$.spawnX, paramsAccess.$.spawnY) * paramsAccess.$.trackScale;
const spawn = d.vec2f(paramsAccess.$.spawnX, paramsAccess.$.spawnY);
return CarState({
position: spawn,
angle: paramsAccess.$.spawnAngle,
Expand Down Expand Up @@ -196,14 +194,14 @@ const initShader = (i: number) => {
randf.seed2(d.vec2f(d.f32(i) + 1, paramsAccess.$.generation + 11));

initLayout.$.genome[i] = Genome({
h1: InputLayer({
h1: {
wA: randSignedMat4x4(),
wB: randSignedMat4x4(),
wC: randSignedMat4x4(),
bias: d.vec4f(),
}),
h2: DenseLayer({ w: randSignedMat4x4(), bias: d.vec4f() }),
out: OutputLayer({ steer: randSignedVec4(), throttle: randSignedVec4(), bias: d.vec2f() }),
},
h2: { w: randSignedMat4x4(), bias: d.vec4f() },
out: { steer: randSignedVec4(), throttle: randSignedVec4(), bias: d.vec2f() },
});
initLayout.$.state[i] = makeSpawnState();
};
Expand Down Expand Up @@ -279,11 +277,11 @@ export function createGeneticPopulation(root: TgpuRoot, params: TgpuUniform<type
return genomeBuffers[current];
},

init() {
init(population: number) {
current = 0;
generation = 0;
initPipeline.with(initBindGroups[0]).dispatchThreads(MAX_POP);
initPipeline.with(initBindGroups[1]).dispatchThreads(MAX_POP);
initPipeline.with(initBindGroups[0]).dispatchThreads(population);
initPipeline.with(initBindGroups[1]).dispatchThreads(population);
},

reinitCurrent(population: number) {
Expand Down
Loading
Loading