title category import { OrbitControl } from "@oasis-engine/controls" ; import * as dat from "dat.gui" ; import { AmbientLight , AnimationClip , Animator , AssetType , BackgroundMode , BoundingBox , Camera , Color , DirectLight , Entity , GLTFResource , Logger , Material , MeshRenderer , PBRBaseMaterial , PBRMaterial , PBRSpecularMaterial , PrimitiveMesh , Renderer , Scene , SkinnedMeshRenderer , SkyBoxMaterial , Texture2D , UnlitMaterial , Vector3 , WebGLEngine } from "oasis-engine" ; Logger . enable ( ) ; const envList = { sunset : "https://gw.alipayobjects.com/os/bmw-prod/34986a5b-fa16-40f1-83c8-1885efe855d2.bin" , pisa : "https://gw.alipayobjects.com/os/bmw-prod/258a783d-0673-4b47-907a-da17b882feee.bin" , foot : "https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin" } ; class Oasis { static guiToColor ( gui , color ) { color . setValue ( gui [ 0 ] / 255 , gui [ 1 ] / 255 , gui [ 2 ] / 255 , color . a ) ; } static colorToGui ( color = new Color ( 1 , 1 , 1 ) ) { const v = [ ] ; v [ 0 ] = color . r * 255 ; v [ 1 ] = color . g * 255 ; v [ 2 ] = color . b * 255 ; return v ; } textures : Record < string , Texture2D > = { } ; env : Record < string , AmbientLight > = { } ; engine : WebGLEngine = new WebGLEngine ( "canvas" ) ; scene : Scene = this . engine . sceneManager . activeScene ; skyMaterial : SkyBoxMaterial = new SkyBoxMaterial ( this . engine ) ; rootEntity : Entity = this . scene . createRootEntity ( "root" ) ; cameraEntity : Entity = this . rootEntity . createChild ( "camera" ) ; gltfRootEntity : Entity = this . rootEntity . createChild ( "gltf" ) ; lightEntity1 : Entity = this . rootEntity . createChild ( "direct_light1" ) ; lightEntity2 : Entity = this . rootEntity . createChild ( "direct_light2" ) ; camera : Camera = this . cameraEntity . addComponent ( Camera ) ; controler : OrbitControl = this . cameraEntity . addComponent ( OrbitControl ) ; light1 : DirectLight = this . lightEntity1 . addComponent ( DirectLight ) ; light2 : DirectLight = this . lightEntity2 . addComponent ( DirectLight ) ; gui = new dat . GUI ( ) ; materialFolder = null ; animationFolder = null ; state = { background : false , env : "sunset" , envIntensity : 1 , addLights : true , lightColor : Oasis . colorToGui ( new Color ( 1 , 1 , 1 ) ) , lightIntensity : 0.8 , defaultGLTF : "fox" , gltfList : { "2CylinderEngine" : "https://gw.alipayobjects.com/os/bmw-prod/48a1e8b3-06b4-4269-807d-79274e58283a.glb" , alphaBlendModeTest : "https://gw.alipayobjects.com/os/bmw-prod/d099b30b-59a3-42e4-99eb-b158afa8e65d.glb" , animatedCube : "https://gw.alipayobjects.com/os/bmw-prod/8cc524dd-2481-438d-8374-3c933adea3b6.gltf" , antiqueCamera : "https://gw.alipayobjects.com/os/bmw-prod/93196534-bab3-4559-ae9f-bcb3e36a6419.glb" , avocado : "https://gw.alipayobjects.com/os/bmw-prod/0f978c4d-1cd6-4cec-9a4c-b58c8186e063.glb" , avocado_draco : "https://gw.alipayobjects.com/os/bmw-prod/b3b73614-cf06-4f41-940d-c1bc04cf6410.gltf" , avocado_specular : "https://gw.alipayobjects.com/os/bmw-prod/3cf50452-0015-461e-a172-7ea1f8135e53.gltf" , avocado_quantized : "https://gw.alipayobjects.com/os/bmw-prod/6aff5409-8e82-4e77-a6ac-55b6adfd0cf5.gltf" , barramundiFish : "https://gw.alipayobjects.com/os/bmw-prod/79d7935c-404b-4d8d-9ad3-5f8c273f0e4a.glb" , boomBox : "https://gw.alipayobjects.com/os/bmw-prod/2e98b1c0-18e8-45d0-b54e-dcad6ef05e22.glb" , boomBoxWithAxes : "https://gw.alipayobjects.com/os/bmw-prod/96e1b8b2-9be6-4b64-98ea-8c008c6dc422.gltf" , boxVertexColors : "https://gw.alipayobjects.com/os/bmw-prod/6cff6fcb-5191-465e-9a38-dee42a07cc65.glb" , brianStem : "https://gw.alipayobjects.com/os/bmw-prod/e3b37dd9-9407-4b5c-91b3-c5880d081329.glb" , buggy : "https://gw.alipayobjects.com/os/bmw-prod/d6916a14-b004-42d5-86dd-d8520b719288.glb" , cesiumMan : "https://gw.alipayobjects.com/os/bmw-prod/3a7d9597-7354-4bef-b314-b84509bef9b6.glb" , cesiumMilkTruck : "https://gw.alipayobjects.com/os/bmw-prod/7701125a-7d0d-4281-a7d8-7f0dfc8d0792.glb" , corset : "https://gw.alipayobjects.com/os/bmw-prod/3deaa5a4-5b2a-4a0d-8512-a8c4377a08ff.glb" , DamagedHelmet : "https://gw.alipayobjects.com/os/bmw-prod/a1da72a4-023e-4bb1-9629-0f4b0f6b6fc4.glb" , Duck : "https://gw.alipayobjects.com/os/bmw-prod/6cb8f543-285c-491a-8cfd-57a1160dc9ab.glb" , environmentTest : "https://gw.alipayobjects.com/os/bmw-prod/7c7b887c-05d6-43dd-b354-216e738e81ed.gltf" , flightHelmet : "https://gw.alipayobjects.com/os/bmw-prod/d6dbf161-48e2-4e6d-bbca-c481ed9f1a2d.gltf" , fox : "https://gw.alipayobjects.com/os/bmw-prod/f40ef8dd-4c94-41d4-8fac-c1d2301b6e47.glb" , animationInterpolationTest : "https://gw.alipayobjects.com/os/bmw-prod/4f410ef2-20b4-494d-85f1-a806c5070bfb.glb" , lantern : "https://gw.alipayobjects.com/os/bmw-prod/9557420a-c622-4e9c-bb46-f7af8b19d7de.glb" , materialsVariantsShoe : "https://gw.alipayobjects.com/os/bmw-prod/b1a414bb-61ea-4667-94d2-ef6cf179ac0d.glb" , metalRoughSpheres : "https://gw.alipayobjects.com/os/bmw-prod/67b39ede-1c82-4321-8457-0ad83ca9413a.glb" , normalTangentTest : "https://gw.alipayobjects.com/os/bmw-prod/4bb1a66c-55e3-4898-97d7-a9cc0f239686.glb" , normalTangentMirrorTest : "https://gw.alipayobjects.com/os/bmw-prod/8335f555-2061-47f5-9252-366c6ebf882a.glb" , orientationTest : "https://gw.alipayobjects.com/os/bmw-prod/16cdf390-ac42-411c-9d2b-8e112dfd723b.glb" , sparseTest : "https://gw.alipayobjects.com/os/bmw-prod/f00de659-53ea-49d1-8f2c-d0a412542b80.gltf" , specGlossVsMetalRough : "https://gw.alipayobjects.com/os/bmw-prod/4643bd7b-f988-4144-8245-4a390023d92d.glb" , sponza : "https://gw.alipayobjects.com/os/bmw-prod/ca50859b-d736-4a3e-9fc3-241b0bd2afef.gltf" , suzanne : "https://gw.alipayobjects.com/os/bmw-prod/3869e495-2e04-4e80-9d22-13b37116379a.gltf" , sheenChair : "https://gw.alipayobjects.com/os/bmw-prod/34847225-bc1b-4bef-9cb9-6b9711ca2f8c.glb" , sheenCloth : "https://gw.alipayobjects.com/os/bmw-prod/4529d2e8-22a8-47af-9b38-8eaff835f6bf.gltf" , textureCoordinateTest : "https://gw.alipayobjects.com/os/bmw-prod/5fd23201-51dd-4eea-92d3-c4a72ecc1f2b.glb" , textureEncodingTest : "https://gw.alipayobjects.com/os/bmw-prod/b8795e57-3c2c-4412-b4f0-7ffa796e4917.glb" , textureSettingTest : "https://gw.alipayobjects.com/os/bmw-prod/a4b26d58-bd49-4051-8f05-0fe8b532e716.glb" , textureTransformMultiTest : "https://gw.alipayobjects.com/os/bmw-prod/8fa18786-5188-4c14-94d7-77bf6b8483f9.glb" , textureTransform : "https://gw.alipayobjects.com/os/bmw-prod/6c59d5d0-2e2e-4933-a737-006d431977fd.gltf" , toyCar : "https://gw.alipayobjects.com/os/bmw-prod/8138b7d7-45aa-494a-8aea-0c67598b96d2.glb" , transmissionTest : "https://gw.alipayobjects.com/os/bmw-prod/1dd51fe8-bdd3-42e4-99be-53de5dc106b8.glb" , unlitTest : "https://gw.alipayobjects.com/os/bmw-prod/06a855be-ac8c-4705-b5d7-659b8b391189.glb" , vc : "https://gw.alipayobjects.com/os/bmw-prod/b71c4212-25fb-41bb-af88-d79ce6d3cc58.glb" , vertexColorTest : "https://gw.alipayobjects.com/os/bmw-prod/8fc70cc6-66d8-43c8-b460-f7d2aaa9edcf.glb" , waterBottle : "https://gw.alipayobjects.com/os/bmw-prod/0f403530-96f5-455a-8a39-b31ac68b6ed5.glb" } } ; _materials : Material [ ] = [ ] ; _boundingBox : BoundingBox = new BoundingBox ( ) ; _center : Vector3 = new Vector3 ( ) ; _extent : Vector3 = new Vector3 ( ) ; constructor ( ) { this . initResources ( ) . then ( ( ) => { this . initScene ( ) ; this . addGLTFList ( ) ; this . addSceneGUI ( ) ; } ) ; } initResources ( ) { const names = Object . keys ( envList ) ; return new Promise ( ( resolve ) => { this . engine . resourceManager . load ( names . map ( ( name ) => { return { type : AssetType . Env , url : envList [ name ] } ; } ) ) . then ( ( envs ) => { envs . forEach ( ( env , index ) => { const name = names [ index ] ; this . env [ name ] = env ; if ( name === this . state . env ) { this . scene . ambientLight = env ; this . skyMaterial . textureCubeMap = env . specularTexture ; this . skyMaterial . textureDecodeRGBM = true ; } } ) ; resolve ( true ) ; } ) ; } ) ; } initScene ( ) { this . engine . canvas . resizeByClientSize ( ) ; this . controler . minDistance = 0 ; if ( this . state . background ) { this . scene . background . mode = BackgroundMode . Sky ; } if ( ! this . state . addLights ) { this . light1 . enabled = this . light2 . enabled = false ; } this . light1 . intensity = this . light2 . intensity = this . state . lightIntensity ; this . lightEntity1 . transform . setRotation ( 30 , 0 , 0 ) ; this . lightEntity2 . transform . setRotation ( - 30 , 180 , 0 ) ; this . scene . ambientLight . specularIntensity = this . state . envIntensity ; this . scene . background . sky . material = this . skyMaterial ; this . scene . background . sky . mesh = PrimitiveMesh . createCuboid ( this . engine , 1 , 1 , 1 ) ; this . engine . run ( ) ; } addGLTFList ( ) { this . loadGLTF ( this . state . gltfList [ this . state . defaultGLTF ] ) ; this . gui . add ( this . state , "defaultGLTF" , Object . keys ( this . state . gltfList ) ) . name ( "GLTF List" ) . onChange ( ( v ) => { this . loadGLTF ( this . state . gltfList [ v ] ) ; } ) ; } addSceneGUI ( ) { const { gui } = this ; const dispFolder = gui . addFolder ( "Scene" ) ; dispFolder . add ( this . state , "background" ) . onChange ( ( v ) => { if ( v ) { this . scene . background . mode = BackgroundMode . Sky ; } else { this . scene . background . mode = BackgroundMode . SolidColor ; } } ) ; const lightFolder = gui . addFolder ( "Lighting" ) ; lightFolder . add ( this . state , "env" , [ ... Object . keys ( this . env ) ] ) . name ( "IBL" ) . onChange ( ( v ) => { this . scene . ambientLight = this . env [ v ] ; this . skyMaterial . textureCubeMap = this . env [ v ] . specularTexture ; } ) ; lightFolder . add ( this . state , "addLights" ) . onChange ( ( v ) => { this . light1 . enabled = this . light2 . enabled = v ; } ) . name ( "直接光" ) ; lightFolder . addColor ( this . state , "lightColor" ) . onChange ( ( v ) => { Oasis . guiToColor ( v , this . light1 . color ) ; Oasis . guiToColor ( v , this . light2 . color ) ; } ) ; lightFolder . add ( this . state , "lightIntensity" , 0 , 2 ) . onChange ( ( v ) => { this . light1 . intensity = this . light2 . intensity = v ; } ) . name ( "直接光强度" ) ; } setCenter ( renderers ) { const boundingBox = this . _boundingBox ; const center = this . _center ; const extent = this . _extent ; boundingBox . min . setValue ( 0 , 0 , 0 ) ; boundingBox . max . setValue ( 0 , 0 , 0 ) ; renderers . forEach ( ( renderer ) => { BoundingBox . merge ( renderer . bounds , boundingBox , boundingBox ) ; } ) ; boundingBox . getExtent ( extent ) ; const size = extent . length ( ) ; boundingBox . getCenter ( center ) ; this . controler . target . setValue ( center . x , center . y , center . z ) ; this . cameraEntity . transform . setPosition ( center . x , center . y , size * 3 ) ; this . camera . farClipPlane = size * 12 ; if ( this . camera . nearClipPlane > size ) { this . camera . nearClipPlane = size / 10 ; } else { this . camera . nearClipPlane = 0.1 ; } this . controler . maxDistance = size * 10 ; } loadGLTF ( url ) { this . destroyGLTF ( ) ; const isGLB = /.glb$/ . test ( url ) ; this . engine . resourceManager . load < GLTFResource > ( { type : AssetType . Prefab , url : `${ url }#${ Math . random ( ) }.${ isGLB ? "glb" : "gltf" }` } ) . then ( ( asset ) => { const { defaultSceneRoot , materials , animations } = asset ; console . log ( asset ) ; this . gltfRootEntity = defaultSceneRoot ; this . rootEntity . addChild ( defaultSceneRoot ) ; const meshRenderers = [ ] ; const skinnedMeshRenderers = [ ] ; defaultSceneRoot . getComponentsIncludeChildren ( MeshRenderer , meshRenderers ) ; defaultSceneRoot . getComponentsIncludeChildren ( SkinnedMeshRenderer , skinnedMeshRenderers ) ; this . setCenter ( meshRenderers . concat ( skinnedMeshRenderers ) ) ; this . loadMaterialGUI ( materials ) ; this . loadAnimationGUI ( animations ) ; } ) . catch ( ( e ) => { console . error ( e ) ; } ) ; } destroyGLTF ( ) { this . gltfRootEntity . destroy ( ) ; } loadMaterialGUI ( materials ? ) { const { gui } = this ; if ( this . materialFolder ) { gui . removeFolder ( this . materialFolder ) ; this . materialFolder = null ; } if ( ! materials ) { materials = this . _materials ; } this . _materials = materials ; if ( ! materials . length ) return ; const folder = ( this . materialFolder = gui . addFolder ( "Material" ) ) ; const folderName = { } ; materials . forEach ( ( material ) => { if ( ! ( material instanceof PBRBaseMaterial ) && ! ( material instanceof UnlitMaterial ) ) return ; if ( ! material . name ) { material . name = "default" ; } const state = { opacity : material . baseColor . a , baseColor : Oasis . colorToGui ( material . baseColor ) , emissiveColor : Oasis . colorToGui ( ( material as PBRBaseMaterial ) . emissiveColor ) , specularColor : Oasis . colorToGui ( ( material as PBRSpecularMaterial ) . specularColor ) , baseTexture : material . baseTexture ? "origin" : "" , roughnessMetallicTexture : ( material as PBRMaterial ) . roughnessMetallicTexture ? "origin" : "" , normalTexture : ( material as PBRBaseMaterial ) . normalTexture ? "origin" : "" , emissiveTexture : ( material as PBRBaseMaterial ) . emissiveTexture ? "origin" : "" , occlusionTexture : ( material as PBRBaseMaterial ) . occlusionTexture ? "origin" : "" , specularGlossinessTexture : ( material as PBRSpecularMaterial ) . specularGlossinessTexture ? "origin" : "" } ; const originTexture = { baseTexture : material . baseTexture , roughnessMetallicTexture : ( material as PBRMaterial ) . roughnessMetallicTexture , normalTexture : ( material as PBRBaseMaterial ) . normalTexture , emissiveTexture : ( material as PBRBaseMaterial ) . emissiveTexture , occlusionTexture : ( material as PBRBaseMaterial ) . occlusionTexture , specularGlossinessTexture : ( material as PBRSpecularMaterial ) . specularGlossinessTexture } ; const f = folder . addFolder ( folderName [ material . name ] ? `${ material . name }_${ folderName [ material . name ] + 1 }` : material . name ) ; folderName [ material . name ] = folderName [ material . name ] == null ? 1 : folderName [ material . name ] + 1 ; if ( material instanceof PBRMaterial ) { const mode1 = f . addFolder ( "金属模式" ) ; mode1 . add ( material , "metallic" , 0 , 1 ) . step ( 0.01 ) ; mode1 . add ( material , "roughness" , 0 , 1 ) . step ( 0.01 ) ; mode1 . add ( state , "roughnessMetallicTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . roughnessMetallicTexture = v === "None" ? null : this . textures [ v ] || originTexture . roughnessMetallicTexture ; } ) ; mode1 . open ( ) ; } else if ( material instanceof PBRSpecularMaterial ) { const mode2 = f . addFolder ( "高光模式" ) ; mode2 . add ( material , "glossiness" , 0 , 1 ) . step ( 0.01 ) ; mode2 . addColor ( state , "specularColor" ) . onChange ( ( v ) => { Oasis . guiToColor ( v , material . specularColor ) ; } ) ; mode2 . add ( state , "specularGlossinessTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . specularGlossinessTexture = v === "None" ? null : this . textures [ v ] || originTexture . specularGlossinessTexture ; } ) ; mode2 . open ( ) ; } else if ( material instanceof UnlitMaterial ) { f . add ( state , "baseTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . baseTexture = v === "None" ? null : this . textures [ v ] || originTexture . baseTexture ; } ) ; f . addColor ( state , "baseColor" ) . onChange ( ( v ) => { Oasis . guiToColor ( v , material . baseColor ) ; } ) ; } if ( ! ( material instanceof UnlitMaterial ) ) { const common = f . addFolder ( "通用" ) ; common . add ( state , "opacity" , 0 , 1 ) . step ( 0.01 ) . onChange ( ( v ) => { material . baseColor . a = v ; } ) ; common . add ( material , "isTransparent" ) ; common . add ( material , "alphaCutoff" , 0 , 1 ) . step ( 0.01 ) ; common . addColor ( state , "baseColor" ) . onChange ( ( v ) => { Oasis . guiToColor ( v , material . baseColor ) ; } ) ; common . addColor ( state , "emissiveColor" ) . onChange ( ( v ) => { Oasis . guiToColor ( v , material . emissiveColor ) ; } ) ; common . add ( state , "baseTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . baseTexture = v === "None" ? null : this . textures [ v ] || originTexture . baseTexture ; } ) ; common . add ( state , "normalTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . normalTexture = v === "None" ? null : this . textures [ v ] || originTexture . normalTexture ; } ) ; common . add ( state , "emissiveTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . emissiveTexture = v === "None" ? null : this . textures [ v ] || originTexture . emissiveTexture ; } ) ; common . add ( state , "occlusionTexture" , [ "None" , "origin" , ... Object . keys ( this . textures ) ] ) . onChange ( ( v ) => { material . occlusionTexture = v === "None" ? null : this . textures [ v ] || originTexture . occlusionTexture ; } ) ; common . open ( ) ; } } ) ; } loadAnimationGUI ( animations ) { if ( this . animationFolder ) { this . gui . removeFolder ( this . animationFolder ) ; this . animationFolder = null ; } if ( animations ?. length ) { this . animationFolder = this . gui . addFolder ( "Animation" ) ; this . animationFolder . open ( ) ; const animator = this . gltfRootEntity . getComponent ( Animator ) ; animator . play ( animations [ 0 ] . name ) ; const state = { animation : animations [ 0 ] . name } ; this . animationFolder . add ( state , "animation" , [ "None" , ... animations . map ( ( animation ) => animation . name ) ] ) . onChange ( ( name ) => { if ( name === "None" ) { animator . speed = 0 ; } else { animator . speed = 1 ; animator . play ( name ) ; } } ) ; } } } new Oasis ( ) ;