Skip to content

Commit

Permalink
Merge pull request #19 from Triadica/halvorsen
Browse files Browse the repository at this point in the history
demo of halvorsen attractor
  • Loading branch information
NoEgAm authored May 6, 2024
2 parents 6e50f50 + 7469856 commit 56c4ef4
Show file tree
Hide file tree
Showing 2 changed files with 256 additions and 0 deletions.
78 changes: 78 additions & 0 deletions src/apps/attractor-halvorsen.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { createRenderer } from "../index.mjs";
import attractorCompute from "./attractor-halvorsen.wgsl?raw";
import { fiboGridN, rand_middle } from "../math.mjs";

export let loadRenderer = async (canvas: HTMLCanvasElement) => {
let seedSize = 2000000;

let renderFrame = await createRenderer(
canvas,
{
seedSize,
seedData: makeSeed(seedSize, 0),
params: [
0.04, // deltaT
600.0, // scale
0.001, // width
0.99, // opacity
],
computeShader: attractorCompute,
},
{
vertexCount: 1,
vertexData: [0, 1, 2, 3],
indexData: [0, 1, 2, 1, 2, 3],
vertexBufferLayout: vertexBufferLayout,
// topology: "line-list",
bgColor: [0.1, 0.0, 0.2, 1.0],
}
);

return renderFrame;
};

let randPoint: [number, number, number] = [0, 0, 0];
let area = 1.0;

function makeSeed(numParticles: number, scale: number): Float32Array {
const buf = new Float32Array(numParticles * 8);

for (let i = 0; i < numParticles; ++i) {
if (i % 24 == 0) {
let p = fiboGridN(i, numParticles);
randPoint = p;
}

let b = 8 * i;
buf[b + 0] = randPoint[0];
buf[b + 1] = randPoint[1];
buf[b + 2] = randPoint[2];
buf[b + 3] = rand_middle(0.8); // ages
buf[b + 4] = randPoint[0];
buf[b + 5] = randPoint[1];
buf[b + 6] = randPoint[2];
buf[b + 7] = 0; // distance
}

return buf;
}

let vertexBufferLayout: GPUVertexBufferLayout[] = [
{
// instanced particles buffer
arrayStride: 8 * 4,
stepMode: "instance",
attributes: [
{ shaderLocation: 0, offset: 0, format: "float32x3" },
{ shaderLocation: 1, offset: 3 * 4, format: "float32" },
{ shaderLocation: 2, offset: 4 * 4, format: "float32x3" },
{ shaderLocation: 3, offset: 7 * 4, format: "float32" },
],
},
{
// vertex buffer
arrayStride: 1 * 4,
stepMode: "vertex",
attributes: [{ shaderLocation: 4, offset: 0, format: "uint32" }],
},
];
178 changes: 178 additions & 0 deletions src/apps/attractor-halvorsen.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@


/// ok
fn iterate_fn(p: vec3f, dt: f32) -> LorenzResult {
let a = 1.4;
let b = 40.;
let c = 2.;
let d0 = 2.5;

let x = p.x;
let y = p.y;
let z = p.z;

let dx = -a * x - 4. * y - 4. * z - y * y;
let dy = -a * y - 4. * z - 4. * x - z * z;
let dz = -a * z - 4. * x - 4. * y - x * x;

// let dx = a * (y - x);
// let dy = b * x - c * x * z;
// let dz = exp(x * y) - d0 * z;

var d = vec3<f32>(dx, dy, dz) * dt * 10.;
// let dl = length(d);
// if (dl > 0.2) {
// d = d / dl * 0.2;
// } else if (dl < 0.01) {
// d = d / dl * 0.01;
// }
let next = p + d;
// if (length(next) > 100.0) {
// next = vec3(0.1);
// }
return LorenzResult(
next,
vec3(dx, dy, dz),
length(d) * 8.8
);
}


struct Particle {
pos: vec3<f32>,
ages: f32,
prev_pos: vec3<f32>,
distance: f32,
}

struct Params {
delta_t: f32,
scale: f32,
width: f32,
opacity: f32,
}

