Fix: bind sampler uniforms to a 1x1 transparent texture — null samplers broke shader linking, so no ghosts rendered
This commit is contained in:
@@ -20,10 +20,20 @@ const objCache = new Map();
|
|||||||
const texLoader = new THREE.TextureLoader();
|
const texLoader = new THREE.TextureLoader();
|
||||||
const texCache = new Map();
|
const texCache = new Map();
|
||||||
|
|
||||||
|
/* A sampler2D uniform must ALWAYS be bound to a real texture: leaving it null makes
|
||||||
|
* the shader program fail to link on many GPUs, which would break every untextured
|
||||||
|
* ghost. This 1x1 fully-transparent pixel is the safe no-op binding. */
|
||||||
|
const EMPTY_TEX = (() => {
|
||||||
|
const t = new THREE.DataTexture(new Uint8Array([0, 0, 0, 0]), 1, 1, THREE.RGBAFormat);
|
||||||
|
t.needsUpdate = true;
|
||||||
|
return t;
|
||||||
|
})();
|
||||||
|
|
||||||
function loadTexture(url) {
|
function loadTexture(url) {
|
||||||
if (!url) return null;
|
if (!url) return null;
|
||||||
if (!texCache.has(url)) {
|
if (!texCache.has(url)) {
|
||||||
const t = texLoader.load(url);
|
const t = texLoader.load(url, undefined, undefined,
|
||||||
|
() => console.warn('texture failed to load:', url)); // keeps the ghost alive
|
||||||
t.colorSpace = THREE.SRGBColorSpace;
|
t.colorSpace = THREE.SRGBColorSpace;
|
||||||
texCache.set(url, t);
|
texCache.set(url, t);
|
||||||
}
|
}
|
||||||
@@ -41,8 +51,8 @@ function gradientMaterial(top, bottom, opacity, faceTex, torsoTex, bands) {
|
|||||||
uMinY: { value: 0 },
|
uMinY: { value: 0 },
|
||||||
uMaxY: { value: 1 },
|
uMaxY: { value: 1 },
|
||||||
uTime: { value: 0 },
|
uTime: { value: 0 },
|
||||||
faceMap: { value: faceTex || null },
|
faceMap: { value: faceTex || EMPTY_TEX },
|
||||||
torsoMap: { value: torsoTex || null },
|
torsoMap: { value: torsoTex || EMPTY_TEX },
|
||||||
hasFace: { value: faceTex ? 1 : 0 },
|
hasFace: { value: faceTex ? 1 : 0 },
|
||||||
hasTorso: { value: torsoTex ? 1 : 0 },
|
hasTorso: { value: torsoTex ? 1 : 0 },
|
||||||
// [centreY, halfHeight, halfWidth] in normalized model space
|
// [centreY, halfHeight, halfWidth] in normalized model space
|
||||||
@@ -136,7 +146,8 @@ function pickModel(manifest, ov) {
|
|||||||
|
|
||||||
export async function buildGhost(ghost, gradients, manifest, characters) {
|
export async function buildGhost(ghost, gradients, manifest, characters) {
|
||||||
const ov = resolveOverrides(ghost, characters);
|
const ov = resolveOverrides(ghost, characters);
|
||||||
const grad = gradients[ghost.color] || gradients.Blue;
|
const grad = (gradients && (gradients[ghost.color] || gradients.Blue))
|
||||||
|
|| { top: '#51eaf1', bottom: '#529eff' }; // survive a missing/!oddly-shaped gradient payload
|
||||||
const top = ov.topColor || grad.top;
|
const top = ov.topColor || grad.top;
|
||||||
const bottom = ov.bottomColor || grad.bottom;
|
const bottom = ov.bottomColor || grad.bottom;
|
||||||
const opacity = ov.opacity != null ? Number(ov.opacity) : 0.92;
|
const opacity = ov.opacity != null ? Number(ov.opacity) : 0.92;
|
||||||
|
|||||||
Reference in New Issue
Block a user