You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ThreeJS中自定义Canvas无法在PlaneGeometry显示GameBoy模拟器画面问题

Fixing GameBoy Emulator Rendering to Three.js Canvas Texture

Hey there! Let's work through why your GameBoy emulator isn't showing up on your Three.js plane. I've looked over your code and hypotheses, and here are concrete fixes and checks to try:

First: Fix the Canvas ID Assignment

You're setting the canvas ID incorrectly here:

x2.style.id = 'display';

The style property handles CSS styles, not the element's core ID. Change this to:

x2.id = 'display';

While you're directly passing the canvas context to the emulator later, fixing this ensures consistency if the library ever references the canvas by ID under the hood.

Check if the Emulator Requires the Canvas to Be in the DOM

Your first hypothesis hits on a common quirk of older JS emulators: some libraries expect the target canvas to exist in the DOM tree (even if it's hidden). The canvas you created is only used as a texture source for Three.js, so it's not attached to the page. Try adding it to the DOM and hiding it:

// After creating screenCanvas
screenCanvas.style.position = 'fixed';
screenCanvas.style.top = '-9999px';
screenCanvas.style.left = '-9999px';
document.body.appendChild(screenCanvas);

This tricks the emulator into thinking the canvas is part of the page without it being visible to users.

Force CanvasTexture Updates

While Three.js's CanvasTexture is supposed to auto-update when the canvas content changes, external libraries like the GameBoy emulator might modify the canvas in a way that doesn't trigger Three.js's internal checks. You need to manually flag the texture for update after each emulator frame.

First, store the texture reference when you create it (right now you're just pushing the material to the screen array):

// Declare this array at the top of your code
const screenTextures = [];

// Inside your loop where you create tex2
let tex2 = new THREE.CanvasTexture(x2);
screenTextures.push(tex2);
screen.push(new THREE.MeshBasicMaterial({ map: tex2, transparent:true, opacity:0.3 }))

Then, find where the emulator renders frames (look for a requestAnimationFrame loop or setInterval in the jsgameboy code) and add:

// After the emulator draws a frame
screenTextures.forEach(texture => texture.needsUpdate = true);

If you can't modify the emulator code directly, set up your own interval to update the texture periodically:

setInterval(() => {
  screenTextures.forEach(texture => texture.needsUpdate = true);
}, 16); // Matches ~60fps

Simplify Context Management

You're calling screenCanvas.getContext("2d") multiple times—this can sometimes lead to unexpected behavior. Store the context in a variable once and reuse it:

// When creating screenCanvas
const screenCtx = x2.getContext("2d");
// ... your existing fillStyle/fillRect code ...
gb.displaycanvas = screenCtx;
screenCtx.scale(2, 2);

Debugging Step: Verify Canvas Content

To narrow down the issue, add a test draw to your canvas right after initializing the emulator:

gb = new GameBoy(arraybuffer);
gb.displaycanvas = screenCtx;
screenCtx.scale(2,2);
// Test draw: fill a red square
screenCtx.fillStyle = 'red';
screenCtx.fillRect(0, 0, 50, 50);

If you see the red square on your Three.js plane, that means Three.js is working correctly, and the problem is that the emulator isn't actually drawing to the canvas. In that case, double-check that the emulator's displaycanvas property is set correctly, and that you're initializing it with a valid ROM arraybuffer.


内容的提问来源于stack exchange,提问作者Strum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:37:39