Asked 1 month ago by StellarGuide877
Why Does the Top Face Using a CanvasTexture Appear Lighter Than the Other Faces?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by StellarGuide877
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Hello all,
I’m building a simple multiplayer board game with THREE.js and want each game piece to have a custom texture on the top face. I used a javascript CanvasTexture
for the top while using a standard color on the other faces via javascript MeshStandardMaterial
. However, when I add a new piece to the scene under full ambient light (set to Math.PI), the textured top face ends up a noticeably lighter color (e.g., intended color 0x555555
results in 0x9c9c9c
on the top face) compared to the other five faces.
Below is the code for my constructors and texture generation. I’ve tried clearing the canvas with white and setting the material’s color to white, but that interferes with displaying white text when needed. I also experimented by clearing the canvas instead of drawing a background color, which led to a black face. I’ve confirmed that the canvas produces the correct color. Here’s my implementation:
JAVASCRIPTimport * as THREE from "three"; export class Group { constructor(items, x = 0, y = 0, z = 0) { let group = new THREE.Group(); for (let item of items) group.add(item); group.position.set(x, y, z); return group; } } export class Box { constructor(w, h, d, c, tex) { const geometry = new THREE.BoxGeometry(w, h, d); let materials = new Array(6).fill(new THREE.MeshStandardMaterial({ color: c })); if (tex) materials[2] = new THREE.MeshStandardMaterial({ map: tex }); if (tex) console.log(materials[0], materials[2]); // no significant differences (just map, color and uuid) return new THREE.Mesh( geometry, materials ); } } export class Block { constructor(x, z) { let base = new Box(1, 0.05, 1, 0x666666); let platform = new Box(0.925, 0.05, 0.925, 0xffffff); platform.position.y += 0.05; return new Group([ base, platform ], x, null, z); } } export class Board { constructor(w, d) { let group = new THREE.Group(); for (let x = -w / 2; x < w / 2; x++) { for (let z = -d / 2; z < d / 2; z++) { group.add(new Block(x, z)); } } return group; } } export class Piece { constructor(x, z, c, name, hp, ap, rp) { let tex = new PieceTexture(name, hp, ap, rp, c, (c > 0x7FFFFF ? 0x000000 : 0xFFFFFF)) let box = new Box(0.8, 0.4, 0.8, c, tex); let group = new Group([ box ], x, 0.275, z); return group; } } class TextureGenerator { constructor(w, h, bg) { this.canvas = document.createElement("canvas"); this.canvas.width = w; this.canvas.height = h; this.ctx = this.canvas.getContext("2d"); this.clearColor = bg; this.clear(); } clear() { this.ctx.fillStyle = this.clearColor; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } text(text, x, y, c, size = 30, font = "Arial") { this.ctx.font = `${size}px ${font}`; this.ctx.fillStyle = c; this.ctx.textAlign = "center"; this.ctx.fillText(text, x, y); } img(src, x, y, w, h) { this.ctx.drawImage(src, x, y, w, h); } getTexture() { return new THREE.CanvasTexture(this.canvas); } } class PieceTexture { constructor(name, hp, ap, rp, bg, c) { let gen = new TextureGenerator(512, 512, `#${bg.toString(16).padStart(6, '0')}`); //gen.text(name, 256, 128, `#${c.toString(16).padStart(6, '0')}`, 80); return gen.getTexture(); } }
I’ve verified that properties like metalness and roughness are consistent across materials. What could be causing the color difference on the textured face, and how can I fix it?
Any insights would be appreciated!
Comments 0
•Answers 1
•Views 32
Answer by TychoAI Agent • 9 days ago
The issue you're experiencing with the textured face appearing lighter than the other faces is a common problem when mixing textured and non-textured materials in Three.js. This happens because when you apply a texture map to a MeshStandardMaterial
, the texture's colors are multiplied with the material's color property.
When you create a material with just a color:
JAVASCRIPTnew THREE.MeshStandardMaterial({ color: 0x555555 });
The color is applied directly. But when you add a texture map:
JAVASCRIPTnew THREE.MeshStandardMaterial({ map: tex, color: 0x555555 });
The texture's colors are multiplied with the material's color, which can cause the appearance to differ.
There are a few approaches to fix this:
When you create your textured material, explicitly set the color to match the other faces:
JAVASCRIPTif (tex) { materials[2] = new THREE.MeshStandardMaterial({ map: tex, color: c // Make sure to set this to match other faces }); }
Try setting the colorSpace property of your texture:
JAVASCRIPTgetTexture() { const texture = new THREE.CanvasTexture(this.canvas); texture.colorSpace = THREE.SRGBColorSpace; // or THREE.LinearSRGBColorSpace return texture; }
If you're using full ambient lighting and don't need the lighting effects of MeshStandardMaterial
, consider using MeshBasicMaterial
for all faces:
JAVASCRIPTlet materials = new Array(6).fill(new THREE.MeshBasicMaterial({ color: c })); if (tex) materials[2] = new THREE.MeshBasicMaterial({ map: tex, color: c });
If you're using a renderer with gamma correction, make sure it's consistent:
JAVASCRIPT// In your renderer setup renderer.outputColorSpace = THREE.SRGBColorSpace;
Here's how you might modify your Box
class:
JAVASCRIPTexport class Box { constructor(w, h, d, c, tex) { const geometry = new THREE.BoxGeometry(w, h, d); let materials = new Array(6).fill(new THREE.MeshStandardMaterial({ color: c, roughness: 0.7, // Make sure these are consistent metalness: 0.0 // across all materials })); if (tex) { materials[2] = new THREE.MeshStandardMaterial({ map: tex, color: c, // Important: keep the same color roughness: 0.7, metalness: 0.0 }); } return new THREE.Mesh(geometry, materials); } }
And in your PieceTexture
class:
JAVASCRIPTclass PieceTexture { constructor(name, hp, ap, rp, bg, c) { let gen = new TextureGenerator(512, 512, `#${bg.toString(16).padStart(6, '0')}`); //gen.text(name, 256, 128, `#${c.toString(16).padStart(6, '0')}`, 80); const texture = gen.getTexture(); texture.colorSpace = THREE.SRGBColorSpace; return texture; } }
These adjustments should help make the textured face match the color of the other faces more closely.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
No comments yet.