top of page
Search
cedarcantab

Particles in Box WebGL



/* Constants */

let updates_per_frame = 20;

let dt = .005;

let spring_rad = .05;

let spring_const = 30;

let damping = .001;

let w = h = 30;

let gl = canvas.getContext('webgl2');

gl.getExtension("EXT_color_buffer_float");

/* data */

let posvel = new Float32Array(4*w*h);

for (let i = 0; i < w*h; i++) {

posvel[4*i ] = 1 - 2*Math.random(); // x

posvel[4*i+1] = 1 - 2*Math.random(); // y

posvel[4*i+2] = 0; // vx

posvel[4*i+3] = 0; // vy

}

let posvel_tex = [

Texture(0, w,h, gl.RGBA32F, gl.RGBA, gl.FLOAT, posvel),

Texture(1, w,h, gl.RGBA32F, gl.RGBA, gl.FLOAT, posvel)];

let posvel_fbo = [

FrameBuffer(posvel_tex[0]),

FrameBuffer(posvel_tex[1])];

/* Draw Program */

let draw = ProgramBundle(

`in ivec2 pixel;

uniform sampler2D posvel;

void main() {

vec2 pos = texelFetch( posvel, pixel, 0).xy;

gl_PointSize = 7.0;

gl_Position = vec4(pos, 0., 1.);

}`,

`out vec4 color;

void main() {

color = vec4(0.,0.,1.,1.);

}`);

draw.pixel_buf = Buffer(Pixels(w,h));

draw.run = (unit) => {

gl.useProgram(draw.program);

gl.uniform1i( draw.posvel, unit);

gl.bindBuffer(gl.ARRAY_BUFFER, draw.pixel_buf);

gl.vertexAttribIPointer(draw.pixel, 2, gl.INT, false, 0,0);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);

gl.viewport(0,0,canvas.width, canvas.height);

gl.drawArrays(gl.POINTS, 0, w*h);

}

/* update program */

let update = ProgramBundle(

`in vec2 pos;

void main() {

gl_Position = vec4(pos, 0.,1.);}`,

`out vec4 posvel_new;

uniform sampler2D posvel;

void main()

{

float k = ${(spring_const).toFixed(1)};

float R = ${spring_rad};

ivec2 id = ivec2(gl_FragCoord.xy);

vec2 pos = texelFetch(posvel, id, 0).xy;

vec2 vel = texelFetch(posvel, id, 0).zw;

for (int y = 0; y < ${h}; y++) {

for (int x = 0; x < ${w}; x++) {

vec2 posB = texelFetch( posvel, ivec2(x,y), 0 ).xy;

float L = length(pos - posB);

if (L < R) {

vel += k*(posB - pos)*(L - R);

vel -= ${damping}*vel;

}

}

}

vel.y -= .1*${dt};

pos += vel*${dt};

if (pos.y < -1.0) { pos.y = -1.0; vel.y = abs(vel.y); }

if (pos.y > 1.0) { pos.y = 1.0; vel.y =-abs(vel.y); }

if (pos.x < -1.0) { pos.x = -1.0; vel.x = abs(vel.x); }

if (pos.x > 1.0) { pos.x = 1.0; vel.x =-abs(vel.x); }

posvel_new = vec4(pos,vel);

}`);

update.pos_buf = Buffer(new Float32Array([-1,-1, 1,-1, -1,1, 1,1]));

update.run = (in_unit, out_unit) => {

gl.useProgram(update.program);

gl.uniform1i( update.posvel, in_unit);

gl.bindBuffer(gl.ARRAY_BUFFER, update.pos_buf);

gl.vertexAttribPointer(update.pos, 2, gl.FLOAT, false,0, 0);

gl.bindFramebuffer(gl.FRAMEBUFFER, posvel_fbo[out_unit]);

gl.viewport(0,0,w,h);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

}

/* main loop */

let IO = 0;

let count = 0;

(function loop() {

for (let i = 0; i < updates_per_frame; i++) {

update.run(1-IO, IO);

IO = 1 - IO;

}

draw.run(IO);

if (count++ < 500) requestAnimationFrame(loop);

})();

/*--------------------------------------------------------------------------------*/

function Buffer(data) {

let buf = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, buf);

gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

return buf;

}

function ProgramBundle(vertex_code, fragment_code) {

/* Return program and attrib/uniform locations

let pb = ProgramBundle(v_code, f_code)

pb.program == program

pb.(name) == location

pb.(name) == location

...

*/

// Build Shader Program

let pb = { program: gl.createProgram() };

let vertex_shader = gl.createShader(gl.VERTEX_SHADER);

let fragment_shader = gl.createShader(gl.FRAGMENT_SHADER);

vertex_code = "#version 300 es\n precision highp float;\n" + vertex_code;

fragment_code = "#version 300 es\n precision highp float;\n" + fragment_code;

gl.shaderSource( fragment_shader, fragment_code);

gl.shaderSource( vertex_shader, vertex_code);

gl.compileShader(vertex_shader);

gl.compileShader(fragment_shader);

gl.attachShader( pb.program, vertex_shader);

gl.attachShader( pb.program, fragment_shader);

gl.linkProgram( pb.program);

gl.useProgram( pb.program);

// Store Attribute Locations

let attrib_count = gl.getProgramParameter(pb.program, gl.ACTIVE_ATTRIBUTES);

for (let i= 0; i < attrib_count; i++) {

let attrib_name = gl.getActiveAttrib( pb.program, i).name;

let attrib_location = gl.getAttribLocation(pb.program, attrib_name);

gl.enableVertexAttribArray(attrib_location);

pb[attrib_name] = attrib_location;

}

// Store Uniform Locations

let uniform_count = gl.getProgramParameter( pb.program, gl.ACTIVE_UNIFORMS);

for (let i = 0; i < uniform_count; i++) {

let uniform_name = gl.getActiveUniform( pb.program, i).name;

let uniform_location = gl.getUniformLocation(pb.program, uniform_name);

pb[uniform_name] = uniform_location;

}

return pb;

}

function Texture(unit, w, h, internal_format, format, type, data) {

let tex = gl.createTexture();

gl.activeTexture(gl.TEXTURE0 + unit);

gl.bindTexture(gl.TEXTURE_2D, tex);

gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);

gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);

gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

gl.texImage2D(gl.TEXTURE_2D,0, internal_format, w,h, 0, format, type, data);

return tex;

}

function FrameBuffer(target_tex) {

let fbo = gl.createFramebuffer();

gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);

gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target_tex, 0);

return fbo;

}

function Pixels(width, height) {

let UV = [];

for (let x=0; x<width; x++) {

for (let y=0; y<height; y++) {

UV.push(x,y);

}

}

return new Int32Array(UV);

}

3 views0 comments

Recent Posts

See All

p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

sopiro motor constranit

import { Matrix2, Vector2 } from "./math.js"; import { RigidBody } from "./rigidbody.js"; import { Settings } from "./settings.js";...

Commenti


記事: Blog2_Post
bottom of page