天天看點

WebGL/ThreeJS項目結構介紹

WebGL/ThreeJS項目結構介紹

WebGL/ThreeJS項目結構介紹

最重要的一個js就是這個Store3D.js, 絕大多數代碼都放在這裡,也是整個程式的起點,

 common/CommonFunction.js的主要作用

common/CommonFunction.js裡面有個函數CommonFunction.createMaterial用來建立材質,

function CommonFunction() {
}

/**
 * 判斷目前對象是否為空對象
 */
CommonFunction.hasObj = function (obj) {
    if (obj != null && typeof (obj) != "undefined") {
        return true;
    } else {
        return false;
    }
},
    /**
     * 建立材質
     * length:材質的長
     * width:材質寬度
     * style:材質特性
     */
    CommonFunction.createMaterial = function (length, width, style) {
    var color = 0xFF0000;//材質的顔色
    var image = null;//才是是否有貼圖
    var texture = null;
    var ifRepeat = 0;//貼圖是否設定重複顯示
    var transparent = 0;//材質是否透明
    var opacity = 0;//材質透明度
    var depthTest = 1;//材質深度測試
    if (CommonFunction.hasObj(style)) {
        color = style.color || 0xFF0000;
        image = style.image || null;
        ifRepeat = style.ifRepeat || 0;
        transparent = style.transparent || 0;
        opacity = style.opacity || 0;
        depthTest = style.depthTest;
    }
    let material = new THREE.MeshPhongMaterial({map: texture, color: color});
    if (image != null) {
        texture = new THREE.TextureLoader().load(image);
        if (ifRepeat == 1) {
            texture.repeat.x = length / 128;
            texture.repeat.y = width / 128;
            texture.repeat.y = 5;
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        }
        material = new THREE.MeshBasicMaterial({map: texture});
    }
    if (transparent == 1) {
        material.transparent = true;
    }
    if (depthTest == 0) {
        material.depthTest = false;
    }
    material.opacity = opacity;
    return material;
}      

Data/BuildingData.js的主要作用

Data/BuildingData.js裡面聲明了一個buildingObjects對象表示所有建築物的類,

我們的資料分為兩部分,一部分是和建築相關的,比如牆和地闆,這些基本上是不會變化的,我們統一把它放到一個對象類裡面,

let buildingObjects = { // 所有建築物的類
    objects: [ // 我們可以把地闆看作是一個非常薄的立方體
        {
            objectName: 'floor', // 地闆
            objectType: 'cube',
            length: 3400, // 長
            width: 1200, // 寬
            height: 1, // 高
            position: { // 設定地闆位置在螢幕的正中央
                x: 0,
                y: 0,
                z: 0
            },
            style:{
                color: 0x5F7480,
                opacity: 1
            }
        }
    ]
}      

objects/Cube.js的主要作用

剛剛我們看了Data/BuildingData.js裡面的物體資料,那麼就要用一個Cube類來繪制這個立方體,就是objects/Cube.js

/**
 * 立方體類
 * 我們生活中很多的物體都可以歸結為立方體類,比如牆體,地闆,窗戶等都可看成是立方體類
 * @param option
 * @constructor
 */
