mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 03:09:57 +00:00
perf(highway_3d): forceSinglePass on transparent DoubleSide quads
The retrace after the label-swap fix showed getParameters unchanged (~2.5s / ~4% throttled main thread) — the real driver is Three r158+'s transparent-DoubleSide two-pass path: renderBufferDirect renders such objects back side then front side, setting material.needsUpdate BOTH times, i.e. a full getParameters/program-cache lookup twice per object per frame, plus double draw calls. (Found by reading the two-pass branch in the vendored three.module.min.js right next to the getParameters call site.) All 18 transparent DoubleSide materials in this renderer are flat unlit quads — technique markers, sustain rails, chord frames, lane planes, halo bars — where the two-pass self-occlusion ordering buys nothing. Declare forceSinglePass: true on all of them. Also corrects the _setLabelMap comment's churn attribution (that fix removes the label-swap contribution; this one removes the dominant source). Plugin 3.31.1 -> 3.31.2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
59aa70ce5a
commit
95cb51b2ad
@@ -5278,7 +5278,17 @@
|
||||
// appearing on top without depthTest.
|
||||
depthTest: false,
|
||||
depthWrite: false,
|
||||
side: T.DoubleSide,
|
||||
// forceSinglePass accompanies EVERY transparent DoubleSide
|
||||
// material in this file: without it, Three r158+ renders
|
||||
// each such object in TWO passes (back side then front),
|
||||
// setting material.needsUpdate on both — which forces a
|
||||
// full getParameters/program-cache lookup per object per
|
||||
// frame (profiled at ~4% of throttled main-thread time)
|
||||
// and doubles the draw calls. The two-pass path exists to
|
||||
// fix self-occlusion sorting on closed transparent meshes;
|
||||
// all our DoubleSide materials are flat unlit quads
|
||||
// (labels, rails, frames, lanes) where it buys nothing.
|
||||
side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
sm.userData.h3dTechMeshMat = base;
|
||||
}
|
||||
@@ -6660,7 +6670,7 @@
|
||||
depthWrite: false,
|
||||
depthTest: true,
|
||||
blending: T.AdditiveBlending,
|
||||
side: T.DoubleSide,
|
||||
side: T.DoubleSide, forceSinglePass: true,
|
||||
fog: true,
|
||||
}));
|
||||
mAccentHaloNear = mkAccentHaloMats(ACCENT_HALO_OP_NEAR);
|
||||
@@ -6720,7 +6730,7 @@
|
||||
new T.MeshBasicMaterial({
|
||||
vertexColors: true,
|
||||
transparent: true, opacity: 1.0, depthWrite: false,
|
||||
blending: T.AdditiveBlending, side: T.DoubleSide, fog: false,
|
||||
blending: T.AdditiveBlending, side: T.DoubleSide, forceSinglePass: true, fog: false,
|
||||
}),
|
||||
));
|
||||
// Notedetect feedback outline (issue #9): hot magenta-red (0xff0066, hue
|
||||
@@ -6860,7 +6870,7 @@
|
||||
emissiveIntensity: 0.9,
|
||||
transparent: true,
|
||||
opacity: 0.85,
|
||||
side: T.DoubleSide,
|
||||
side: T.DoubleSide, forceSinglePass: true,
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
});
|
||||
@@ -6887,7 +6897,7 @@
|
||||
color: CHORD_BOX_TEAL_HEX,
|
||||
transparent: true, opacity: 0.85,
|
||||
depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
pSusRail = pool(noteG, () => {
|
||||
const m = new T.Mesh(gSusRail, mSusRailBase.clone());
|
||||
@@ -6908,7 +6918,7 @@
|
||||
transparent: true, opacity: 0.55,
|
||||
blending: T.AdditiveBlending,
|
||||
depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
pSusRailBloom = pool(noteG, () => {
|
||||
const m = new T.Mesh(gSusRailBloom, mSusRailBloomBase.clone());
|
||||
@@ -6922,7 +6932,7 @@
|
||||
gTechPlane = new T.PlaneGeometry(1, 1);
|
||||
pTechPlane = pool(noteG, () => {
|
||||
const m = new T.Mesh(gTechPlane, new T.MeshBasicMaterial({
|
||||
transparent: true, depthTest: false, depthWrite: false, side: T.DoubleSide,
|
||||
transparent: true, depthTest: false, depthWrite: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
}));
|
||||
m.renderOrder = 1000;
|
||||
return m;
|
||||
@@ -6976,7 +6986,7 @@
|
||||
uniforms: { map: { value: spriteMat.map } },
|
||||
vertexShader: _imTechVert,
|
||||
fragmentShader: _imTechFrag,
|
||||
transparent: true, depthTest: false, depthWrite: false, side: T.DoubleSide,
|
||||
transparent: true, depthTest: false, depthWrite: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
const im = new T.InstancedMesh(geo, mat, IM_TECH_CAP);
|
||||
im.instanceMatrix.setUsage(T.DynamicDrawUsage);
|
||||
@@ -7089,7 +7099,7 @@
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
fog: false,
|
||||
side: T.DoubleSide,
|
||||
side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
pChordBox = pool(noteG, () => new T.Mesh(
|
||||
@@ -7101,7 +7111,7 @@
|
||||
depthWrite: false,
|
||||
depthTest: false,
|
||||
fog: false,
|
||||
side: T.DoubleSide,
|
||||
side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
|
||||
@@ -7184,7 +7194,7 @@
|
||||
_imPMXFillMat = new T.ShaderMaterial({
|
||||
vertexShader: _imFillVert, fragmentShader: _imFillFrag,
|
||||
transparent: true, depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
imPMXFill = new T.InstancedMesh(gPMXFill, _imPMXFillMat, IM_STRUM_CAP);
|
||||
imPMXFill.instanceMatrix.setUsage(T.DynamicDrawUsage);
|
||||
@@ -7264,7 +7274,7 @@
|
||||
_imFHXFillMat = new T.ShaderMaterial({
|
||||
vertexShader: _imFillVert, fragmentShader: _imFillFrag,
|
||||
transparent: true, depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
imFHXFill = new T.InstancedMesh(gFHXFill, _imFHXFillMat, IM_STRUM_CAP);
|
||||
imFHXFill.instanceMatrix.setUsage(T.DynamicDrawUsage);
|
||||
@@ -7345,7 +7355,7 @@
|
||||
_imPMXLinesMat = new T.ShaderMaterial({
|
||||
vertexShader: _imLinesVert, fragmentShader: _imLinesFrag,
|
||||
transparent: true, depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
imPMXLines = new T.InstancedMesh(gPMXLines, _imPMXLinesMat, IM_STRUM_CAP);
|
||||
imPMXLines.instanceMatrix.setUsage(T.DynamicDrawUsage);
|
||||
@@ -7427,7 +7437,7 @@
|
||||
_imFHXLinesMat = new T.ShaderMaterial({
|
||||
vertexShader: _imLinesVert, fragmentShader: _imLinesFrag,
|
||||
transparent: true, depthTest: false, depthWrite: false,
|
||||
fog: false, side: T.DoubleSide,
|
||||
fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
});
|
||||
imFHXLines = new T.InstancedMesh(gFHXLines, _imFHXLinesMat, IM_STRUM_CAP);
|
||||
imFHXLines.instanceMatrix.setUsage(T.DynamicDrawUsage);
|
||||
@@ -7449,28 +7459,28 @@
|
||||
gPMXFill,
|
||||
new T.MeshBasicMaterial({
|
||||
color: 0x000000, transparent: true, opacity: 1,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
pFHXFill = pool(noteG, () => new T.Mesh(
|
||||
gFHXFill,
|
||||
new T.MeshBasicMaterial({
|
||||
color: 0x000000, transparent: true, opacity: 1,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
pMuteXLines = pool(noteG, () => new T.Mesh(
|
||||
gPMXLines,
|
||||
new T.MeshBasicMaterial({
|
||||
color: 0xffffff, transparent: true, opacity: 1,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
pFHXLines = pool(noteG, () => new T.Mesh(
|
||||
gFHXLines,
|
||||
new T.MeshBasicMaterial({
|
||||
color: 0xffffff, transparent: true, opacity: 1,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide,
|
||||
depthWrite: false, depthTest: false, fog: false, side: T.DoubleSide, forceSinglePass: true,
|
||||
}),
|
||||
));
|
||||
|
||||
@@ -9935,12 +9945,14 @@
|
||||
// Swap a pooled label sprite's cached texture WITHOUT recompiling.
|
||||
// Setting material.needsUpdate bumps material.version, which forces
|
||||
// Three.js through getParameters/getProgramCacheKey on the next
|
||||
// render — profiled at ~4% of throttled main-thread time from the
|
||||
// per-frame label map swaps in dense charts. Swapping one non-null
|
||||
// texture for another does NOT change the compiled program (the
|
||||
// USE_MAP define is unchanged); only a null <-> non-null transition
|
||||
// does, and pooled label sprites are constructed with a non-null
|
||||
// map, so in practice this never recompiles.
|
||||
// render. Swapping one non-null texture for another does NOT change
|
||||
// the compiled program (the USE_MAP define is unchanged); only a
|
||||
// null <-> non-null transition does, and pooled label sprites are
|
||||
// constructed with a non-null map, so in practice this never
|
||||
// recompiles. (Note: the DOMINANT getParameters churn turned out to
|
||||
// be Three's transparent-DoubleSide two-pass path — see the
|
||||
// forceSinglePass comment in _spriteMat2MeshMat — this helper
|
||||
// removes the label-swap contribution on top of that.)
|
||||
function _setLabelMap(sprite, srcMat) {
|
||||
const m = sprite.material;
|
||||
if (m.map === srcMat.map) return;
|
||||
|
||||
Reference in New Issue
Block a user