我有一个3D Webgl场景。我正在使用Regl http://regl.party/。这是WebGL。所以我本质上是在写直线GLSL。
这是一个游戏项目。我有3D位置数组[[x,y,z] ...],它们是子弹或弹丸。我想将这些项目符号绘制为简单的立方体,球体或粒子。外观没有要求。
如何为此创建着色器和绘制调用,而不必为子弹创建重复的几何重复集?
更喜欢使用vert and frag着色器示例的答案,该示例演示了预期的数据输入,并且可以进行反向工程以处理CPU绑定层
答案 0 :(得分:3)
您创建一个regl命令,该命令封装了一堆数据。然后可以用一个对象调用它。
每个制服都可以采用可选功能来提供其值。该函数将第一个参数传递给regl上下文,然后将第二个参数传递给您的对象,因此您可以使用另一个对象多次调用它,以在其他地方绘制相同的东西(相同的顶点,相同的着色器)。
var regl = createREGL()
const objects = [];
const numObjects = 100;
for (let i = 0; i < numObjects; ++i) {
objects.push({
x: rand(-1, 1),
y: rand(-1, 1),
speed: rand(.5, 1.5),
direction: rand(0, Math.PI * 2),
color: [rand(0, 1), rand(0, 1), rand(0, 1), 1],
});
}
function rand(min, max) {
return Math.random() * (max - min) + min;
}
const starPositions = [[0, 0, 0]];
const starElements = [];
const numPoints = 5;
for (let i = 0; i < numPoints; ++i) {
for (let j = 0; j < 2; ++j) {
const a = (i * 2 + j) / (numPoints * 2) * Math.PI * 2;
const r = 0.5 + j * 0.5;
starPositions.push([
Math.sin(a) * r,
Math.cos(a) * r,
0,
]);
}
starElements.push([
0, 1 + i * 2, 1 + i * 2 + 1,
]);
}
const drawStar = regl({
frag: `
precision mediump float;
uniform vec4 color;
void main () {
gl_FragColor = color;
}`,
vert: `
precision mediump float;
attribute vec3 position;
uniform mat4 mat;
void main() {
gl_Position = mat * vec4(position, 1);
}`,
attributes: {
position: starPositions,
},
elements: starElements,
uniforms: {
mat: (ctx, props) => {
const {viewportWidth, viewportHeight} = ctx;
const {x, y} = props;
const aspect = viewportWidth / viewportHeight;
return [.1 / aspect, 0, 0, 0,
0, .1, 0, 0,
0, 0, 0, 0,
x, y, 0, 1];
},
color: (ctx, props) => props.color,
}
})
regl.frame(function () {
regl.clear({
color: [0, 0, 0, 1]
});
objects.forEach((o) => {
o.direction += rand(-0.1, 0.1);
o.x += Math.cos(o.direction) * o.speed * 0.01;
o.y += Math.sin(o.direction) * o.speed * 0.01;
o.x = (o.x + 3) % 2 - 1;
o.y = (o.y + 3) % 2 - 1;
drawStar(o);
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/regl/1.3.11/regl.min.js"></script>
答案 1 :(得分:2)
您可以将所有项目符号绘制为点精灵,在这种情况下,您只需提供每个项目符号的位置和大小并将其绘制为GL_POINTS
。根据您的顶点着色器(每个点运行一次)的输出,将每个“点”栅格化为一个正方形。您的片段着色器将针对该正方形中的每个片段进行调用,并且可以根据需要对其进行着色-通过对纹理进行采样或使用其他所需的颜色,使着色均匀。
或者您可以为所有项目符号提供一个单独的模型,为每个项目符号提供一个单独的变换,然后将它们绘制为实例GL_TRIANGLES
或GL_TRIANGLE_STRIP
或其他实例。了解有关在the OpenGL wiki上实例化的信息。
答案 2 :(得分:2)
不是WebGL编码器,因此有偏见...
将顶点编码为纹理
提防钳制使用的纹理格式不会像<0.0,+1.0>
那样钳制到GL_LUMINANCE32F_ARB
或仅在该范围内使用顶点。要检查夹紧情况:
渲染单个矩形,覆盖整个屏幕
并使用#1 中的纹理作为输入。这样可以确保为屏幕/视图的每个像素调用一次片段着色器。
内部片段着色器读取纹理并检查片段到顶点的距离
基于它的渲染您的东西或dicard()
片段...球很容易,但是根据顶点的距离渲染盒子和其他形状可能会很复杂,特别是如果它们可以任意定向(需要额外定向)输入纹理中的信息)。
为简化此操作,您可以将它们预渲染为某种纹理并将距离用作纹理坐标...
我的答案是使用这种技术:
答案 3 :(得分:2)
有时可以不使用带有较大gl_PointSize和自定义片段着色器的GL_POINTS。 此处显示的示例使用片段alpha到点中心的距离。 (您也可以对纹理进行采样)
不过,对大磅点的支持可能会受到限制,因此请在确定此路线之前先进行检查。
var canvas = document.getElementById('cvs');
gl = canvas.getContext('webgl');
var vertices = [
-0.5, 0.75,0.0,
0.0, 0.5, 0.0,
-0.75,0.25,0.0,
];
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var vertCode =
`attribute vec3 coord;
void main(void) {
gl_Position = vec4(coord, 1.0);
gl_PointSize = 50.0;
}`;
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragCode =
`void main(void) {
mediump float ds = distance(gl_PointCoord.xy, vec2(0.5,0.5))*2.0;
mediump vec4 fg_color=vec4(0.0, 0.0, 0.0,1.0- ds);
gl_FragColor = fg_color;
}`;
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coord = gl.getAttribLocation(shaderProgram, "coord");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.POINTS, 0, 3);
<!doctype html>
<html>
<body>
<canvas width = "400" height = "400" id = "cvs"></canvas>
</body>
</html>