原文链接: regl 星环
上一篇: webgpu 初探
调调参数啥的应该能更好看点, 但是没啥意义
主要思想就是生成球形点和环形点, 然后用时间去改变位置, 所有计算都在gpu里, js只创建数组和初始数据, 每次用uniform变量来传递, 这样只需要每次传递一个变量就行了
import mat4 from "gl-mat4";
import Regl from "regl";
import { getPointList } from "../../utils/sphere";
import { random, randomColor, randomInt } from "../../utils/index";
const regl = Regl();
export default () => {
const size = 20000;
const pointList = Array(size)
.fill(0)
.map(() => [
random(-Math.PI * 2, Math.PI * 2),
random(-Math.PI * 2, Math.PI * 2),
]);
const r = () => random(-1, 1);
const offsetList = Array(pointList.length)
.fill(0)
.map(() => [r(), r()]);
const colorList = Array(pointList.length)
.fill(0)
.map(() => randomColor(true));
const drawCube = regl({
frag: `
precision mediump float;
varying vec3 outColor;
void main () {
gl_FragColor = vec4(outColor,1);
}`,
vert: `
precision mediump float;
attribute vec2 degree; // a,b
attribute vec3 color;
attribute vec2 offset;
uniform float time;
varying vec3 outColor;
uniform mat4 projection, view;
float r = 1.0;
void main() {
outColor=color;
vec2 d = offset*sin(time/100.0)/2.0;
// vec2 d = offset*mod(time,100.0)/100.0;
float x = r * sin(degree.x+d.x)*sin(degree.y+d.y);
float y = r * sin(degree.x+d.x)*cos(degree.y+d.y);
float z = r * cos(degree.x+d.x);
vec3 position = vec3(x,y,z);
vec4 p = projection * view * vec4(position, 1);
// gl_Position = vec4(p.x+dp.x,p.y+dp.y,p.z+dp.z,p.w);
gl_Position = p;
gl_PointSize = 2.0;
}`,
attributes: {
degree: pointList,
color: colorList,
offset: offsetList,
},
primitive: "points",
count: pointList.length,
// elements: cubeElements,
uniforms: {
time: regl.prop("time"),
view: ({ tick }) => {
// const t = 0.5;
const t = 0.01 * tick;
return mat4.lookAt(
[],
[5 * Math.cos(t), 2.5 * Math.sin(t), 5 * Math.sin(t)],
[0, 0.0, 0],
[0, 1, 0]
);
},
projection: ({ viewportWidth, viewportHeight }) =>
mat4.perspective(
[],
Math.PI / 4,
viewportWidth / viewportHeight,
0.01,
10
),
},
});
const sizeRing = 40000;
const ringList = Array(sizeRing)
.fill(0)
.map(() => [
random(-Math.PI * 2, Math.PI * 2), // 角度
random(-0.2, 0.2), // 偏移
]);
const ringRandom = () => random(-1, 1);
const ringOffsetList = Array(ringList.length)
.fill(0)
.map(() => [ringRandom(), ringRandom()]);
const ringColorList = Array(ringList.length)
.fill(0)
.map(() => randomColor(true));
const drawRing = regl({
frag: `
precision mediump float;
varying vec3 outColor;
void main () {
gl_FragColor = vec4(outColor,1);
}`,
vert: `
precision mediump float;
attribute vec2 degree; // a,b
attribute vec3 color;
attribute vec2 offset;
uniform float time;
uniform float dr;
varying vec3 outColor;
uniform mat4 projection, view;
float r = 2.0;
void main() {
// vec2 d = offset*sin(time/100.0)/2.0;
vec2 dd = degree + sin(time/1000.0)*3.0;
vec2 d = vec2(0,0);
float x = (r+degree.y) * sin(dd.x+d.x+dr);
float z = (r+degree.y) * cos(dd.x+d.y+dr);
// float y = degree.y;
float y = 0.0;
vec3 position = vec3(x,y,z);
vec4 p = projection * view * vec4(position, 1);
gl_Position = p;
gl_PointSize = 2.0;
outColor=color;
}`,
attributes: {
degree: ringList,
color: ringColorList,
offset: ringOffsetList,
},
primitive: "points",
count: pointList.length,
// elements: cubeElements,
uniforms: {
time: regl.prop("time"),
dr: regl.prop("dr"),
view: ({ tick }) => {
// const t = 0.01 * tick;
const t = 1;
return mat4.lookAt(
[],
[5 * Math.cos(t), 2.5 * Math.sin(t), 5 * Math.sin(t)],
[0, 0.0, 0],
[0, 1, 0]
);
},
projection: ({ viewportWidth, viewportHeight }) =>
mat4.perspective(
[],
Math.PI / 4,
viewportWidth / viewportHeight,
0.01,
10
),
},
});
regl.frame(({ tick }) => {
regl.clear({
color: [0, 0, 0, 255],
depth: 1,
});
drawCube({ time: tick });
const dr = Math.sin(tick / 1000) * Math.PI * 2;
drawRing({ time: tick, dr });
});
};