美文网首页
[Three.js 代码组织] 资源加载器

[Three.js 代码组织] 资源加载器

作者: alue | 来源:发表于2023-08-02 20:42 被阅读0次

    如果每个文件都写一遍加载流程, 代码会随着文件数量线性增加. 这里用一个工具类来完成这个工作.

    首先将资源列表, 整理成一个规范的三元组列表文件,分别由资源名称、类型、路径构成:

    export default [  
        {        
            name: 'environmentMapTexture',  
            type: 'cubeTexture',  
            path:  
                [  
                    'textures/environmentMap/px.jpg',  
                    'textures/environmentMap/nx.jpg',  
                    'textures/environmentMap/py.jpg',  
                    'textures/environmentMap/ny.jpg',  
                    'textures/environmentMap/pz.jpg',  
                    'textures/environmentMap/nz.jpg'  
                ]    },  
        {  
            name: 'grassColorTexture',  
            type: 'texture',  
            path: 'textures/dirt/color.jpg'  
        },  
        {  
            name: 'grassNormalTexture',  
            type: 'texture',  
            path: 'textures/dirt/normal.jpg'  
        },  
        {  
            name: 'foxModel',  
            type: 'gltfModel',  
            path: 'models/Fox/glTF/Fox.gltf'  
        }  
    ]
    

    然后编写资源加载类如下:

    import * as THREE from 'three'  
    import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'  
    import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';  
    import EventEmitter from './EventEmitter.js'  
      
    export default class Resources extends EventEmitter  
    {  
        constructor(sources)  
        {  
            super()  
      
            this.sources = sources  
      
            this.items = {}  
            this.toLoad = this.sources.length  
            this.loaded = 0  
      
            this.setLoaders()  
            this.startLoading()  
        }  
      
        setLoaders()  
        {  
            this.loaders = {}  
            this.loaders.gltfLoader = new GLTFLoader()  
            this.loaders.textureLoader = new THREE.TextureLoader()  
            this.loaders.cubeTextureLoader = new THREE.CubeTextureLoader()  
            this.loaders.objLoader = new OBJLoader()  
        }  
      
        startLoading()  
        {  
            // Load each source  
            for(const source of this.sources)  
            {  
                if(source.type === 'gltfModel')  
                {  
                    this.loaders.gltfLoader.load(  
                        source.path,  
                        (file) =>  
                        {  
                            this.sourceLoaded(source, file)  
                        }  
                    )  
                }  
                else if(source.type === 'texture')  
                {  
                    this.loaders.textureLoader.load(  
                        source.path,  
                        (file) =>  
                        {  
                            this.sourceLoaded(source, file)  
                        }                )  
                }            else if(source.type === 'cubeTexture')  
                {                this.loaders.cubeTextureLoader.load(  
                        source.path,  
                        (file) =>  
                        {  
                            this.sourceLoaded(source, file)  
                        }  
                    )            }  
                else if(source.type==='obj')  
                {  
                    this.loaders.objLoader.load(  
                        source.path,  
                        (file) =>  
                        {  
                            this.sourceLoaded(source, file)  
                        }  
                    )  
                }  
            }  
        }  
      
        sourceLoaded(source, file)  
        {  
            this.items[source.name] = file  
      
            this.loaded++  
      
            if(this.loaded === this.toLoad)  
            {  
                this.trigger('ready')  
            }  
        }  
    }
    
    

    将需要用到的所有loader都集中在 setLoaders 方法内。通过 startLoading 来加载资源,资源加载完毕后,会向外抛出 ready 事件。

    调用资源对象时,可以监听 ready 事件,来完成资源对象类对象的新建。

    import Floor from './Floor.js'  
    import Fox from './Fox.js'
    // Wait for resources  
    this.resources.on('ready', () =>  
    {  
        // Setup  
        this.floor = new Floor()  
        this.fox = new Fox()  
    })
    
    

    资源对象类,可以直接调用 resources 中的材质对象

    // Floor.js
    import * as THREE from 'three'  
    import Experience from '../Experience.js'  
      
    export default class Floor  
    {  
        constructor()  
        {  
            this.experience = new Experience()  
            this.scene = this.experience.scene  
            this.resources = this.experience.resources  
      
            this.setGeometry()  
            this.setTextures()  
            this.setMaterial()  
            this.setMesh()  
        }  
      
        setGeometry()  
        {  
            this.geometry = new THREE.CircleGeometry(5, 64)  
        }  
      
        setTextures()  
        {  
            this.textures = {}  
      
            this.textures.color = this.resources.items.grassColorTexture  
            this.textures.color.encoding = THREE.sRGBEncoding  
            this.textures.color.repeat.set(1.5, 1.5)  
            this.textures.color.wrapS = THREE.RepeatWrapping  
            this.textures.color.wrapT = THREE.RepeatWrapping  
      
            this.textures.normal = this.resources.items.grassNormalTexture  
            this.textures.normal.repeat.set(1.5, 1.5)  
            this.textures.normal.wrapS = THREE.RepeatWrapping  
            this.textures.normal.wrapT = THREE.RepeatWrapping  
        }  
      
        setMaterial()  
        {  
            this.material = new THREE.MeshStandardMaterial({  
                map: this.textures.color,  
                normalMap: this.textures.normal  
            })  
        }  
      
        setMesh()  
        {  
            this.mesh = new THREE.Mesh(this.geometry, this.material)  
            this.mesh.rotation.x = - Math.PI * 0.5  
            this.mesh.receiveShadow = true  
            this.scene.add(this.mesh)  
        }  
    }
    
    

    直接调用模型资源

    // Fox.js
    
    import * as THREE from 'three'  
    import Experience from '../Experience.js'  
      
    export default class Fox  
    {  
        constructor()  
        {  
            this.experience = new Experience()  
            this.scene = this.experience.scene  
            this.resources = this.experience.resources  
            this.time = this.experience.time  
     
            // Resource  
            this.resource = this.resources.items.foxModel  
      
            this.setModel()  
            this.setAnimation()  
        }  
      
        setModel()  
        {  
            this.model = this.resource.scene  
            this.model.scale.set(0.02, 0.02, 0.02)  
            this.scene.add(this.model)  
      
            this.model.traverse((child) =>  
            {            if(child instanceof THREE.Mesh)  
                {  
                    child.castShadow = true  
                }  
            })  
        }  
      
        setAnimation()  
        {  
            this.animation = {}  
            // Mixer  
            this.animation.mixer = new THREE.AnimationMixer(this.model)  
            // Actions  
            this.animation.actions = {}  
            this.animation.actions.idle = this.animation.mixer.clipAction(this.resource.animations[0])  
            this.animation.actions.walking = this.animation.mixer.clipAction(this.resource.animations[1])  
            this.animation.actions.running = this.animation.mixer.clipAction(this.resource.animations[2])  
            this.animation.actions.current = this.animation.actions.idle  
            this.animation.actions.current.play()  
      
            // Play the action  
            this.animation.play = (name) =>  
            {            const newAction = this.animation.actions[name]  
                const oldAction = this.animation.actions.current  
      
                newAction.reset()  
                newAction.play()  
                newAction.crossFadeFrom(oldAction, 1)  
      
                this.animation.actions.current = newAction  
            }  
        }  
      
        update()  
        {  
            this.animation.mixer.update(this.time.delta * 0.001)  
        }  
    }
    
    

    相关文章

      网友评论

          本文标题:[Three.js 代码组织] 资源加载器

          本文链接:https://www.haomeiwen.com/subject/dqvppdtx.html