function Cube(option){
    this.length = option.length || 1;
    this.width = option.width || 1;
    this.height = option.height || 1;

    this.Name = option.objName;

    this.positionX = option.position.x || 0;
    this.positionY = option.position.y || 0;
    this.positionZ = option.position.z || 0;

    // 設定立方體的顔色
    this.style=option.style||{color:0xFF0000}; 
    // 設定立方體的材質
    let curmaterial=CommonFunction.createMaterial(this.width,this.height,this.style);
    // 建立一個立方體
    let cubeGeometry = new THREE.BoxGeometry(this.length, this.height, this.width);

    let cube = new THREE.Mesh( cubeGeometry, curmaterial );
    cube.name=this.Name;
    cube.position.x=this.positionX;
    cube.position.y=this.positionY;
    cube.position.z=this.positionZ;
    return cube;
}      
function Store3D() {
    this.scene = null; //場景
    this.camera = null; //相機
    this.renderer = null; //渲染器
    this.objects = []; //場景中所有對象的集合
}

    /**
     * 初始化倉庫所有插件
     */
    Store3D.prototype.initMain = function () {
        this.initScene(); /** 初始化場景 */
        this.initCamera(); /** 初始化相機 */
        this.initRenderer(); /** 初始化渲染器 */
        this.initBuilding(); /** 初始化建築物 */
        this.initLight(); /** 初始化燈光 */
    },
    /**
     * 倉庫整體開始運作
     */
    Store3D.prototype.start = function () {
        this.initMain();
        this.animate();
    },

    /**
     初始化場景,僅僅需要有句話就可以生命一個場景,非常簡單
     **/
    Store3D.prototype.initScene = function () {
        this.scene = new THREE.Scene();
    },
    /**
     初始化場景,因為我們做的工廠模型,盡可能的接近于真實情景,采用透視相機
     **/
    Store3D.prototype.initCamera = function () {
        // 聲明一個相機, 這裡我們使用透視相機
        // 視角:60,
        // 縱橫比aspect:全屏,使用的是浏覽器的寬度/高度
        //近平面near:0.1
        //遠平面視角far:10000
        this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
        /*
        設定相機位置,注意threejs中的坐标系采用的是右手坐标系
         */
        this.camera.position.x = 0;
        this.camera.position.y = 1600;
        this.camera.position.z = 1000;
        //相機的朝向
        this.camera.lookAt(0, 0, 0);
        //将相機放到場景中
        this.scene.add(this.camera);
    },
    /**
     聲名渲染器
     **/
    Store3D.prototype.initRenderer = function () {
        this.renderer = new THREE.WebGLRenderer(
            {
                antialias: true, //是否開啟反鋸齒,設定為true開啟反鋸齒。
                alpha: true, //是否可以設定背景色透明。
                logarithmicDepthBuffer: true //模型的重疊部位便不停的閃爍起來。這便是Z-Fighting問題,為解決這個問題,我們可以采用該種方法
            }
        );
        this.renderer.setSize(window.innerWidth, window.innerHeight);//渲染器的尺寸與windows的尺寸相同
        this.renderer.setClearColor(0x39609B);//設定渲染的背景顔色
        this.renderer.setPixelRatio(window.devicePixelRatio);//設定渲染器的分辨率與浏覽器電腦本身的分辨率相同
        //将渲染器添加到我們的網頁中,可以将渲染的内容在網頁中顯示出來
        let container = document.getElementById("container");
        container.appendChild(this.renderer.domElement);
    },
    /**
     * 初始化燈光
     */
    Store3D.prototype.initLight=function(){
        //首先添加個環境光
        let ambient = new THREE.AmbientLight(0xffffff, 1); //AmbientLight,影響整個場景的光源
        ambient.position.set(0, 0, 0);
        this.addObject(ambient);
        //添加平行光,平行光類似于太陽光
        let directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);//模拟遠處類似太陽的光源
        directionalLight.position.set(0, 200, 0);
        this.addObject(directionalLight);
        //設定點光源
        let pointLight1=new THREE.PointLight(0xffffff, 0.3);
        pointLight1.position.set(-500,200,0);
        this.addObject(pointLight1);
        let pointLight2=new THREE.PointLight(0xffffff, 0.3);
        pointLight2.position.set(500,200,0);
        this.addObject(pointLight2);
    },

    /**
     * 向場景中添加物體,并記錄到
     */
    Store3D.prototype.addObject = function (object) {
        this.scene.add(object);
        this.objects.push(object);
    },
    /**
     建立建築物
     */
    Store3D.prototype.initBuilding = function () {
        let buildingData = buildingObjects.objects;
        // buildingObjects.objects 下的所有對象進行周遊
        for (let i = 0; i < buildingData.length; i++) {
            let object = buildingData[i];
            switch (object.objectType) { // 取object.objectType,
                case "cube": // 當類型為cube的時候
                    let cube = new Cube(object); // 建立一個立方體
                    this.addObject(cube); // 将這個立方體放入場景中
            }
        }
    },
    /**
     * 定時重複重新整理
     */
    Store3D.prototype.animate = function () {
        requestAnimationFrame(this.animate.bind(this));
        this.renderer.render(this.scene, this.camera);
    }