Изменение размера текстур холста и webGL
Я хочу изменить размер своего окна и сделать так, чтобы холст и все в нем растягивалось, чтобы заполнить окно, когда оно расширяется / сжимается.
Это немного сложно, потому что в моем коде webgl я создаю цикл обратной связи между последовательной цепочкой кадровых буферов и фрагментных шейдеров. В одном вершинном шейдере происходит небольшое преобразование, чтобы поддерживать цикл обратной связи. Если я вызываю следующее для события resize, оно делает дополнительное преобразование, которое мне не нужно, и отправляет цикл обратной связи из-под контроля. Тем не менее, он растягивает текстуры, чтобы соответствовать окну.
gl.viewport(0,0,canvas.clientWidth, canvas.clientHeight);
Я также попытался сделать слушатель событий, чтобы изменить размер холста, но текстуры не изменяют размер вместе с ним. Вместо этого они просто остаются запертыми в левом нижнем углу моего окна. Проверка элемента canvas показывает, что холст действительно изменил размер, а текстуры - нет.
window.addEventListener( 'resize', resizeCanvas );
function resizeCanvas(){
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if(canvas.width != width ||
canvas.height != height){
canvas.width = width;
canvas.height = height;
//gl.viewport(0,0,width, height);
}
}
Я хочу сделать это без необходимости перераспределять мои FBO. По какой-то причине я думал, что смогу просто растянуть свой холст и все, что на нем, но я не могу заставить его работать.
Вот ссылка на страницу с моим полным кодом webgl. У этого нет никаких петель обратной связи для простоты, но я могу опубликовать один, если было бы полезно увидеть. Заранее спасибо за помощь!
1 ответ
Я не уверен, что понимаю проблему, но, глядя на ваш код, если ваши вложения кадрового буфера (в данном случае текстуры) имеют другой размер, чем ваш холст, который вам нужно вызвать gl.viewport
каждый раз, когда вы меняете текущий кадровый буфер.
Другими словами в псевдокоде
function(render) {
resizeCanvas();
gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer);
gl.viewport(0, 0, widthOfSomeFramebuffer, heightOfSomeFramebuffer);
drawStuffToFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, someOtherFramebuffer);
gl.viewport(0, 0, widthOfSomeOtherFramebuffer, heightOtherOfSomeFramebuffer);
drawStuffToOtherFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
drawStuffToCanvas();
requestAnimationFrame(render);
}
render();
В большинстве случаев область просмотра всегда должна быть установлена на размер холста при рисовании на холст (width
а также height
не clientWidth
а также clientHeight
). использование clientWidth
а также clientHeight
для изменения размера и / или для вычисления соотношения сторон для вашей проекции, будь то проекция 2d или 3d. На самом деле это возможно неправильно использовать clientWidth
а также clientHeight
за gl.viewport
,
Вы можете думать о gl.viewport
как определение области, которую вы хотите нарисовать. Установка его в gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
в основном говорит, что вы хотите нарисовать на всем холсте.
Это не вся правда, хотя. gl.viewport
в основном задает, как преобразовать пространство клипа (-1 <-> +1), пространство, используемое в ваших шейдерах, обратно в пиксельное пространство на любой текущей поверхности рисования (холст или кадровый буфер). Итак, установив область просмотра на gl.viewport(x, y, width, height)
говорит, что от -1 до +1 в x идет от пикселей x до x + w - 1 на текущей поверхности рисования, а от -1 до +1 в y идет от пикселей y до y + высота - 1 на текущей поверхности рисования.
Так как в большинстве случаев вы хотите рисовать на всей поверхности рисования, вам нужно установить gl.viewport
к размеру поверхности, к которой вы рисуете.
Надеюсь, это дает понять, почему использование clientWidth
а также clientHeight
не подходит для gl.viewport
так как clientWidth
а также clientHeight
не имеют никакого отношения к фактическому размеру холста (пикселей в нем). Они относятся только к тому, насколько велики эти пиксели растянуты или сжаты. Другими словами
<canvas width="10" height="20" style="width: 30px; height: 40px"></canvas>
...
console.log("canvas.width : " + canvas.width);
console.log("canvas.height : " + canvas.height);
console.log("canvas.clientWidth : " + canvas.clientWidth);
console.log("canvas.clientHeight: " + canvas.clientHeight);
Будет печатать
canvas.width : 10
canvas.height : 20
canvas.clientWidth : 30
canvas.clientHeight: 40
Это означает, что на холсте есть только 10х20 пикселей, но они растягиваются до 30х40 на странице. Установка области просмотра на gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight)
было бы сказать, что вы хотите нарисовать в области 30 пикселей в ширину и 40 пикселей в высоту, но на самом деле у вас есть только 10 пикселей в ширину и 20 пикселей вниз
Что касается обработки изменения размера, если вы постоянно выполняете рендеринг (который выглядит так, как будто вы находитесь в своем коде), то проще всего и, пожалуй, лучше всего вызывать изменение размера в начале цикла рендеринга.