编写一个函数来绘制 x/y 用于 WebGL 绘制的正弦波?
Write a function that will plot x/y for a sine wave to be drawn by WebGL?
我正在尝试学习 WebGL(以及来自 codingmath 的一些数学知识)。今天的目标是在任何开始和结束方向绘制正弦波。
是这样的:
我只是在 makePoints()
方法中遗漏了一些东西。我的观点很奇怪,我对下一步该去哪里有点傻眼了。
问题:
如何修复我的 makePoints()
函数,以便它绘制出正弦波的 x 和 y 坐标。
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const diff = (Math.PI * 2) / (points - 1);
const len = {length: points};
return Array.from(len, (_, i) => Math.sin(i * diff));
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
console.log(vertices)
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH/2);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
您提供的顶点缓冲区不够大。它应该为 x 和 y 存储 2 个浮点数(而不是 1 个)
我重写了它:(检查 makePoints2)
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const diff = (Math.PI * 2) / (points - 1);
const len = {length: points};
return Array.from(len, (_, i) => Math.sin(i * diff));
}
function makePoints2(points) {
let arr = Array(points * 2);
let index = 0;
for(var i=0;i<points;i++) {
let val = (i/points) * (Math.PI * 2); // lerp 0..points => 0..2PI
arr[index] = ((i/points)*2)-1; // x, lerp 0..points => -1..1 range
arr[index+1] = Math.sin(val); // y, the sinus function...
index += 2; // next vertex
}
return arr;
}
function createVertices() {
// Feel like my function is close but I'm missing something
vertices = makePoints2(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.enableVertexAttribArray(coords);
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
console.log(vertices)
//gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH);
//requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
感谢 gman 如何制作片段
由于您的代码期望每个顶点有 2 个点,因此您需要为偶数 (x) 和奇数 (y) 值设置 return 不同的值。
我发现理解冗长的代码要容易得多,所以这是我的 makePoints
。请注意,我发现像这样在循环中始终计算 lerp0to1
值很有用。然后我可以使用该值轻松转换为我想要的几乎任何类型的数据。
function makePoints(points) {
const highestPointNdx = points / 2 - 1;
return Array.from({length: points}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const odd = i % 2;
return odd
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const highestPointNdx = points / 2 - 1;
return Array.from({length: points}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const odd = i % 2;
return odd
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
console.log(vertices);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH/2);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
让我补充一下,我认为 makePoints
目前有点令人困惑。我会更改它以获取您想要的点数,而不是顶点缓冲区中的值数(这是现在所需要的),这与点数不同。如果你想要 N 个点,你需要 2*N 个值。所以,我将其更改为
function makePoints(numPoints) {
const highestPointNdx = numPoints - 1;
return Array.from({length: numPoints * 2}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const isY = i % 2;
return isY
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
然后我传入 VERTEX_LENGTH
并为 gl.drawArrays
使用相同的值,如果我使用 3D 点而不是 2D 点,则两者都不必更改。
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(numPoints) {
const highestPointNdx = numPoints - 1;
return Array.from({length: numPoints * 2}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const isY = i % 2;
return isY
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
我正在尝试学习 WebGL(以及来自 codingmath 的一些数学知识)。今天的目标是在任何开始和结束方向绘制正弦波。
是这样的:
我只是在 makePoints()
方法中遗漏了一些东西。我的观点很奇怪,我对下一步该去哪里有点傻眼了。
问题:
如何修复我的 makePoints()
函数,以便它绘制出正弦波的 x 和 y 坐标。
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const diff = (Math.PI * 2) / (points - 1);
const len = {length: points};
return Array.from(len, (_, i) => Math.sin(i * diff));
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
console.log(vertices)
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH/2);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
您提供的顶点缓冲区不够大。它应该为 x 和 y 存储 2 个浮点数(而不是 1 个)
我重写了它:(检查 makePoints2)
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const diff = (Math.PI * 2) / (points - 1);
const len = {length: points};
return Array.from(len, (_, i) => Math.sin(i * diff));
}
function makePoints2(points) {
let arr = Array(points * 2);
let index = 0;
for(var i=0;i<points;i++) {
let val = (i/points) * (Math.PI * 2); // lerp 0..points => 0..2PI
arr[index] = ((i/points)*2)-1; // x, lerp 0..points => -1..1 range
arr[index+1] = Math.sin(val); // y, the sinus function...
index += 2; // next vertex
}
return arr;
}
function createVertices() {
// Feel like my function is close but I'm missing something
vertices = makePoints2(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.enableVertexAttribArray(coords);
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
console.log(vertices)
//gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH);
//requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
感谢 gman 如何制作片段
由于您的代码期望每个顶点有 2 个点,因此您需要为偶数 (x) 和奇数 (y) 值设置 return 不同的值。
我发现理解冗长的代码要容易得多,所以这是我的 makePoints
。请注意,我发现像这样在循环中始终计算 lerp0to1
值很有用。然后我可以使用该值轻松转换为我想要的几乎任何类型的数据。
function makePoints(points) {
const highestPointNdx = points / 2 - 1;
return Array.from({length: points}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const odd = i % 2;
return odd
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(points) {
const highestPointNdx = points / 2 - 1;
return Array.from({length: points}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const odd = i % 2;
return odd
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
console.log(vertices);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH/2);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>
让我补充一下,我认为 makePoints
目前有点令人困惑。我会更改它以获取您想要的点数,而不是顶点缓冲区中的值数(这是现在所需要的),这与点数不同。如果你想要 N 个点,你需要 2*N 个值。所以,我将其更改为
function makePoints(numPoints) {
const highestPointNdx = numPoints - 1;
return Array.from({length: numPoints * 2}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const isY = i % 2;
return isY
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
然后我传入 VERTEX_LENGTH
并为 gl.drawArrays
使用相同的值,如果我使用 3D 点而不是 2D 点,则两者都不必更改。
let gl,
shaderProgram,
vertices,
canvas;
const VERTEX_LENGTH = 1500;
const VERTEX_SHADER = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color;
}
`;
initGL();
createShader();
createVertices();
draw();
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
function initGL() {
canvas = document.querySelector('#canvas');
gl = canvas.getContext('webgl');
setCanvasSize();
console.log(gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clearColor(0, 0, 0, 1);
}
function makePoints(numPoints) {
const highestPointNdx = numPoints - 1;
return Array.from({length: numPoints * 2}, (_, i) => {
const pointId = i / 2 | 0;
const lerp0To1 = pointId / highestPointNdx;
const isY = i % 2;
return isY
? Math.sin(lerp0To1 * Math.PI * 2) // Y
: (lerp0To1 * 2 - 1); // X
});
}
function createVertices() {
vertices = makePoints(VERTEX_LENGTH);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);
const coords = gl.getAttribLocation(shaderProgram, 'coords');
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
const pointSize = gl.getAttribLocation(shaderProgram, 'pointSize');
gl.vertexAttrib1f(pointSize, 2);
const uniformColor = gl.getUniformLocation(shaderProgram, 'color');
gl.uniform4f(uniformColor, 0, normalize(200), normalize(83), 1);
}
function createShader() {
const vs = VERTEX_SHADER;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
const fs = FRAGMENT_SHADER;
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, VERTEX_LENGTH);
requestAnimationFrame(draw);
}
function normalize(val, max=255, min=0) { return (val - min) / (max - min); }
html, body, canvas {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
display: block;
position: relative;
}
<canvas id="canvas" width="500" height="500"></canvas>