Прекомпиляция нескольких программ
До сих пор у меня были хорошие успехи в рендеринге в выходную текстуру с использованием входных данных (текстура)
В интересах скорости я хочу набор предварительно скомпилированных программ webgl, готовых к "использованию" в зависимости от того, что я хочу сделать
можно ли (псевдокод)
createProgram #1
createProgram #2
createProgram #3
createProgram #4
1: useProgram #1
2: attach selected frame buffers/uniforms
3: setViewPort (depended on output framebuffer attached texture)
3: drawArrays
4: readPixels
На данный момент я хочу использовать другую программу (например, #2), что происходит с прикрепленной униформой и буферами к программе #1, нужно ли их очищать? Могу ли я оставить их на месте и использовать их позже?
Если я выдаю "useProgram #1", все ли активные униформы и фреймбуферы, которые я выбрал для программы #1, остаются неизменными?
1 ответ
Да, вы можете настроить несколько программ во время инициализации. Это нормальное занятие.
заметки:
Унифицированные локации уникальны для каждой программы
Например, давайте создадим 2 шейдерные программы с одинаковым содержимым и попробуем использовать одинаковое местоположение из одной программы с другой программой.
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
void main() {
// draw a 10 pixel "POINT" in the center of the canvas
gl_PointSize = 10.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`;
// make 2 identical programs
// compile shaders, link programs
const p1 = twgl.createProgram(gl, [vs, fs]);
const p2 = twgl.createProgram(gl, [vs, fs]);
// look up color location from first program
const colorLoc = gl.getUniformLocation(p1, 'color');
// try to use colorLoc with second program
gl.useProgram(p2); // make p2 the current program
gl.uniform4fv(colorLoc, [1, 0, 0, 1]);
console.log('error:', glEnumToString(gl, gl.getError()));
function glEnumToString(gl, v) {
return Object.keys(WebGLRenderingContext.prototype)
.filter(k => gl[k] === v)
.join(' | ');
}
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
Это не с INVALID_OPERATION
, Вам нужно искать места отдельно для каждой программы
единое состояние для каждой программы
так, например, давайте сделаем те же самые программы, мы установим униформу на них перед рендерингом с ними, чтобы показать, что унифицированные настройки "для каждой программы"
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
void main() {
// draw a 10 pixel "POINT" in the center of the canvas
gl_PointSize = 10.0;
gl_Position = position;
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`;
// make 3 identical programs
// compile shaders, link programs, force position to location 0 by calling
// bindAttribLocation
const p1 = twgl.createProgram(gl, [vs, fs], ['position']);
const p2 = twgl.createProgram(gl, [vs, fs], ['position']);
const p3 = twgl.createProgram(gl, [vs, fs], ['position']);
// look up color location for each program
const colorLocP1 = gl.getUniformLocation(p1, 'color');
const colorLocP2 = gl.getUniformLocation(p2, 'color');
const colorLocP3 = gl.getUniformLocation(p3, 'color');
// set the color uniform on each program
gl.useProgram(p1);
gl.uniform4fv(colorLocP1, [1, 0, 0, 1]);
gl.useProgram(p2);
gl.uniform4fv(colorLocP2, [0, 1, 0, 1]);
gl.useProgram(p3);
gl.uniform4fv(colorLocP3, [0, 0, 1, 1]);
// draw with each program
const positionIndex = 0;
gl.vertexAttrib2f(positionIndex, -0.5, 0);
gl.useProgram(p1);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.vertexAttrib2f(positionIndex, 0.0, 0);
gl.useProgram(p2);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.vertexAttrib2f(positionIndex, 0.5, 0);
gl.useProgram(p3);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
атрибуты являются частью состояния массива вершин
К каждому включенному атрибуту прикреплен буфер при вызове vertexAttribPointer
Единицы текстуры имеют глобальное состояние.
Какая единица текстуры используется единообразным сэмплером конкретной программы - это состояние программы (то есть униформа, то есть состояние программы). Но то, что текстуры на каждом текстурном блоке, является глобальным состоянием. Другими словами, если у вас есть шейдерная программа с
uniform sampler2D foo;
Затем вы сообщаете шейдерной программе, какой текстурный модуль использовать с
gl.uniform1i(fooLocation, indexOfTextureUnit);
Но только укажите, является ли каждая текстурная единица глобальным состоянием. Например, если это было реализовано в JavaScript
gl = {
activeTexture: 0,
textureUnits: [
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
{ TEXTURE_2D: null, TEXTURE_CUBE_MAP: null, ... },
... MAX_COMBINED_TEXTURE_UNITS ...
],
};
и функции, которые манипулируют текстурами, работают на этих единицах, как это
gl = {
activeTexture(unitEnum) {
this.activeTexture = unitEnum - gl.TEXTURE0;
}
bindTexture(target, texture) {
const textureUnit = this.textureUnits[this.activeTexture];
textureUnit[target] = texture;
}
texImage2D(target, ...args) {
const textureUnit = this.textureUnits[this.activeTexture];
updateDataToTexture(textureUnit[target], ...args);
}
}