【问题标题】:OffscreenCanvas.getContext().fillText() produces texts that are upside down. How to flip them?OffscreenCanvas.getContext().fillText() 产生颠倒的文本。如何翻转它们?
【发布时间】:2020-04-21 14:39:56
【问题描述】:

我使用OffscreenCanvas.getContext().fillText() 生成一些文本,然后使用OffscreenCanvas.transferToImageBitmap() 获取地图,但是当我将其用作threejs 项目的纹理时,它们被颠倒了。请查看显示字母“R”如何错误显示的图像。

我想我可以使用createImageBitmap()flipY 选项来更改文本的方向,但我没有从该功能中得到任何信息。没有崩溃,但没有显示任何文本。

你能告诉我其他的技巧吗?

【问题讨论】:

    标签: javascript three.js html5-canvas


    【解决方案1】:

    使用 OffscreenCanvas 并将其传递给 THREE.CanvasTexture 似乎在工作人员中工作正常。设置texture.flipY = false也可以(默认为true)

    在下面的示例中,texture.flipY = false 被注释掉了,但如果你取消注释,你会看到纹理翻转

    // Three.js - OffscreenCanvas
    // from https://threejsfundamentals.org/threejs/threejs-offscreencanvas.html
    
    'use strict';  // eslint-disable-line
    
    function main() {  /* eslint consistent-return: 0 */
      const canvas = document.querySelector('#c');
      if (!canvas.transferControlToOffscreen) {
        canvas.style.display = 'none';
        document.querySelector('#noOffscreenCanvas').style.display = '';
        return;
      }
      const offscreen = canvas.transferControlToOffscreen();
      const worker = new Worker(getWorkerBlob());
      worker.postMessage({type: 'main', canvas: offscreen}, [offscreen]);
    
      function sendSize() {
        worker.postMessage({
          type: 'size',
          width: canvas.clientWidth,
          height: canvas.clientHeight,
        });
      }
    
      window.addEventListener('resize', sendSize);
      sendSize();
    }
    main();
    
    
    
    
    
    // ------
    // Creates Blobs for the Worker Scripts so things can be self contained for snippets/JSFiddle/Codepen
    //
    function getWorkerBlob() {
      const idsToUrls = [];
      const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
      for (const scriptElement of scriptElements) {
        let text = scriptElement.text;
        for (const {id, url} of idsToUrls) {
          text = text.split(id).join(url);
        }
        const blob = new Blob([text], {type: 'application/javascript'});
        const url = URL.createObjectURL(blob);
        const id = scriptElement.id;
        idsToUrls.push({id, url});
      }
      return idsToUrls.pop().url;
    }
    body {
      margin: 0;
    }
    #c {
      width: 100vw;
      height: 100vh;
      display: block;
    }
    #noOffscreenCanvas {
      display: flex;
      width: 100vw;
      height: 100vh;
      align-items: center;
      justify-content: center;
      background: red;
      color: white;
    }
    <script id="worker-offscreencanvas-cubes.js" type="x-worker">
    'use strict';  // eslint-disable-line
    
    /* global importScripts, THREE */
    
    importScripts('https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.min.js');
    
    const state = {
      width: 300,   // canvas default
      height: 150,  // canvas default
    };
    
    function main(data) {
      const {canvas} = data;
      const renderer = new THREE.WebGLRenderer({canvas});
    
      state.width = canvas.width;
      state.height = canvas.height;
    
      const fov = 75;
      const aspect = 2; // the canvas default
      const near = 0.1;
      const far = 100;
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
      camera.position.z = 4;
    
      const scene = new THREE.Scene();
    
      {
        const color = 0xFFFFFF;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(-1, 2, 4);
        scene.add(light);
      }
    
      const boxWidth = 1;
      const boxHeight = 1;
      const boxDepth = 1;
      const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
    
      const offscreenCanvas = new OffscreenCanvas(256, 256);
      const ctx = offscreenCanvas.getContext('2d');
      ctx.fillStyle = '#FDB';
      ctx.fillRect(0, 0, 256, 256);
      ctx.font = '200px bold sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillStyle = '#666';
      ctx.fillText('F', 128, 128);
      const texture = new THREE.CanvasTexture(offscreenCanvas);
    
    // texture.flipY = false;
    
      function makeInstance(geometry, color, x) {
        const material = new THREE.MeshPhongMaterial({
          map: texture,
        });
    
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
    
        cube.position.x = x;
    
        return cube;
      }
    
      const cubes = [
        makeInstance(geometry, 0x44aa88, 0),
        makeInstance(geometry, 0x8844aa, -2),
        makeInstance(geometry, 0xaa8844, 2),
      ];
    
      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement;
        const width = state.width;
        const height = state.height;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
          renderer.setSize(width, height, false);
        }
        return needResize;
      }
    
      function render(time) {
        time *= 0.001;
    
        if (resizeRendererToDisplaySize(renderer)) {
          camera.aspect = state.width / state.height;
          camera.updateProjectionMatrix();
        }
    
        cubes.forEach((cube, ndx) => {
          const speed = 1 + ndx * .1;
          const rot = time * speed;
          cube.rotation.x = rot;
          cube.rotation.y = rot;
        });
    
        renderer.render(scene, camera);
    
        requestAnimationFrame(render);
      }
    
      requestAnimationFrame(render);
    }
    
    function size(data) {
      state.width = data.width;
      state.height = data.height;
    }
    
    const handlers = {
      main,
      size,
    };
    
    self.onmessage = function(e) {
      const fn = handlers[e.data.type];
      if (!fn) {
        throw new Error('no handler for type: ' + e.data.type);
      }
      fn(e.data);
    };
    
    </script><canvas id="c"></canvas>
        <div id="noOffscreenCanvas" style="display:none;">
          <div>no OffscreenCanvas support</div>
        </div>
      

    【讨论】:

    • 谢谢。你说得对。我没有意识到我可以将 OffscreenCanvas 传递给 CanvasTexture。 CanvasTexture 签名“...canvas : HTMLElement...”的three.js 文档有点误导我。好吧,事后看来,我应该知道签名只是一个提示,而不是强类型合同。
    【解决方案2】:

    在您的threejs 纹理上设置 .flipY = false。由于涉及扫描线光栅的历史原因,OpenGL 纹理默认垂直翻转。

    【讨论】:

    • three.js documentation 表示flipY 不适用于ImageBitmap。无论如何我都对其进行了测试,但它并没有按预期工作。三.js依赖底层createImageBitmap()来设置flipY。
    • 你把它设置在你的threejs纹理上......不是你的“imagebitmap”
    • 你也不需要那个 transferinagetobitmap 垃圾。只需使用 THREE.CanvasTexture(你的画布)
    • 我也许应该强调“屏幕外”方法,这基本上意味着整个 three.js 的东西都发生在 web worker 中。 THREE.CanvasTexture() 需要访问“文档”,这在 Web Worker 中是无法访问的。所以,它会崩溃。这就是整个问题的开始。顺便说一句,如果我在前面的画布中使用three.js,一切都会完美无缺。但我需要的是如何在屏幕外进行。
    • THREE.CanvasTexture 在 Chrome 的工作人员中通过 OffscreenCanvas 似乎工作得很好。 (jsfiddle.net/greggman/1wmtu0dx) AFAIK Firefox 仍然不支持 OffscreenCanvas
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多