This commit is contained in:
@@ -92,6 +92,7 @@ import {
|
||||
type PoiDomLabelAnchor,
|
||||
type PoiDomLabelKind
|
||||
} from './poiDomLabels'
|
||||
import { applyGuideModelMaterialPolicy } from './modelMaterialPolicy'
|
||||
|
||||
type ViewMode = 'overview' | 'floor' | 'multi'
|
||||
type CameraPreset = 'top' | 'oblique'
|
||||
@@ -2923,6 +2924,8 @@ const loadModelWithFallback = async (
|
||||
}
|
||||
|
||||
const prepareModel = (model: THREE.Object3D) => {
|
||||
applyGuideModelMaterialPolicy(model)
|
||||
|
||||
model.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
child.castShadow = false
|
||||
|
||||
85
src/components/map/modelMaterialPolicy.ts
Normal file
85
src/components/map/modelMaterialPolicy.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import * as THREE from 'three'
|
||||
|
||||
export const GUIDE_MODEL_MATERIAL_POLICY = {
|
||||
envMapIntensity: 0.42,
|
||||
nonMetalRoughnessFloor: 0.48,
|
||||
nonMetalSpecularIntensityCap: 0.6,
|
||||
metalnessThreshold: 0.5,
|
||||
transparentOpacityThreshold: 0.99,
|
||||
transmissionThreshold: 0.01
|
||||
} as const
|
||||
|
||||
const isTransparentOrGlass = (material: THREE.MeshStandardMaterial) => {
|
||||
const physicalMaterial = material as THREE.MeshPhysicalMaterial
|
||||
return material.transparent
|
||||
|| material.opacity < GUIDE_MODEL_MATERIAL_POLICY.transparentOpacityThreshold
|
||||
|| physicalMaterial.transmission > GUIDE_MODEL_MATERIAL_POLICY.transmissionThreshold
|
||||
}
|
||||
|
||||
const MATERIAL_POLICY_KEY = '__guideModelMaterialPolicyApplied'
|
||||
|
||||
const applyNonMetalRoughnessFloor = (material: THREE.MeshStandardMaterial) => {
|
||||
if (material.roughness < GUIDE_MODEL_MATERIAL_POLICY.nonMetalRoughnessFloor) {
|
||||
material.roughness = GUIDE_MODEL_MATERIAL_POLICY.nonMetalRoughnessFloor
|
||||
}
|
||||
|
||||
// GLB roughness textures can still produce mirror-like texels when the
|
||||
// exported scalar factor is already 1. Clamp after Three.js samples that map.
|
||||
if (!material.roughnessMap || material.userData[MATERIAL_POLICY_KEY]) return
|
||||
|
||||
const originalOnBeforeCompile = material.onBeforeCompile
|
||||
const originalCacheKey = material.customProgramCacheKey
|
||||
material.onBeforeCompile = (shader, renderer) => {
|
||||
originalOnBeforeCompile(shader, renderer)
|
||||
shader.fragmentShader = shader.fragmentShader.replace(
|
||||
'#include <roughnessmap_fragment>',
|
||||
`#include <roughnessmap_fragment>\nroughnessFactor = max(roughnessFactor, ${GUIDE_MODEL_MATERIAL_POLICY.nonMetalRoughnessFloor.toFixed(2)});`
|
||||
)
|
||||
}
|
||||
material.customProgramCacheKey = () => `${originalCacheKey.call(material)}|guide-non-metal-roughness-floor`
|
||||
material.userData[MATERIAL_POLICY_KEY] = true
|
||||
material.needsUpdate = true
|
||||
}
|
||||
|
||||
const applyNonMetalSpecularCap = (material: THREE.MeshStandardMaterial) => {
|
||||
if (!(material instanceof THREE.MeshPhysicalMaterial)) return
|
||||
|
||||
material.specularIntensity = Math.min(
|
||||
material.specularIntensity,
|
||||
GUIDE_MODEL_MATERIAL_POLICY.nonMetalSpecularIntensityCap
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes imported GLB PBR factors at one rendering boundary. Textures,
|
||||
* alpha and deliberate metal/glass material classes remain authored by the model.
|
||||
*/
|
||||
export const applyGuideModelMaterialPolicy = (object: THREE.Object3D) => {
|
||||
let pbrMaterialCount = 0
|
||||
let nonMetalMaterialCount = 0
|
||||
let protectedMaterialCount = 0
|
||||
|
||||
object.traverse((child) => {
|
||||
if (!(child instanceof THREE.Mesh)) return
|
||||
|
||||
const materials = Array.isArray(child.material) ? child.material : [child.material]
|
||||
materials.forEach((material) => {
|
||||
if (!(material instanceof THREE.MeshStandardMaterial)) return
|
||||
|
||||
pbrMaterialCount += 1
|
||||
material.envMapIntensity = GUIDE_MODEL_MATERIAL_POLICY.envMapIntensity
|
||||
|
||||
const isMetal = material.metalness >= GUIDE_MODEL_MATERIAL_POLICY.metalnessThreshold
|
||||
if (isMetal || isTransparentOrGlass(material)) {
|
||||
protectedMaterialCount += 1
|
||||
return
|
||||
}
|
||||
|
||||
nonMetalMaterialCount += 1
|
||||
applyNonMetalRoughnessFloor(material)
|
||||
applyNonMetalSpecularCap(material)
|
||||
})
|
||||
})
|
||||
|
||||
return { pbrMaterialCount, nonMetalMaterialCount, protectedMaterialCount }
|
||||
}
|
||||
Reference in New Issue
Block a user