最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ThreeJS updating texture with HTML canvas gives "WebGL: INVALID_VALUE: texImage2D: no canvas" on

programmeradmin15浏览0评论

I am trying to update a THREE.Texture ".image" property with an HTML5 canvas object. This works on Chromium (MacOSX) on my laptop. However, iPhone Safari and iPhone Chrome both does not work. What could be the root cause and how to fix this?

Using Web Inspector in Safari, I get this error message:

WebGL: INVALID_VALUE: texImage2D: no canvas.

I made sure the canvas is pletely drawn before being updated, using the below code to update the material:

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

Here is how material is used:

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

Strangely, if I use THREE.ImageUtils.loadTexture to load an image, it works fine. However, my use case is that I have to use an canvas object (multiple images on a canvas).

Thanks.

I am trying to update a THREE.Texture ".image" property with an HTML5 canvas object. This works on Chromium (MacOSX) on my laptop. However, iPhone Safari and iPhone Chrome both does not work. What could be the root cause and how to fix this?

Using Web Inspector in Safari, I get this error message:

WebGL: INVALID_VALUE: texImage2D: no canvas.

I made sure the canvas is pletely drawn before being updated, using the below code to update the material:

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

Here is how material is used:

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

Strangely, if I use THREE.ImageUtils.loadTexture to load an image, it works fine. However, my use case is that I have to use an canvas object (multiple images on a canvas).

Thanks.

Share edited Oct 18, 2019 at 14:29 Rabbid76 211k30 gold badges157 silver badges200 bronze badges asked Jun 9, 2015 at 6:23 Log0Log0 1451 silver badge8 bronze badges 4
  • I met similar issue, do you have any results? – Wayne Wang Commented Aug 7, 2015 at 11:17
  • 1 Just stumbled across the same error. Any luck in finding a solution? – droidballoon Commented Sep 9, 2015 at 13:33
  • 1 @voondo This question is 4 years old. Are you still seeing issues? Are you using the latest version of three.js (currently r109)? The current version supports CanvasTexture. – TheJim01 Commented Oct 18, 2019 at 15:30
  • Here's an article otherwise post a snippet. What size is your canvas? iPhone browsers only support max 4096x4096 IIRC – user128511 Commented Oct 18, 2019 at 15:40
Add a ment  | 

2 Answers 2

Reset to default 5

According to the Texture docs, the .image property is more of a "getter" for the image element created via the TextureLoader.load() method. If you want to create a texture with a <canvas> element, you can create it with new THREE.Texture(canvas); as demonstrated via the snippet below. The texture creation takes place in the makeCanvasTexture() function:

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./ajax/libs/three.js/109/three.min.js"></script>

Keep in mind that WebGL texture size is limited depending on each device's graphics card capabilities, so you'll get errors if you try to create a canvas that breaches this limitation. You can see the limit of your current device by visiting https://webglreport./ and looking at the "Max texture size" readout on the right. Mine is 8192px².

Likewise, you can access this information programmatically with THREE.WebGLRenderer.capabilities.maxTextureSize as explained in this documentation page so you can use this number to prevent canvas sizes from going beyond the device's limit.

This is is probably fixed from this mit on d3-x3d, Fix #14 texImage2D: no canvas. which is related to this (already closed) issue, INVALID_VALUE: texImage2D: no canvas.

If the problem still persists, this is possibly related to the limitations of each browser on their maximum supported canvas dimensions/area.

Please refer to this answer from another post to look for the said limitations per browser.

Exceeding the maximum length/width/area on most browsers renders the canvas unusable. (It will ignore any draw mands, even in the usable area.)
- Brandon Gano

Unfortunately there's no given figures for Safari from the upvoted answer, but you may look for the ments under it like:

iOS 9.3.1 Safari on an iPhone 6 Plus is limited to an area of 16777216 pixels (for example, 4096 x 4096)
- matb33

Or look into the other answers of the post like this

Therefore, any size variation of 5242880 (5 x 1024 x 1024) pixels will work on large memory devices, otherwise it's 3145728 pixels.

Example for 5 megapixel canvas (width x height):

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

and so on..

The largest SQUARE canvases are ("MiB" = 1024x1024 Bytes):

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

Another possible factor is the client side's graphics card.

发布评论

评论列表(0)

  1. 暂无评论