Вот, что вам следует знать об изменениях размера canvas.
Каждый canvas имеет 2 размера. Первый - размер буфера отрисовки. Он отвечает за то, сколько пикселей помещается в canvas. Второй - размер отображаемого на HTML-странице элемента canvas. Этот размер задаётся через CSS.
Размер буфера отрисовки можно задать двумя способами. Первый - через HTML:
<canvas id="c" width="400" height="300"></canvas>
Второй способ - через JavaScript:
<canvas id="c" ></canvas>
JavaScript
var canvas = document.querySelector("#c");
canvas.width = 400;
canvas.height = 300;
Что касается размера отображаемого элемента, то при отсутствии стилей CSS, которые влияют на элемент, размер элемента будет равен размеру буфера отрисовки. Поэтому в 2 примерах выше размер буфера отрисовки будет равен 400x300, и размер отображаемого элемента будет также равен 400x300.
А вот пример, когда размер буфера отображения - 10x15, а размер HTML-элемента - 400x300 пикселей:
<canvas id="c" width="10" height="15" style="width: 400px; height: 300px;"></canvas>
или можно задать так:
<style>
#c {
width: 400px;
height: 300px;
}
</style>
<canvas id="c" width="10" height="15"></canvas>
Если мы отобразим вращающуюся линию шириной один пиксель, мы получим что-то вроде:
Почему она такая размытая? Потому что браузер принимает canvas 10x15, а затем растягивает его до размера 400x300 пикселей, применяя для этого фильтрацию.
Так что же делать, если, к примеру, нам нужно, чтобы canvas заполнил всё окно? Для начала нам нужны CSS-стили, чтобы браузер растянул canvas на всё окно. Например:
<html>
<head>
<style>
/* убираем границу */
body {
border: 0;
background-color: white;
}
/* растягиваем canvas на всю область просмотра */
canvas {
width: 100vw;
height: 100vh;
display: block;
}
<style>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
Теперь нам нужно, чтобы размер буфера отрисовки соответствовал размеру HTML-элемента,
как бы браузер его ни растянул. Мы можем использовать свойствами clientWidth
и
clientHeight
, которые есть у любого HTML-элемента и которые позволяют JavaScript
узнавать размер отображаемого элемента.
function resize(canvas) {
// получаем размер HTML-элемента canvas
var displayWidth = canvas.clientWidth;
var displayHeight = canvas.clientHeight;
// проверяем, отличается ли размер canvas
if (canvas.width != displayWidth ||
canvas.height != displayHeight) {
// подгоняем размер буфера отрисовки под размер HTML-элемента
canvas.width = displayWidth;
canvas.height = displayHeight;
}
}
Большинство приложений WebGL используют анимацию, поэтому будем вызывать эту функцию непосредственно перед отрисовкой, чтобы при отрисовке размер canvas всегда соответствовал размеру HTML-элемента.
function drawScene() {
resize(gl.canvas);
...
И вот результат:
Но что не так? Почему линия не занимает всю область?
Причина в том, что при изменении размера canvas нам также необходимо вызвать gl.viewport
для установки размера области просмотра. gl.viewport
сообщает WebGL, как и в какую область
внутри canvas преобразовывать координаты пространства отсечения (от -1 до +1) в пиксели.
При первом создании контекста WebGL область просмотра будет соответствовать размеру canvas,
но после этого вам необходимо следить за её размерами. Если вы меняете размер canvas, вам
также необходимо сообщить WebGL новые параметры области просмотра.
Изменим код, чтобы учитывать такую ситуацию. Более того, раз уж ссылка на canvas доступна из контекста WebGL, будем передавать его параметром функции resize.
function drawScene() {
resize(gl.canvas);
+ gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
...
Теперь линия отображается как мы и ожидали.
Откройте пример в отдельном окне и меняйте размер окна. Линия всегда заполняет всё окно.
Слышу, вы спрашиваете, почему WebGL не устанавливает область просмотра для нас автоматически при изменении размера canvas? Просто потому, что он не знает, как и для чего вы используете область просмотра. Например, вы можете выполнять отрисовку во фреймбуфер или заниматься чем-то другим, что требует различного размера области просмотра. WebGL никак не может знать ваши намерения, поэтому он не подстраивает область просмотра.
В разных программах WebGL люди по-разному обрабатывают изменение размера canvas. Если вам интересно, я описал несколько причин, почему я предпочитаю описанный выше подход.