deepkolos / three-platformize

一个让 THREE 平台化的项目,目前已适配微信,淘宝,头条小程序,微信小游戏
533 stars 82 forks source link

当用canvas渲染文字时出错 #17

Closed jenerse closed 3 years ago

jenerse commented 3 years ago

想在threejs 里用canvas渲染一个2d的文字,但总是报以下错误

THREE.WebGLState: TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': Overload resolution failed.

附上部分代码: wxml:

<canvas type='2d' id='canvas-text' />
<canvas type='webgl' id='canvas' />

js:

onLaunch() {
    this.canvas = (await getNode('#canvas'))[0].node;
    this.canvasText = (await getNode('#canvas-text'))[0].node;
    this.platform = new WechatPlatform(this.canvas); // webgl canvas

    this.platform.enableDeviceOrientation('game'); // 开启DeviceOrientation
    THREE.PLATFORM.set(this.platform);

    this.init();
    this.animate();
}
changeCanvas() {
    const ctx = this.canvasText.getContext('2d');
    ctx.font = '16pt Arial';
    ctx.fillStyle = 'orange';
    ctx.fillRect(0, 0, this.canvasText.width, this.canvasText.height);
    ctx.fillStyle = 'white';
    ctx.fillRect(10, 10, this.canvasText.width - 20, this.canvasText.height - 20);
    ctx.fillStyle = 'black';
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText("踏得网", this.canvasText.width / 2, this.canvasText.height / 2);
}
init() {
    this.renderer = new THREE.WebGL1Renderer({
        antialias: true,   // 抗锯齿
    });
    this.renderer.setSize(this.canvas.width, this.canvas.height);
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(70, this.canvas.width / this.canvas.height, 1, 1000);
    this.camera.position.z = 500;
    this.scene.add(this.camera);
    this.texture = new THREE.Texture(this.canvasText);
    this.material = new THREE.MeshBasicMaterial({
        map: this.texture
    });
    const geometry = new THREE.BoxGeometry(200, 200, 200);
    this.mesh = new THREE.Mesh(geometry, this.material);
    this.scene.add(this.mesh);
}

animate() {
    THREE.$requestAnimationFrame(() => this.animate());

        this.changeCanvas();
    this.texture.needsUpdate = true;
    this.mesh.rotation.y += 0.01;
    this.renderer.render(this.scene, this.camera);
}

ps:以上例子能够在html版本运行(引入的是最新的three.js) 附上完整html代码:

        <!DOCTYPE html>
        <html lang="en">
            <head>
    <title>three.js webgl - materials - canvas texture</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link type="text/css" rel="stylesheet" href="main.css">
    <style>
        #drawing-canvas {
            position: absolute;
            background-color: #000000;
            top: 0px;
            right: 0px;
            z-index: 3000;
            cursor: crosshair;
            touch-action: none;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>

    <script type="module">

        import * as THREE from '../build/three.module.js';

        var width = window.innerWidth,
            height = window.innerHeight / 2;
        var size = 128;
        var canvas = document.getElementById('canvas'),
            ctx = canvas.getContext('2d');

        var camera, scene, renderer, geometry, texture, mesh;

        function changeCanvas() {
            ctx.font = '16pt Arial';
            ctx.fillStyle = 'orange';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = 'white';
            ctx.fillRect(10, 10, canvas.width - 20, canvas.height - 20);
            ctx.fillStyle = 'black';
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillText("踏得网", canvas.width / 2, canvas.height / 2);
        }

        function init() {
            renderer = new THREE.WebGLRenderer();
            renderer.setSize(width, height);
            document.body.appendChild(renderer.domElement);

            scene = new THREE.Scene();

            camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000);
            camera.position.z = 500;
            scene.add(camera);

            texture = new THREE.Texture(canvas);
            var material = new THREE.MeshBasicMaterial({
                map: texture
            });
            geometry = new THREE.BoxGeometry(200, 200, 200);
            mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

            canvas.width = canvas.height = size;
        }

        function animate() {
            requestAnimationFrame(animate);

            changeCanvas();
            texture.needsUpdate = true;
            mesh.rotation.y += 0.01;
            renderer.render(scene, camera);
        }

        init();
        animate();

    </script>

            </body>
        </html>

感谢作者!

deepkolos commented 3 years ago

可以canvas2d读取imageData,然后使用DataTexture写入webgl的纹理

ctx.getImageData(0,0, canvas2d.width, canvas2d.height)
jenerse commented 3 years ago

可以canvas2d读取imageData,然后使用DataTexture写入webgl的纹理

ctx.getImageData(0,0, canvas2d.width, canvas2d.height)

感谢,我回去试试

jenerse commented 3 years ago

@deepkolos 试了一下,错误没有了,但开发工具渲染空白,真机也是空白但抛出了一个warning

THREE.WebGLRenderer: EXT_blend_minmax extension not supported;

但不知道是不是因为这个渲染不出来

代码:

const ctx = canvas2d.getContext('2d');
const data = ctx.getImageData(0, 0, 128, 128);
const texture = new THREE.DataTexture(new Uint8Array(data.data.buffer));
jenerse commented 3 years ago

@deepkolos 已找到方法

const ctx = canvas2d.getContext('2d');
const texture = new THREE.Texture(ctx.canvas);
632366134 commented 1 year ago

@deepkolos 已找到方法

const ctx = canvas2d.getContext('2d');
const texture = new THREE.Texture(ctx.canvas);

this.texture.needsUpdate = true;会直接闪退