修复导览三维模型材质反光过强
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
cxk
2026-07-20 18:18:19 +08:00
parent 3cc0336806
commit 65ba9720f8
3 changed files with 157 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import { describe, expect, it } from 'vitest'
import * as THREE from 'three'
import {
applyGuideModelMaterialPolicy,
GUIDE_MODEL_MATERIAL_POLICY
} from '@/components/map/modelMaterialPolicy'
const meshWith = (material: THREE.Material) => new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
material
)
describe('guide GLB material policy', () => {
it('raises the roughness floor and limits environment reflection for opaque non-metal PBR materials', () => {
const root = new THREE.Group()
const wall = new THREE.MeshStandardMaterial({ roughness: 0.12, metalness: 0.05, envMapIntensity: 1 })
root.add(meshWith(wall))
expect(applyGuideModelMaterialPolicy(root)).toEqual({
pbrMaterialCount: 1,
nonMetalMaterialCount: 1,
protectedMaterialCount: 0
})
expect(wall.roughness).toBe(GUIDE_MODEL_MATERIAL_POLICY.nonMetalRoughnessFloor)
expect(wall.envMapIntensity).toBe(GUIDE_MODEL_MATERIAL_POLICY.envMapIntensity)
})
it('also applies the roughness floor after a non-metal roughness texture is sampled', () => {
const root = new THREE.Group()
const floor = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 })
floor.roughnessMap = new THREE.Texture()
root.add(meshWith(floor))
applyGuideModelMaterialPolicy(root)
const shader = { fragmentShader: '#include <roughnessmap_fragment>' }
floor.onBeforeCompile(shader as any, {} as any)
expect(shader.fragmentShader).toContain('roughnessFactor = max(roughnessFactor, 0.48);')
expect(floor.customProgramCacheKey()).toContain('guide-non-metal-roughness-floor')
})
it('caps imported specular extensions on opaque non-metal physical materials', () => {
const root = new THREE.Group()
const wall = new THREE.MeshPhysicalMaterial({ roughness: 0.55, metalness: 0, specularIntensity: 1 })
root.add(meshWith(wall))
applyGuideModelMaterialPolicy(root)
expect(wall.specularIntensity).toBe(GUIDE_MODEL_MATERIAL_POLICY.nonMetalSpecularIntensityCap)
})
it('keeps authored roughness on metal, transparent and glass materials while limiting environment reflection', () => {
const root = new THREE.Group()
const metal = new THREE.MeshStandardMaterial({ roughness: 0.08, metalness: 0.9, envMapIntensity: 1 })
const transparent = new THREE.MeshStandardMaterial({ roughness: 0.08, transparent: true, opacity: 0.4, envMapIntensity: 1 })
const glass = new THREE.MeshPhysicalMaterial({ roughness: 0.08, transmission: 0.9, envMapIntensity: 1, specularIntensity: 1 })
root.add(meshWith(metal), meshWith(transparent), meshWith(glass))
expect(applyGuideModelMaterialPolicy(root)).toEqual({
pbrMaterialCount: 3,
nonMetalMaterialCount: 0,
protectedMaterialCount: 3
})
expect([metal.roughness, transparent.roughness, glass.roughness]).toEqual([0.08, 0.08, 0.08])
expect(glass.specularIntensity).toBe(1)
expect([metal.envMapIntensity, transparent.envMapIntensity, glass.envMapIntensity])
.toEqual([0.42, 0.42, 0.42])
})
})