我正在尝试使用纯webgl创建虚线。我知道已经有一个问题,也许我很傻,但是我不知道如何使它工作。我了解这个概念,但不知道如何在着色器中沿路径获取距离。先前的答案包含以下内容:
varying float LengthSoFar; // <-- passed in from the vertex shader
那我怎么得到
LengthSoFar
?如何在顶点着色器中计算它?我完全想念什么吗?有人可以给我一个有效的例子吗?或至少有一些好的线索?几天来,我一直在撞墙。
最佳答案
我假设它像这样工作。您有职位空缺。您创建了lengthSoFar
的相应缓冲区,因此,
function distance(array, ndx1, ndx2)
{
ndx1 *= 3;
ndx2 *= 3;
var dx = array[ndx1 + 0] - array[ndx2 + 0];
var dy = array[ndx1 + 1] - array[ndx2 + 1];
var dz = array[ndx1 + 2] - array[ndx2 + 2];
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
var positions =
[
0.123, 0.010, 0.233,
0.423, 0.312, 0.344,
0.933, 1.332, 0.101,
];
var lengthSoFar = [0]; // the length so far starts at 0
for (var ii = 1; ii < positions.length / 3; ++ii)
{
lengthSoFar.push(lengthSoFar[ii - 1] + distance(positions, ii - 1, ii));
}
现在,您可以为
positions
和lengthSoFar
制作缓冲区,并将lengthSoFar
作为属性传递到您的顶点着色器,然后从那里将它作为变量传递到片段着色器。不幸的是,它不适用于索引几何(最常见的类型?)。换句话说,它不适用于
gl.drawElements
,仅适用于gl.drawArrays
。同样,虚线将以3D而不是2D的方式虚线,因此进入屏幕(远离查看者)的线看起来与穿过屏幕的线不同。当然,如果要绘制2D,则没有问题。如果这些限制对您有利,请问您对此有疑问吗?
const gl = document.querySelector("#c").getContext("webgl");
// Note: createProgramFromScripts will call bindAttribLocation
// based on the index of the attibute names we pass to it.
var program = twgl.createProgramFromScripts(
gl,
["vshader", "fshader"],
["a_position", "a_lengthSoFar"]);
gl.useProgram(program);
function distance(array, ndx1, ndx2)
{
ndx1 *= 3;
ndx2 *= 3;
var dx = array[ndx1 + 0] - array[ndx2 + 0];
var dy = array[ndx1 + 1] - array[ndx2 + 1];
var dz = array[ndx1 + 2] - array[ndx2 + 2];
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
// Used this line in the console to generate the positions
// var sub = 10; for (var ii = 0; ii <= sub; ++ii) { r = (ii & 1) ? 0.5 : 0.9; a = ii * Math.PI * 2 / sub; console.log((Math.cos(a) * r).toFixed(3) + ", " + (Math.sin(a) * r).toFixed(3) + ", "); }
var positions = [
0.900, 0.000, 0,
0.405, 0.294, 0,
0.278, 0.856, 0,
-0.155, 0.476, 0,
-0.728, 0.529, 0,
-0.500, 0.000, 0,
-0.728, -0.529, 0,
-0.155, -0.476, 0,
0.278, -0.856, 0,
0.405, -0.294, 0,
0.900, -0.000, 0,
];
var lengthSoFar = [0]; // the length so far starts at 0
for (var ii = 1; ii < positions.length / 3; ++ii)
{
lengthSoFar.push(lengthSoFar[ii - 1] + distance(positions, ii - 1, ii));
}
var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lengthSoFar), gl.STATIC_DRAW);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
// Since uniforms default to '0' and since
// the default active texture is '0' we don't
// have to setup the texture uniform.
var pixels = [
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 255, 255,
0, 0, 0, 0,
0, 0, 0, 0,
255, 0, 0, 255,
0, 0, 0, 0,
0, 0, 0, 0,
255, 0, 0, 255,
0, 0, 0, 0,
0, 0, 0, 0,
];
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGBA, pixels.length / 4, 1, 0,
gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(pixels));
gl.texParameteri(
gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(
gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.drawArrays(gl.LINE_STRIP, 0, positions.length / 3);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vshader" type="whatever">
attribute vec4 a_position;
attribute float a_lengthSoFar;
varying float v_lengthSoFar;
void main() {
gl_Position = a_position;
v_lengthSoFar = a_lengthSoFar;
}
</script>
<script id="fshader" type="whatever">
precision mediump float;
varying float v_lengthSoFar;
uniform sampler2D u_pattern;
#define NumDashes 6.0
void main() {
gl_FragColor = texture2D(
u_pattern,
vec2(fract(v_lengthSoFar * NumDashes)), 0.5);
}
</script>
<canvas id="c" width="300" height="300"></canvas>
注意:Here's an article that might help explain how varyings work
另请注意,您不能更改线条的粗细。为此,您需要draw lines from triangles