2

モバイルデバイスのキャンバスのサイズをデバイスの画面の実際のピクセルサイズに1対1にする方法はありますか?

これは、Google Cardboard (VR) アプリケーションをサイトから直接サポートするために重要です。(この場合、dpi は本当に重要です)

現在、viewport target-densitydpi を使用する唯一の方法は廃止されており、最新のブラウザーでは機能しません。

4

1 に答える 1

3

最も簡単な方法は、CSS を使用してキャンバスのサイズを決定することです。canvas.clientWidth次に、とを使用して、ブラウザーが CSS ピクセルでキャンバスを表示しているサイズを調べますcanvas.clientHeight。これを掛けて、window.devicePixelRatioそれらの CSS ピクセルが表すデバイス ピクセルの数を取得し、キャンバスのコンテンツ/描画バッファ サイズを一致するように設定します。

例:

  1. キャンバスを作る

    <canvas id="c"></canvas>  
    
  2. CSS を使用してサイズを設定する

    ここでは、キャンバスをビューポート (ウィンドウ) のサイズにしています。

    body {
      margin: 0;
    }
    canvas {
      width: 100vw;
      height: 100vh; 
      display: block;
    }
    
  3. 表示されているサイズを調べて、描画バッファのサイズと一致させます。

    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;
    }
    
  4. 各フレームをレンダリングする前にサイズを調整します

    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 はフルスクリーン APIをサポートしていません。Chrome for android はサポートしていますが、ウェブサイトを HTTPS から提供する必要があります。

これもあなたの<head>セクションに入れるべきです

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

そして、あなたが望むものに応じてまたはに設定user-scalableしますyesno

于 2016-04-26T11:47:48.480 に答える