我一直在玩vertexshaderart.com,我想在一个单独的网站上使用我学到的东西。虽然之前我使用过着色器,但在网站上实现的一些效果取决于对顶点/线条/三角形的访问。虽然传递顶点很容易(至少它是THREE.js,虽然它对于简单的着色器来说有点过分,但在某些情况下也需要着色器材质),创建三角形看起来有点复杂。
我无法从源头看出来,当你在这里切换模式时,三角形是如何在那里创建的?
我想复制这种行为,但老实说我不知道如何处理它。我可以通过THREE创建多个三角形,但是如此多的单个对象性能会迅速受到影响。这里创建的三角形是单独的实体还是它们是一个几何体的一部分?
答案 0 :(得分:3)
vertexshaderart.com更像是一个拼图,玩具,艺术盒,创意编码实验,而不是一个好的WebGL的例子。 shadertoy.com也是如此。一个例子like this很漂亮,但是在它的微小窗口中以20fps运行,在我的2014 Macbook Pro上大约1fps全屏,但我的MBP可以播放beautiful games with huge worlds rendered fullscreen at 60fps。换句话说,这些技术更多的是用于艺术/娱乐/游戏/心理锻炼,以及尝试使事情发生在极端限制而不是实际上是好技术的乐趣。
我想要做的是vertexshaderart和shadertoy都很有趣但不切实际。
vertexshaderart的工作方式是它提供一个计算顶点的计数vertexId
。 0到N,其中N是设置UI顶部的计数。对于每个计数,您输出gl_Position
和v_color
(颜色)。
所以,如果你想画一些东西,你需要提供数学来根据计数生成顶点位置。例如,让我们首先使用Canvas 2D
这是一个用JavaScript编写的虚假JavaScript顶点着色器除了vertexId
之外什么也没有给出一个网格1个单位高,N个单位长,其中N =顶点数(vertexCount
)/ 6。 / p>
function ourPseudoVertexShader(vertexId, time) {
// let's compute an infinite grid of points based off vertexId
var x = Math.floor(vertexId / 6) + (vertexId % 2);
var y = (Math.floor(vertexId / 2) + Math.floor(vertexId / 3)) % 2;
// color every other triangle red or green
var triangleId = Math.floor(vertexId / 3);
var color = triangleId % 2 ? "#F00" : "#0F0";
return {
x: x * 0.2,
y: y * 0.2,
color: color,
};
}
我们从提供vertexId
for (var count = 0; count < vertexCount; count += 3) {
// get 3 points
var position0 = ourPseudoVertexShader(count + 0, time);
var position1 = ourPseudoVertexShader(count + 1, time);
var position2 = ourPseudoVertexShader(count + 2, time);
// draw triangle
ctx.beginPath();
ctx.moveTo(position0.x, position0.y);
ctx.lineTo(position1.x, position1.y);
ctx.lineTo(position2.x, position2.y);
ctx.fillStyle = position0.color;
ctx.fill();
}
如果你在这里运行它,你会看到一个网格1单位高,N单位长。我设置了画布原点,因此0,0就像WebGL一样位于中心,因此画布的地址为+1到-1,而+1到-1
var vertexCount = 100;
function ourPseudoVertexShader(vertexId, time) {
// let's compute an infinite grid of points based off vertexId
var x = Math.floor(vertexId / 6) + (vertexId % 2);
var y = (Math.floor(vertexId / 2) + Math.floor(vertexId / 3)) % 2;
// color every other triangle red or green
var triangleId = Math.floor(vertexId / 3);
var color = triangleId % 2 ? "#F00" : "#0F0";
return {
x: x * 0.2,
y: y * 0.2,
color: color,
};
}
var ctx = document.querySelector("canvas").getContext("2d");
requestAnimationFrame(render);
function render(time) {
time *= 0.001;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.save();
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.scale(ctx.canvas.width / 2, -ctx.canvas.height / 2);
// lets assume triangles
for (var count = 0; count < vertexCount; count += 3) {
// get 3 points
var position0 = ourPseudoVertexShader(count + 0, time);
var position1 = ourPseudoVertexShader(count + 1, time);
var position2 = ourPseudoVertexShader(count + 2, time);
// draw triangle
ctx.beginPath();
ctx.moveTo(position0.x, position0.y);
ctx.lineTo(position1.x, position1.y);
ctx.lineTo(position2.x, position2.y);
ctx.fillStyle = position0.color;
ctx.fill();
}
ctx.restore();
requestAnimationFrame(render);
}
canvas { border: 1px solid black; }
<canvas width="500" height="200"></canvas>
在WebGL中执行相同操作意味着使用计数
创建缓冲区var count = [];
for (var i = 0; i < vertexCount; ++i) {
count.push(i);
}
然后将该计数放入缓冲区并将其用作着色器的属性。
这是上面假冒着色器的等效着色器
attribute float vertexId;
uniform float time;
varying vec4 v_color;
void main() {
// let's compute an infinite grid of points based off vertexId
float x = floor(vertexId / 6.) + mod(vertexId, 2.);
float y = mod(floor(vertexId / 2.) + floor(vertexId / 3.), 2.);
// color every other triangle red or green
float triangleId = floor(vertexId / 3.);
v_color = mix(vec4(0, 1, 0, 1), vec4(1, 0, 0, 1), mod(triangleId, 2.));
gl_Position = vec4(x * 0.2, y * 0.2, 0, 1);
}
如果我们运行,我们将得到相同的结果
var vs = `
attribute float vertexId;
uniform float vertexCount;
uniform float time;
varying vec4 v_color;
void main() {
// let's compute an infinite grid of points based off vertexId
float x = floor(vertexId / 6.) + mod(vertexId, 2.);
float y = mod(floor(vertexId / 2.) + floor(vertexId / 3.), 2.);
// color every other triangle red or green
float triangleId = floor(vertexId / 3.);
v_color = mix(vec4(0, 1, 0, 1), vec4(1, 0, 0, 1), mod(triangleId, 2.));
gl_Position = vec4(x * 0.2, y * 0.2, 0, 1);
}
`;
var fs = `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`;
var vertexCount = 100;
var gl = document.querySelector("canvas").getContext("webgl");
var count = [];
for (var i = 0; i < vertexCount; ++i) {
count.push(i);
}
var bufferInfo = twgl.createBufferInfoFromArrays(gl, {
vertexId: { numComponents: 1, data: count, },
});
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var uniforms = {
time: 0,
vertexCount: vertexCount,
};
requestAnimationFrame(render);
function render(time) {
uniforms.time = time * 0.001;
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
requestAnimationFrame(render);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/twgl.min.js"></script>
<canvas width="500" height="200"></canvas>
vertexshartart上的其他所有内容都只是创造性的数学,以制作有趣的模式。您可以使用time
来制作动画。还提供了具有声音数据的纹理。
所以,在回答你的问题时,当你在vertexshaderart.com上切换模式(三角形/线条/点)时,所做的就是改变传递给gl.drawArrays
的内容(gl.POINTS
,{{1} },gl.LINES
)。这些点本身是在顶点着色器中生成的,如上例所示。
这就是问题所在,你想要达到的具体效果是什么。然后我们就可以知道要实现它的目的。你可能想问一个新问题(这个答案仍然符合上面的问题)