为顶点着色器启动多个顶点/三角形以供使用

时间:2016-09-07 11:42:54

标签: javascript three.js glsl webgl

我一直在玩vertexshaderart.com,我想在一个单独的网站上使用我学到的东西。虽然之前我使用过着色器,但在网站上实现的一些效果取决于对顶点/线条/三角形的访问。虽然传递顶点很容易(至少它是THREE.js,虽然它对于简单的着色器来说有点过分,但在某些情况下也需要着色器材质),创建三角形看起来有点复杂。

我无法从源头看出来,当你在这里切换模式时,三角形是如何在那里创建的?

enter image description here

我想复制这种行为,但老实说我不知道​​如何处理它。我可以通过THREE创建多个三角形,但是如此多的单个对象性能会迅速受到影响。这里创建的三角形是单独的实体还是它们是一个几何体的一部分?

1 个答案:

答案 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_Positionv_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来制作动画。还提供了具有声音数据的纹理。

There are some tutorials here

所以,在回答你的问题时,当你在vertexshaderart.com上切换模式(三角形/线条/点)时,所做的就是改变传递给gl.drawArrays的内容(gl.POINTS,{{1} },gl.LINES)。这些点本身是在顶点着色器中生成的,如上例所示。

这就是问题所在,你想要达到的具体效果是什么。然后我们就可以知道要实现它的目的。你可能想问一个新问题(这个答案仍然符合上面的问题)

相关问题