使用HTML画布更新纹理ThreeJS给出" WebGL:INVALID_VALUE:texImage2D:没有画布"在手机上(iPhone Safari等)

时间:2015-06-09 06:23:45

标签: javascript ios html5 three.js

我正在尝试更新THREE.Texture" .image"具有HTML5画布对象的属性。这适用于笔记本电脑上的Chromium(MacOSX)。但是,iPhone Safari和iPhone Chrome都不起作用。可能是根本原因以及如何解决这个问题?

在Safari中使用Web Inspector,我收到以下错误消息:" WebGL:INVALID_VALUE:texImage2D:no canvas "。

我确保在更新之前完全绘制画布,使用以下代码更新材料:

material.map.image = loaded_canvas[curr_id]; // loaded_canvas stores canvas that has been completed loaded already, drawn by Image() objects.
material.map.needsUpdate = true; 

以下是材料的使用方法:

var geometry = new THREE.SphereGeometry(100.0, 32, 32);
var material = new THREE.MeshBasicMaterial({
  map: THREE.ImageUtils.loadTexture(image_path),
  side: THREE.BackSide,
});

奇怪的是,如果我使用THREE.ImageUtils.loadTexture加载图像,它可以正常工作。但是,我的用例是我必须使用画布对象(画布上的多个图像)。

感谢。

2 个答案:

答案 0 :(得分:1)

根据Texture docs,对于通过TextureLoader.load()方法创建的图像元素,.image属性更像是一个“获取器”。如果要使用<canvas>元素创建纹理,则可以使用new THREE.Texture(canvas);创建纹理,如下面的代码片段所示。纹理创建在makeCanvasTexture()函数中进行:

function makeCanvasTexture() {
    // Create canvas context
    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");
    canvas.width = 32;
    canvas.height = 32;

    // Draw radial gradient
    var grad = context.createRadialGradient(16, 16, 6, 16, 16, 16);
    grad.addColorStop(0, "rgba(255, 150, 0, 1.0");
    grad.addColorStop(0.5, "rgba(255, 0, 150, 1.0");
    grad.addColorStop(1, "rgba(0, 150, 255, 1.0)");
    context.fillStyle = grad;
    context.fillRect(0, 0, 32, 32);

    // Use canvas to create texture
    var canvasTexture = new THREE.Texture(canvas);
    canvasTexture.needsUpdate = true;

    return canvasTexture;
}

// Boilerplate Three.js setup
var camera, scene, renderer;
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xe1e1e1);
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 30, -30);
camera.lookAt(0, 0, 0);

const ambient = new THREE.DirectionalLight(0xddeeff, 1);
ambient.position.set(0, 1, 1);

// Using canvas as material map texture:
const floor = new THREE.Mesh(
    new THREE.BoxBufferGeometry(20, 0.25, 20),
    new THREE.MeshBasicMaterial({map: makeCanvasTexture()})
);

scene.add(ambient, floor);

function animate(t) {
	// Animate mesh
    floor.rotation.z += Math.sin(t * 0.001) * 0.1;
	renderer.render(scene, camera);
	requestAnimationFrame(animate);
}

animate(0);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script>

请记住,WebGL纹理大小受每个设备的图形卡功能的限制,因此,如果您尝试创建违反此限制的画布,则会出错。您可以通过访问https://webglreport.com/并查看右侧的“最大纹理大小”来查看当前设备的限制。我的是8192px²。

enter image description here

同样,您可以按照in this documentation page的说明使用THREE.WebGLRenderer.capabilities.maxTextureSize以编程方式访问此信息,因此可以使用此数字来防止画布尺寸超出设备的限制。

答案 1 :(得分:0)

此问题很可能是由于对d3-x3d Fix #14 texImage2D: no canvas.的此提交(已关闭)INVALID_VALUE: texImage2D: no canvas的提交而得到的修复

如果问题仍然存在,则可能与每个浏览器在其支持的最大画布尺寸/区域上的限制有关。

请参考另一篇文章的this答案,以了解每个浏览器的上述限制。

  

在大多数浏览器中超过最大长度/宽度/面积会使画布无法使用。 (即使在可用区域中,它也会忽略任何绘制命令。)
  -Brandon Gano

不幸的是,答案没有给出Safari的具体数字,但是您可以在下面找到它的注释:

  

iPhone 6 Plus上的iOS 9.3.1 Safari仅限16777216像素(例如4096 x 4096)区域
  -matb33

或者查看帖子的其他答案,例如this

  

因此,任何尺寸变化为5242880(5 x 1024 x 1024)像素的像素   可以在大型存储设备上运行,否则为3145728像素。

     

5百万像素画布(宽x高)的示例:

Any total <= 5242880
--------------------
5 x 1048576 ~= 5MP   (1048576 = 1024 x 1024)
50 x 104857 ~= 5MP
500 x 10485 ~= 5MP
     

以此类推。

     

最大的SQUARE画布为(“ MiB” = 1024x1024字节):

device < 256 MiB   device >= 256 MiB   iPhone 6 [not confirmed]
-----------------  -----------------   ---------------------
<= 3145728 pixels  <= 5242880 pixels   <= 16 x 1024 x 1024 p
1773 x 1773        2289 x 2289         4096 x 4096
     

-dcbarans

另一个可能的因素是客户端的图形卡。