struct Particles {
particles: array<Particle>,
}

@group(0) @binding(1) var<uniform> params: Params;
@group(1) @binding(0) var<storage, read> particles_a: Particles;
@group(1) @binding(1) var<storage, read_write> particles_b: Particles;

const tau = 10f;
const rou = 28f;

struct LorenzResult {
position: vec3f,
velocity: vec3f,
distance: f32,
}



fn rand(n: f32) -> f32 { return fract(sin(n) * 43758.5453123); }

// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) GlobalInvocationID: vec3<u32>) {
var index = GlobalInvocationID.x;

var v_pos = particles_a.particles[index].pos;
// let dd = floor(f32(index) / 80.0);

let inner_idx = f32(index % 24u);
let group_idx = floor(f32(index) / 24.0);

if index % 24u != 0u {
let prev = index - 1u;
particles_b.particles[index].pos = particles_a.particles[prev].pos;
// particles_b.particles[index].ages = particles_a.particles[prev].ages;
particles_b.particles[index].ages = inner_idx;
particles_b.particles[index].prev_pos = particles_a.particles[prev].prev_pos;
// particles_b.particles[index].distance = particles_a.particles[prev].distance;
particles_b.particles[index].distance = group_idx;
return;
}

// let ret = lorenz(v_pos, params.delta_t * 0.01 * (2. + 2. * rand(f32(index))));
let ret = iterate_fn(v_pos, params.delta_t * 0.001 * (2. + 2. * rand(f32(index))));

// Write back
particles_b.particles[index].pos = ret.position;
particles_b.particles[index].ages = inner_idx;
particles_b.particles[index].prev_pos = v_pos;
// particles_b.particles[index].distance += ret.distance;
particles_b.particles[index].distance = group_idx;
}

struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(4) color: vec4<f32>,
}

@vertex
fn vert_main(
@location(0) position0: vec3<f32>,
@location(1) ages: f32,
@location(2) prev_pos0: vec3<f32>,
@location(3) travel: f32,
@location(4) idx: u32,
) -> VertexOutput {
let position = position0 * 8.;
let prev_pos = prev_pos0 * 8.;
var pos: vec3<f32>;
let v0 = position - prev_pos;
var prev_position = prev_pos;
let forward: vec3<f32> = uniforms.forward;
let right = normalize(cross(v0, forward));

// let front = params.length;
var width = params.width * 8.;

if ages < 0.01 {
// prev_position = position;
width = 0.0;
}
// TODO hack
if distance(position, prev_pos) > 12.2 {
width = 0.0;
}

if idx == 0u {
pos = position + right * width;
// pos += vec3(1.,1.,1.) * 100.0;
} else if idx == 1u {
pos = position - right * width;
} else if idx == 2u {
pos = prev_position + right * width;
} else if idx == 3u {
pos = prev_position - right * width;
} else {
pos = position;
}

var output: VertexOutput;
let p0 = vec4(pos * params.scale, 1.0);

let p: vec3<f32> = transform_perspective(p0.xyz).point_position;
let scale: f32 = 0.00002;

output.position = vec4(p * scale, 1.0);
// let c3: vec3<f32> = hsl(fract(travel/100.), 0.8, fract(0.9 - ages * 0.0002));
// let c3: vec3<f32> = hsl(0.24, 0.8, 0.7 + 0.3 * sin(travel * 0.2));
// let c3 = hsl(0.24, 0.99, 0.99 - dim);
// let c3 = vec3<f32>(0.99, 0.94, 0.2) * (1. - ages * 0.01);
let c3: vec3<f32> = hsl(fract(travel * 0.000008 + 0.0), 0.998, 0.5 - ages * 0.002);
output.color = vec4(c3, params.opacity * (1.2 - ages * 0.04));
return output;
}

@fragment
fn frag_main(@location(4) color: vec4<f32>) -> @location(0) vec4<f32> {
return color;
// return vec4<f32>(0.7, 0.7, 1., 1.0);
}

#import protea::perspective
#import protea::colors

0 comments on commit 56c4ef4

Please sign in to comment.