在移动设备上全屏、全 dpi WebGL canvas
Fullscreen, full dpi WebGL canvas on mobile device
有什么方法可以使 canvas 在移动设备上的大小与设备屏幕的实际像素大小成一比?
这对于 google 直接从站点支持纸板 (VR) 应用程序很重要。 (在这种情况下 dpi 真的很重要)
目前使用视口 target-densitydpi 的唯一方法已被弃用,并且不适用于现代浏览器。
最简单的方法是使用 CSS 来决定您想要 canvas 的尺寸。然后使用 canvas.clientWidth
和 canvas.clientHeight
查看浏览器以 CSS 像素显示的 canvas 的大小。现在将其乘以 window.devicePixelRatio
以获得那些 CSS 像素代表的设备像素数,并设置 canvas 的 content/drawingbuffer 大小以匹配。
示例:
制作canvas
<canvas id="c"></canvas>
使用 CSS
设置其大小
在这里,我将 canvas 设为视口的大小(window)。
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
查找显示的大小并匹配其绘图缓冲区大小。
function resizeToMatchDisplaySize(canvas) {
var displayWidth = canvas.clientWidth * window.devicePixelRatio;
var displayHeight = canvas.clientHeight * window.devicePixelRatio;
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
canvas.width = displayWidth;
canvas.height = displayHeight;
return true;
}
return false;
}
在渲染每一帧之前调整大小
function render() {
// resize before rendering in case of resizing or rotation
if (resizeToMatchDisplaySize(gl.canvas)) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
// render scene
requestAnimationFrame(render);
}
requestAnimationFrame(render);
下面是一个画线的例子
var gl = document.querySelector("#c").getContext("webgl", { alpha: false });
var programInfo = twgl.createProgramInfo(gl, ['vs', 'fs']);
var ids = [];
for (var i = 0; i < 500; ++i) {
ids.push(i);
}
var arrays = {
vertexId: { size:1, data: ids},
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
time: 0,
numIds: ids.length,
resolution: [0, 0],
};
function resizeToMatchDisplaySize(canvas) {
var displayWidth = canvas.clientWidth * window.devicePixelRatio;
var displayHeight = canvas.clientHeight * window.devicePixelRatio;
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
canvas.width = displayWidth;
canvas.height = displayHeight;
return true;
}
return false;
}
function render(time) {
// resize before rendering in case of resizing or rotation
if (resizeToMatchDisplaySize(gl.canvas)) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
// render scene
gl.useProgram(programInfo.program);
uniforms.time = time * 0.001;
uniforms.resolution[0] = gl.drawingBufferWidth;
uniforms.resolution[1] = gl.drawingBufferHeight;
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.LINES, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<canvas id="c"></canvas>
<script id="vs" type="notjs">
attribute float vertexId;
varying vec4 v_color;
uniform float numIds;
uniform float time;
uniform vec2 resolution;
#define PI radians(180.0)
vec3 hsv2rgb(vec3 c) {
c = vec3(c.x, clamp(c.yz, 0.0, 1.0));
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec4 offsets = vec4(
sin(time),
sin(time * .13) * PI * 2.,
sin(time * .43) * .5 + 1.,
cos(time * .17) * .5 + .5);
vec4 centers = vec4(
sin(time * .163) * .5,
cos(time * .267) * .5,
sin(time * .367) * .5,
cos(time * .497) * .5);
vec4 mult = vec4(
1.,
(sin(time * .1) * .5 + .5) * 3.,
0.,
0.);
vec2 position = vec2(vertexId / numIds, mod(vertexId, 2.));
vec2 offset = mix(offsets.xz, offsets.yw, position.y);
float a = mult.x * position.x * PI * 2.0 + offset.x;//mix(u_offsets.x, u_offsets.y, a_position.y);
float c = cos(a * mult.y);
vec2 xy = vec2(
cos(a),
sin(a)) * c * offset.y +
mix(centers.xy, centers.zw, position.y);
vec2 aspect = vec2(resolution.y / resolution.x, 1);
gl_Position = vec4(xy * aspect, 0, 1);
float hue = position.x;
float sat = 1.;
float val = 1.;
v_color = vec4(hsv2rgb(vec3(hue, sat, val)), 1);
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
</script>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
请注意,您问了 2 个问题。如何获得原生 1x1 像素以及如何进入全屏。全屏更难。 iOS Safari 不支持 fullscreen API。 Chrome for android 可以,但它需要您的网站从 HTTPS 提供服务。
你也应该把这个放在你的<head>
部分
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
并根据需要将user-scalable
设置为yes
或no
有什么方法可以使 canvas 在移动设备上的大小与设备屏幕的实际像素大小成一比?
这对于 google 直接从站点支持纸板 (VR) 应用程序很重要。 (在这种情况下 dpi 真的很重要)
目前使用视口 target-densitydpi 的唯一方法已被弃用,并且不适用于现代浏览器。
最简单的方法是使用 CSS 来决定您想要 canvas 的尺寸。然后使用 canvas.clientWidth
和 canvas.clientHeight
查看浏览器以 CSS 像素显示的 canvas 的大小。现在将其乘以 window.devicePixelRatio
以获得那些 CSS 像素代表的设备像素数,并设置 canvas 的 content/drawingbuffer 大小以匹配。
示例:
制作canvas
<canvas id="c"></canvas>
使用 CSS
设置其大小在这里,我将 canvas 设为视口的大小(window)。
body { margin: 0; } canvas { width: 100vw; height: 100vh; display: block; }
查找显示的大小并匹配其绘图缓冲区大小。
function resizeToMatchDisplaySize(canvas) { var displayWidth = canvas.clientWidth * window.devicePixelRatio; var displayHeight = canvas.clientHeight * window.devicePixelRatio; if (canvas.width !== displayWidth || canvas.height !== displayHeight) { canvas.width = displayWidth; canvas.height = displayHeight; return true; } return false; }
在渲染每一帧之前调整大小
function render() { // resize before rendering in case of resizing or rotation if (resizeToMatchDisplaySize(gl.canvas)) { gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); } // render scene requestAnimationFrame(render); } requestAnimationFrame(render);
下面是一个画线的例子
var gl = document.querySelector("#c").getContext("webgl", { alpha: false });
var programInfo = twgl.createProgramInfo(gl, ['vs', 'fs']);
var ids = [];
for (var i = 0; i < 500; ++i) {
ids.push(i);
}
var arrays = {
vertexId: { size:1, data: ids},
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
time: 0,
numIds: ids.length,
resolution: [0, 0],
};
function resizeToMatchDisplaySize(canvas) {
var displayWidth = canvas.clientWidth * window.devicePixelRatio;
var displayHeight = canvas.clientHeight * window.devicePixelRatio;
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
canvas.width = displayWidth;
canvas.height = displayHeight;
return true;
}
return false;
}
function render(time) {
// resize before rendering in case of resizing or rotation
if (resizeToMatchDisplaySize(gl.canvas)) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
// render scene
gl.useProgram(programInfo.program);
uniforms.time = time * 0.001;
uniforms.resolution[0] = gl.drawingBufferWidth;
uniforms.resolution[1] = gl.drawingBufferHeight;
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.LINES, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<canvas id="c"></canvas>
<script id="vs" type="notjs">
attribute float vertexId;
varying vec4 v_color;
uniform float numIds;
uniform float time;
uniform vec2 resolution;
#define PI radians(180.0)
vec3 hsv2rgb(vec3 c) {
c = vec3(c.x, clamp(c.yz, 0.0, 1.0));
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec4 offsets = vec4(
sin(time),
sin(time * .13) * PI * 2.,
sin(time * .43) * .5 + 1.,
cos(time * .17) * .5 + .5);
vec4 centers = vec4(
sin(time * .163) * .5,
cos(time * .267) * .5,
sin(time * .367) * .5,
cos(time * .497) * .5);
vec4 mult = vec4(
1.,
(sin(time * .1) * .5 + .5) * 3.,
0.,
0.);
vec2 position = vec2(vertexId / numIds, mod(vertexId, 2.));
vec2 offset = mix(offsets.xz, offsets.yw, position.y);
float a = mult.x * position.x * PI * 2.0 + offset.x;//mix(u_offsets.x, u_offsets.y, a_position.y);
float c = cos(a * mult.y);
vec2 xy = vec2(
cos(a),
sin(a)) * c * offset.y +
mix(centers.xy, centers.zw, position.y);
vec2 aspect = vec2(resolution.y / resolution.x, 1);
gl_Position = vec4(xy * aspect, 0, 1);
float hue = position.x;
float sat = 1.;
float val = 1.;
v_color = vec4(hsv2rgb(vec3(hue, sat, val)), 1);
}
</script>
<script id="fs" type="notjs">
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
</script>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
请注意,您问了 2 个问题。如何获得原生 1x1 像素以及如何进入全屏。全屏更难。 iOS Safari 不支持 fullscreen API。 Chrome for android 可以,但它需要您的网站从 HTTPS 提供服务。
你也应该把这个放在你的<head>
部分
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
并根据需要将user-scalable
设置为yes
或no