@@ -297,6 +297,30 @@ function restructureForVrm(json: any): void {
297297 }
298298}
299299
300+ /**
301+ * Tags every material as KHR_materials_unlit so VRM viewers render the avatar
302+ * with the flat / cartoon look DCL uses, instead of PBR metallic shading.
303+ * Matches the juanma reference, which also marks every material as unlit.
304+ */
305+ function applyUnlitMaterials ( json : any ) : void {
306+ if ( ! Array . isArray ( json . materials ) || json . materials . length === 0 ) return
307+
308+ if ( ! json . extensionsUsed ) json . extensionsUsed = [ ]
309+ if ( ! json . extensionsUsed . includes ( 'KHR_materials_unlit' ) ) {
310+ json . extensionsUsed . push ( 'KHR_materials_unlit' )
311+ }
312+
313+ for ( const mat of json . materials ) {
314+ if ( ! mat . extensions ) mat . extensions = { }
315+ if ( ! mat . extensions . KHR_materials_unlit ) mat . extensions . KHR_materials_unlit = { }
316+ // Unlit materials should not contribute metallic/roughness — zero them out.
317+ if ( mat . pbrMetallicRoughness ) {
318+ mat . pbrMetallicRoughness . metallicFactor = 0
319+ mat . pbrMetallicRoughness . roughnessFactor = 0.9
320+ }
321+ }
322+ }
323+
300324function injectVRMExtension ( json : any ) : void {
301325 const seenVrmBones = new Set < string > ( )
302326 const humanBones : Array < { bone : string ; node : number ; useDefaultValues : boolean } > = [ ]
@@ -481,6 +505,7 @@ export async function exportVRM(scene: Scene): Promise<Blob> {
481505 rebakeBindPose ( json , binChunk , snapshotByName , boneParentNameByName )
482506 mergeSkeletons ( json )
483507 restructureForVrm ( json )
508+ applyUnlitMaterials ( json )
484509 injectVRMExtension ( json )
485510
486511 return new Blob ( [ packGLB ( json , binChunk ) ] , { type : 'application/octet-stream' } )
0 commit comments