【问题标题】:initiate a number of vertices/triangles for vertex shader to use启动一些顶点/三角形供顶点着色器使用
【发布时间】:2016-09-07 23:10:28
【问题描述】:

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

我无法从源头上弄清楚,当您在此处切换模式时,那里的三角形究竟是如何创建的?

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

【问题讨论】:

  • 根据我对 ThreeJS 的理解,将所有几何图形组合成一个 BufferGeometry 比多个几何图形性能更高。可能值得查找 Geometries 和 BufferGeometries 之间的差异
  • 我在使用着色器材质时已经在使用 bufferGeometry。然而,合并它们会产生我无法解决的意外问题——大多数时候合并的几何图形只是空的。这就是为什么我想知道是否有更简单的方法来实现这一目标
  • 我实际上是同一条船——在尝试跑步时,由于没有面/顶点,我收到RENDER ERROR——我认为这与您在尝试合并时遇到的问题相同?跨度>
  • 其实有点玄乎,一点错误都没有,但是所有的属性都丢失了。场景启动但始终为空

标签: javascript three.js glsl webgl


【解决方案1】:

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。

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; }
&lt;canvas width="500" height="200"&gt;&lt;/canvas&gt;

在 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.POINTSgl.LINESgl.TRIANGLES) .点本身是在顶点着色器中生成的,如上例。

所以剩下的问题是,您要达到什么具体效果。然后我们可以知道要建议什么来实现它。你可能想为此提出一个新问题(这样这个答案仍然与上面的问题相匹配)

【讨论】:

  • 我正在尝试设置您在 vertexshaderart 上设置的最小版本(顺便感谢您)。我缺少的只是关于 gl.drawArrays 的部分,因为我从未从事过裸 webgl 的实现,只使用了三个、vsa、shadertoy 或 twgl 之类的东西。我应该可以从这里继续。至于教程,已经看过了,我想我也是第一个对它们发表评论的人。竖起大拇指
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多