#javascript #interpolation #linear-interpolation #webgl2
Вопрос:
У меня есть некоторые потоковые данные, я хочу нарисовать интерполированные вершины с помощью gl.ОЧКИ с помощью WebGL2. У меня есть функция сглаживания для создания кругов, и это действительно то, что мне нужно (я могу захотеть интерполировать дважды или трижды):
Чтобы проиллюстрировать проблему:
Чтобы интерполировать между вершинами, здесь, в JavaScript, дважды:
var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]);
var array2 = new Float32Array(array.length * 2 - 2);
/* init canvas */
var gl = document.getElementById('plot2').getContext('webgl2');
gl.canvas.width = gl.canvas.height = 128;
gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
const fs_point = `#version 300 es
precision mediump float;
out vec4 color;
void main() {
color = vec4(0.5, 0., 0.5, 0.8);
}`;
const vs_points = `#version 300 es
precision mediump float;
in vec2 vPos;
void main() {
gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
gl_PointSize = 10.0;
}`;
const shaderProgram = gl.createProgram();
let shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fs_point);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, vs_points);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
const pointPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW);
pointPosBuffer.itemSize = 2;
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 0, 0);
/* /init canvas */
/* loop */
gl.clear(gl.COLOR_BUFFER_BIT);
//array changes, manual interpolation
for(var i = 0; i < array.length; i = 2) {
array2[2 * i] = array[i];
array2[2 * i 1] = array[i 1];
}
//here starts interpolation
for(var i = 2; i < array2.length - 2; i = 4) {
array2[i] = (array2[i - 2] array2[i 2]) * 0.5;
array2[i 1] = (array2[i - 1] array2[i 3]) * 0.5;
}
gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW); //array values changes
gl.drawArrays(gl.GL_POINTS, 0, 7);
/* /loop */
<canvas id="plot2"></canvas>
Это действительно очень неудобно делать вручную, поэтому переключитесь на шейдер:
var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]),
gl = document.getElementById('plot3').getContext('webgl2');
gl.canvas.width = gl.canvas.height = 128;
gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
const fs_point = `#version 300 es
precision mediump float;
out vec4 color;
void main() {
color = vec4(0.5, 0., 0.5, 0.8);
}`;
const vs_points = `#version 300 es
precision mediump float;
in vec4 vPos;
void main() {
switch (gl_VertexID % 3) {
case 0:
gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
break;
case 1:
gl_Position = vec4(0.5 * (vPos.x vPos.z), 0.5 * (vPos.y vPos.w), 0, 1.0);
break;
case 2:
gl_Position = vec4(vPos.z, vPos.w, 0, 1.0);
break;
}
gl_PointSize = 12.0;
}`;
const shaderProgram = gl.createProgram();
let shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fs_point);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, vs_points);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
const pointPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);
pointPosBuffer.itemSize = 4;
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 8, 0);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const indices = new Uint8Array([
0, 0, 0,
1, 1, 1,
2, 2, 2
]);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
/* /init canvas */
/* loop */
gl.clear(gl.COLOR_BUFFER_BIT);
//array changes, manual interpolation
gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW); //array values changes
gl.drawElements(gl.GL_POINTS, 9, gl.UNSIGNED_BYTE, 0);
/* /loop */
<canvas id="plot3"></canvas>
Here, I want to use indices and supply two pairs of x, y coordinates to shader. I see only three dots. I think the code tells the indices, calls three times the same quad of vertices interpolating them according to index (which seems to fail), advances 8 bytes (2 Float coordinates) and draws again.
Is there easier way to interpolate between vertices?
Aren’t gl_VertexID or gl_InstanceID (tried the same at instanced version) suppose to advance every index / vertex?
Is this due to index reuse?