webgl实现canvas生命游戏三维进化动画代码

代码语言:html

所属分类:动画

代码描述:webgl实现canvas生命游戏三维进化动画代码

代码标签: webgl canvas 生命 游戏 三维 进化 动画 代码

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">

  
  
<style>
html {
  --side: max(100vw, 100vh);
}

html, body {
  width: 100%;
  height: 100%;
}

body {
  margin: 0;
  overflow: hidden;
  position: fixed;
  background-color: #111;
}

canvas {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: var(--side);
  height: var(--side);
  position: fixed;
}
</style>

  
</head>

<body translate="no">
  <script>console.clear()</script>
<canvas id="canvas"></canvas>
  
      <script >
"use strict";
//////// SETUP
const settings = [
    [32, 64, 0.02, 0.67],
    [64, 64, 0.02, 0.67],
    [128, 64, 0.01, 0.33], // 2
];
// settings index
const S = 1;
const side = settings[S][0];
const height = settings[S][1];
const scale = settings[S][2];
const y_offset = settings[S][3];
// total number of cubes
const N = side * side * height;
// texture side
const t_side = Math.sqrt(N);
// grid (of chunks on texture) side
const g_side = t_side / side;
// half side
const h_side = side / 2;
// coordinate of last chunk (life chunk)
const l_chunk = t_side - side;
//////// PREPARE WEBGL CONTEXT
const gl = (() => {
    const dpr = Math.min(2, devicePixelRatio);
    let c_side = Math.max(innerWidth, innerHeight);
    c_side = Math.max(c_side * dpr, t_side);
    canvas.width = c_side;
    canvas.height = c_side;
    return canvas.getContext("webgl2", {
        preserveDrawingBuffer: true,
        alpha: false,
    });
})();
gl.enable(gl.DEPTH_TEST);
gl.clearColor(0.067, 0.067, 0.067, 1);
//////// ATTRIBUTES
// indices
var A;
(function (A) {
    A[A["QUAD"] = 0] = "QUAD";
    A[A["ID"] = 1] = "ID";
    A[A["POS"] = 2] = "POS";
    A[A["IPOS"] = 3] = "IPOS";
    A[A["NORM"] = 4] = "NORM";
})(A || (A = {}));
{
    // quad from a triangle
    const quad = new Float32Array([
        -1, -3,
        3, 1,
        -1, 1,
    ]);
    set_attrib(quad, [A.QUAD, 2]);
    // cube data -> pos, norm
    const cube = new Float32Array([
        // face, face, normal
        [0, 0, 0, 1, 0, 0, 1, 1, 0,
            1, 1, 0, 0, 1, 0, 0, 0, 0,
            0, 0, -1],
        [1, 0, 0, 1, 0, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 0, 1, 0, 0,
            1, 0, 0],
        [1, 0, 1, 0, 0, 1, 0, 1, 1,
            0, 1, 1, 1, 1, 1, 1, 0, 1,
            0, 0, 1],
        [0, 0, 1, 0, 0, 0, 0, 1, 0,
            0, 1, 0, 0, 1, 1, 0, 0, 1,
            -1, 0, 0],
        [1, 1, 0, 1, 1, 1, 0, 1, 1,
            0, 1, 1, 0, 1, 0, 1, 1, 0,
            0, 1, 0],
    ].reduce((arr, e) => {
        const n = e.slice(18), data = [];
        for (let i = 0; i < 18; i += 3) {
            e[i + 0] -= 0.5;
            e[i + 1] -= 0.5;
            e[i + 2] -= 0.5;
            data.push(e[i], e[i + 1], e[i + 2], ...n);
        }
        return arr.concat(data);
    }, []));
    set_attrib(cube, [A.POS, 3], [A.NORM, 3]);
    // instanced cubes data -> ipos, id
    const icubes = new ArrayBuffer(N * 6 * 4);
    for (let i = 0; i < N; i++) {
        const x = i % side;
        const z = (i / t_side | 0) % side;
        const y = (() => {
            // grid id — coord of chunk on texture
            const x = (i % t_side) / side | 0;
            const y = i / (t_side * side) | 0;
            return y * g_side + x;
        })();
        const o = i * 6 * 4;
        const ipos = new Float32Array(icubes, o, 3);
        ipos[0] = x - h_side;
        ipos[1] = y - height;
        ipos[2] = h_side - z;
        const id = new Int32Array(icubes, o + 12, 3);
        id[0] = x;
        id[1] = y;
        id[2] = z;
    }
    set_attrib(icubes, [A.IPOS, 3, 1], [A.ID, 3, 1, true]);
}
//////// MESH PROGRAM
const mesh = (() => {
    const vert = /*glsl*/ `#version 300 es
  layout(location=${A.ID})   in ivec3 id;
  layout(location=${A.POS})  in vec3 pos;
  layout(location=${A.IPOS}) in vec3 ipos;
  layout(location=${A.NORM}) in vec3 norm;

  uniform mat4 proj;
  uniform mat4 wmat;
  uniform mat4 rmat;
  uniform sampler2D map;

  out vec3 color;

  void main() {
  
    ivec2 uv = id.xz;
    uv.x += (id.y % ${g_side}) * ${side};
    uv.y += (id.y / ${g_side}) * ${side};

    float is_alive = texelFetch(map, uv, 0).r;
    vec4 p = rmat * vec4((pos + ipos) * is_alive, 1);

    // AO, SELF SHADOW

    // height
    float h = float(id.y) / ${height}.0;

    // length from far corner
    float l = length(vec2(-${h_side}, ${h_side}) - p.xz);
    l = min(1.0, l / ${side}.0);
    l *= l;
    l = mix(1.0, l, sqrt(1.0 - h) - 0.1);

    // radius from center
    float r = length(vec2(id.xz) / ${side}.0 - 0.5);
    r = min(1.0, r * 2.0);
    r = mix(1.0, r, sqrt(1.0 - h) - 0.1);

    h = mix(h, 1.0, (l + h) / 5.0);

    color = vec3(l * r * sqrt(h));
    color *= color;
    color = 0.087 + color * (1.0 - 0.087);

    // LIGHT

    vec3 n = mat3(rmat) * norm;
    vec3 light_dir = normalize(vec3(1, 3, -2));
    float diff = max(dot(n, light_dir), 0.0);
    color *= sqrt(0.67 + diff * 0.33);

    gl_Position = proj * wmat * vec4(p.xyz * ${scale}, 1);
  }`;
    const frag = /*glsl*/ `#version 300 es
  precision highp float;
  in vec3 color;
  out vec3 Color;
  void main() {
    Color = color;
  }`;
    const pr = new_program(vert, frag);
    gl.useProgram(pr);
    gl.uniformMatrix4fv(uloc(pr, "proj"), !1, ortho_proj());
    gl.uniform1i(uloc(pr, "map"), 0);
    return pr;
})();
const wmat = new_mat();
rot_x(wmat, -Math.PI / 4 + 0.17);
rot_y(wmat, Math.PI / 4);
mov_y(wmat, -y_offset);
const wmat_loc = uloc(mesh, "wmat");
gl.uniformMatrix4fv(wmat_loc, false, wmat);
const rmat = new_mat();
const rmat_loc = uloc(mesh, "rmat");
//////// LIFE PROGRAM
const life = (() => {
    const vert = /*glsl*/ `#version 300 es
  layout(location=${A.QUAD}) in vec2 pos;
  void main() {
    gl_Position = v.........完整代码请登录后点击上方下载按钮下载查看

网友评论0