1. 程式人生 > >使用THREE-js設計一款3D遊戲.md

使用THREE-js設計一款3D遊戲.md

使用THREE.js製作一款3D遊戲

前言

這個學期選修了一門計算機圖形學的課程,課程選用的教材是基於WebGL。在此之前我對計算機圖形學是沒有任何概念的,只知道如果想要設計一款遊戲具有圖形學的知識是很重要的。我從來就有一個念想就是製作一款遊戲,因此我對這方面是很有興趣的。 老師推薦了一本入門教材《WebGL程式設計指南》,這本教材講的很詳細很適合入門使用,我花了大約一週的時間將這本書看完,對webgl的程式設計有了個大致的瞭解,當然真的只是粗粗入門。學習過程中又瞭解到three.js這個基於webgl的第三方3d圖形庫,看到了很多酷炫的3d遊戲都使用了這個庫,我決定下一步就是學習這個庫的使用。 我大概看了半本的《THREE.js開發指南》,這本書很系統的講了這個第三方庫,但是難免很枯燥,於是就找到了現在這個使用three.js設計遊戲的這麼一個小專案。

程式碼結構

主函式由各種構件場景的函式組成,十分簡潔

function init(event){
    createScene();
    
    createLights();

    createPlane();
    
    createSea();
    
    createSky();
    
    document.addEventListener('mousemove', handleMouseMove, false);
    
    loop();//迴圈函式,用於最後每一個幀的重繪,實現動畫效果
}

使用dat.gui圖形介面動態的調整資料

dat.gui是一個第三方的圖形庫,通過這個圖形介面來調整資料真的很方便

//通過dat.gui來調整環境光
var controls = new function () {//宣告一個控制物件
    this.ambientLightColor = "#dc8874";
}
//環境光的值可以是16進位制的數值,如"#ffffff",每次通過gui調整了color值都會觸發下面的匿名函式從而調整環境光的顏色,環境光加入到場景中後每次渲染場景時都會使用最新的環境光顏色值,從而實現了使用gui調整環境光顏色的功能
var gui = new dat.GUI;//建立gui物件
gui.addColor(controls,'ambientLightColor').onChange(
function (e) { ambientLight.color = new THREE.Color(e);// });

當然可以新增更多的資料來進行動態調整,比如照相機的位置,各種顏色數值,等等。這是一個超級使用的功能。

一、搭建一個場景

使用thre.js繪製3d圖形最基本的就是需要一個場景,場景像一個容器,至少需要包括燈光,照相機和渲染器

function createScene(){

    HEIGHT = window.innerHeight;
    WIDTH = window.innerWidth;

    scene = new THREE.Scene();//建立場景
    scene.fog = new THREE.Fog(0xf7d9aa, 100,950);//使用霧化的效果
    var axes = new THREE.AxisHelper(200);//場景中新增一個三維座標系,便於觀察圖形的位置
    scene.add(axes);
    aspectRatio = WIDTH / HEIGHT;//寬高比設定為視窗大小,避免圖案的變形
    fieldOfView = 50;
    nearPlane = 0.1;
    farPlane = 10000;
    camera = new THREE.PerspectiveCamera(fieldOfView,aspectRatio,nearPlane,farPlane);//使用一個透視相機使物體具有3d的效果
    camera.position.x = 0;//相機的位置和視點將影響觀察到的物體
    camera.position.z = 200;
    camera.position.y = 100;//待優化

    renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });//宣告一個webgl的渲染器,這個渲染器就如同html中的canvas
    renderer.setSize(WIDTH,HEIGHT);
    renderer.shadowMap.enabled = true;
    container = document.getElementById('world');
    container.appendChild(renderer.domElement);//將這個渲染器加到html當中

    

二、新增燈光

在three.js中新增燈光十分的簡單,不同的燈光有不同的作用,比如環境光,點光源,聚光燈等等。這裡用到了半球光,半球光其中設定的兩個引數天空和地面的顏色可以使場景更加的真實。

function createLights(){
    hemisphereLight = new THREE.HemisphereLight(0xbbbbbb,0x000000, .9);
    ambientLight = new THREE.AmbientLight(controls.ambientLightColor);
    shadowLight = new THREE.DirectionalLight(0xffffff, .9);
    shadowLight.castShadow = true;
    shadowLight.shadow.camera.left = -400;
    shadowLight.shadow.camera.right = 400;
    shadowLight.shadow.camera.top = 400;
    shadowLight.shadow.camera.bottom = -400;
    shadowLight.shadow.camera.near = 1;
    shadowLight.shadow.camera.far = 1000;
    shadowLight.shadow.mapSize.width = 2048;
    shadowLight.shadow.mapSize.height = 2048;
//每次設定完燈光都需要把他新增到場景中
    scene.add(hemisphereLight);
    scene.add(shadowLight);
    scene.add(ambientLight);
}

三、創造一片大海

這裡的大海是通過一個倒置的圓柱體來實現的,通過調整照相機的位置,並且配合旋轉的動畫,在半球光的照射下就如同一片汪洋。

Sea = function(){
    var geom = new THREE.CylinderGeometry(600,600,800,40,10);
    geom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI/2));
    var mat = new THREE.MeshPhongMaterial({
        color:Colors.blue,
        transparent:true,
        opacity:.6,
        shading:THREE.FlatShading,
    });
    this.mesh = new THREE.Mesh(geom, mat);
    this.mesh.receiveShadow = true;

}

var sea;
function createSea(){
    sea = new Sea();
    sea.mesh.position.y = -600;
    scene.add(sea.mesh);
}

四、簡單又精緻的天空

我們使用幾塊大小不一的方塊隨機的堆疊在一起,它們就像雲朵一樣,很抽象派是吧!如果再把他們的位置隨機的擺放,配合轉動的動畫,是不是更像了呢!

//構造一個雲朵物件
Cloud = function(){
    this.mesh = new THREE.Object3D();
    var geom = new THREE.BoxGeometry(20,20,20);

    var mat = new THREE.MeshPhongMaterial({
        color:Colors.white,
    });
    var nBlocs = 3+Math.floor(Math.random()*3);

    for(i=0;i<nBlocs;i++){
    //實現位置隨機,大小隨機
        var m = new THREE.Mesh(geom, mat);
        m.position.x = i*15;
        m.position.y =Math.random()*10;
        m.position.z = Math.random()*10;
        m.rotation.z = Math.random()*Math.PI*2;
        m.rotation.y = Math.random()*Math.PI*2;
        var s = .1 + Math.random()*.9;
        m.scale.set(s,s,s);

        m.castShadow = true;
        m.receiveShadow = true;

        this.mesh.add(m);
    }
}

Sky = function(){
    this.mesh = new THREE.Object3D();
    this.nClouds = 20;
    var stepAngle = Math.PI*2 / this.nClouds;
    for (var i=0;i<this.nClouds;i++){
        var c = new Cloud();
        var a = stepAngle*i;
        var h = 750 + Math.random()*200;
        c.mesh.position.y = Math.sin(a)*h;
        c.mesh.position.x = Math.cos(a)*h;
        c.mesh.rotation.z = - Math.PI/2+a;
        c.mesh.position.z = -50-Math.random()*400;
        var s = 1+Math.random()*2;
        c.mesh.scale.set(s,s,s);
        this.mesh.add(c.mesh);
    }
}
var sky;

function createSky(){
    sky = new Sky();
    sky.mesh.position.y = -600;
    scene.add(sky.mesh);
}

五、設計一架超酷的飛機

使用五個矩形打造一款飛機!這似乎聽起來有點困難,但是這真的很有意思,配合不同的顏色,在螺旋槳的轉動下,這款飛機真的很逼真!

var AirPlane = function() {

    this.mesh = new THREE.Object3D();

    // 這裡要做的是一個駕駛艙
    var geomCockpit = new THREE.BoxGeometry(80,50,50,1,1,1);
    var matCockpit = new THREE.MeshPhongMaterial({color:Colors.red, shading:THREE.FlatShading});
    geomCockpit.vertices[4].y-=10;
    geomCockpit.vertices[4].z+=20;
    geomCockpit.vertices[5].y-=10;
    geomCockpit.vertices[5].z-=20;
    geomCockpit.vertices[6].y+=20;
    geomCockpit.vertices[6].z+=20;
    geomCockpit.vertices[7].y+=20;
    geomCockpit.vertices[7].z-=20;

    var cockpit = new THREE.Mesh(geomCockpit, matCockpit);
    cockpit.castShadow = true;
    cockpit.receiveShadow = true;
    this.mesh.add(cockpit);

    // 還要有引擎蓋
    var geomEngine = new THREE.BoxGeometry(20,50,50,1,1,1);
    var matEngine = new THREE.MeshPhongMaterial({color:Colors.white, shading:THREE.FlatShading});
    var engine = new THREE.Mesh(geomEngine, matEngine);
    engine.position.x = 40;
    engine.castShadow = true;
    engine.receiveShadow = true;
    this.mesh.add(engine);

    // 做個尾巴吧
    var geomTailPlane = new THREE.BoxGeometry(15,20,5,1,1,1);
    var matTailPlane = new THREE.MeshPhongMaterial({color:Colors.red, shading:THREE.FlatShading});
    var tailPlane = new THREE.Mesh(geomTailPlane, matTailPlane);
    tailPlane.position.set(-35,25,0);
    tailPlane.castShadow = true;
    tailPlane.receiveShadow = true;
    this.mesh.add(tailPlane);

    // 機翼當然少不了,用長長的矩形穿過機身,多麼美妙!
    var geomSideWing = new THREE.BoxGeometry(40,8,150,1,1,1);
    var matSideWing = new THREE.MeshPhongMaterial({color:Colors.red, shading:THREE.FlatShading});
    var sideWing = new THREE.Mesh(geomSideWing, matSideWing);
    sideWing.castShadow = true;
    sideWing.receiveShadow = true;
    this.mesh.add(sideWing);

    // 飛機前端旋轉的螺旋槳
    var geomPropeller = new THREE.BoxGeometry(20,10,10,1,1,1);
    var matPropeller = new THREE.MeshPhongMaterial({color:Colors.brown, shading:THREE.FlatShading});
    this.propeller = new THREE.Mesh(geomPropeller, matPropeller);
    this.propeller.castShadow = true;
    this.propeller.receiveShadow = true;

    // 螺旋槳
    var geomBlade = new THREE.BoxGeometry(1,100,20,1,1,1);
    var matBlade = new THREE.MeshPhongMaterial({color:Colors.brownDark, shading:THREE.FlatShading});

    var blade = new THREE.Mesh(geomBlade, matBlade);
    blade.position.set(8,0,0);
    blade.castShadow = true;
    blade.receiveShadow = true;
    this.propeller.add(blade);
    this.propeller.position.set(50,0,0);
    this.mesh.add(this.propeller);

};

var airplane;

function createPlane(){
    airplane = new AirPlane();
    airplane.mesh.scale.set(.25,.25,.25);
    airplane.mesh.position.y = 100;
    scene.add(airplane.mesh);
}

好了,夥計!現在我們的場景中有了燈光,大海,天空還有飛機,但是,似乎還少了什麼。對的,我們要操控這個飛機!

六、控制我們的飛機

飛機能跟隨滑鼠移動的軌跡,為了做到更完美,當飛機上升和下降時,應該要有旋轉的感覺!


function handleMouseMove(event) {

    // 我們要把滑鼠的座標值轉換成webgl系統中規格化的數值,從-1到1
    // 這種轉換很簡單的夥計!tx = (x-width/2)/(width/2)

    var tx = -1 + (event.clientX / WIDTH)*2;

    // y軸在視窗座標系和webg座標系的方向是相反的,因此我們把他逆一下就可以
    

    var ty = 1 - (event.clientY / HEIGHT)*2;
    mousePos = {x:tx, y:ty};

}


function updatePlane(){
    var targetY = 100+mousePos.y*75;//控制飛機在y軸25到175的位置
    var targetX = mousePos.x*195;//控制飛機在x軸-195到195的位置

    // 每一幀移動飛機移動的距離,使飛機最終到達滑鼠的位置,這樣製造出飛機緩緩飛向指定位置的效果,而不會顯得很突兀。
    airplane.mesh.position.y += (targetY-airplane.mesh.position.y)*0.1;
    airplane.mesh.position.x += (targetX-airplane.mesh.position.x)*0.5;
    // 通過剩餘距離的長度來計算旋轉地幅度,這樣飛機如果一次性移動的距離很多相應的旋轉幅度就越大,與真實的情況也符合,使動畫更加真實。
    airplane.mesh.rotation.z = (targetY-airplane.mesh.position.y)*0.0256;
    airplane.mesh.rotation.x = (airplane.mesh.position.y-targetY)
            
           

相關推薦

使用THREE-js設計3D遊戲.md

使用THREE.js製作一款3D遊戲 前言 這個學期選修了一門計算機圖形學的課程,課程選用的教材是基於WebGL。在此之前我對計算機圖形學是沒有任何概念的,只知道如果想要設計一款遊戲具有圖形學的知識是很重要的。我從來就有一個念想就是製作一款遊戲,因此我對這方面

3、找到大學生的某個痛點,設計手機產品

技能培訓 會有 激勵 職業 虛擬貨幣 互聯 幫助 結構 設置 詳解: 第一步:需求調研 針對大學生的職業技能培訓平臺 目標用戶: 還未步入職場的年輕人 初入職場的年輕人 第一期主要功能: 主推互聯網公司的職業技能培訓 幫助學生找到真正適合自己的職業 第二步:需求分析

如何從零開始設計漂亮的移動APP?

原型設計 交互設計 界面設計 APP開發 以下內容由Mockplus團隊翻譯整理,僅供學習交流,Mockplus是更快更簡單的原型設計工具。 我13歲時開始學習平面設計。我從網上課程學會了設計網站,並習慣於全天使用Photoshop和Affinity Designer進行設計

進階學習,如何無代碼設計美觀且實用的網站?

可用性測試 很好 product 收獲 遷移 落地 流行 最好的 人員 作為一門新興的邊緣性職業,網站設計既要從外觀上創意,又要適當結合圖形、版面及交互設計等相關原理,使得它成為一門獨特且令人神往的藝術。毫無疑問,好的設計能讓網站在諸多站點中脫穎而出,優秀的創意和表現方式能

[微信小遊戲+Three.JS]針對微信小遊戲修改的three.js和weapp-adapter.js

github 無法 inf 運行 .net AD bsp targe hat 最近在做一個微信3D小遊戲 直接從github上下載的three.js,無法直接在微信小遊戲中運行 下面是我修改,並經過測試完美的three.js和weapp-adapter.js Thre

設計c#自動程式碼生成器 (1)

1,構思配置驅動檔案生成 網上自動化指令碼生成的思路是 1)設定好對應的模板 2)讀取資料庫對應的檔案 3)根據模板對應的欄位替換生成 模板》讀取資料》生成對應檔案 為什麼會有做自動化指令碼的想法,是因為工作中發現protobuf 這個工具可以自動編譯根據伺服器生成對應的cs檔案 所以我這裡想仿

利用二叉樹設計簡單的huffman編碼器

從磁碟讀入一個僅包括英文字母及標點符號的文字檔案(如f1.txt),統計各字元的頻度,據此構建huffman樹,對各字元進行編碼,並將字符集,頻度集及相應編碼碼字集輸出在顯示器或儲存在另一個文字檔案(如 f1_code.txt)中. 思路: Void Huffman

如何設計基於ROS的移動機器人?

編者按:本文是EAI科技創始人兼CEO李金榜在硬創公開課的文字稿,感謝作者和雷鋒網授權轉載。   最近幾年各種移動機器人開始湧現出來,不論是輪式的還是履帶式的,如何讓移動機器人移動都是最核心的工作。要讓機器人實現環境感知、機械臂控制、導航規劃等一系列功能,就需要

.Net架構篇:思考如何設計實用的分散式監控系統?

前言無論從最早期的unix作業系統,還是曾經大行其道的單體式應用,還是現在日益流行的微服務架構,始終都離不開監控的身影。如windows的工作管理員,linux的top命令,都可以看作是監控的面板。再聯絡起現實生活,無處不在的路網攝像頭,為交通機關監控交通人流提供了方便。系統規模越大,越離不開監控。缺少了監控

【乾貨分享】用AI工具設計吸引人的字型效果

乾貨又來啦!今天教大家如何使用AI工具設計一款引人注目的字型效果,話不多說,我們直接開始! 1、在AI畫布中使用鋼筆工具勾勒出字母的線條,如圖所示 2、使用橢圓工具畫一個小的正圓,並填充藍色漸變。 3、我們再複製一個小圓,並填充紫色漸變,使用混合工具分別在

如何設計分散式發號器

在網際網路的世界裡,產生唯一流水號的服務系統俗稱發號器。Twitter的Snowflake是一個流行的開源的發號器的實現。Slowfake是由Scala語言實現的,並且文件簡單、釋出模式單一、缺少支援和維護,很難在現實的專案中直接使用。 為了能讓Java領域的小夥伴們在不同

程式設計策略(設計APP的步驟)

偉大的程式起源於一個偉大的想法,但這並不意味著講想法孕育成成功的程式是一件輕鬆的事。本文介紹的是一些能用於精煉想法、回顧設計選擇(design options)的策略,幫助我們設計出人見人愛的程式。 明確程式定義 在開發早期就完成程式的定義,能

案例分析:如何從0到1對產品遊戲

作者:青谷全文共 5369 字 12 圖,閱讀需要 12 分鐘———— / BEGIN / ——

js 學習 猜數字遊戲

val user 數字 mar math submit rem for listener 知識點 js 操作元素 增 (document.createElement(),document.body.appendChild()), 刪(parentNode.removeCh

如何設計軟體的一些感想

        想想入行已經1年有餘,天天出了拿需求寫程式碼,完成一個個功能外,自己對整個軟體的開發如何誕生,如何設計卻瞭解的很有限。這些天一直在思考著一款軟體在讓我編碼之前都做了什麼?一款軟體到我這樣的程式設計師開始功能程式碼的編寫之前都是由誰完成的?都是怎麼設計的?都是

如何步步設計微服務的補償方案

背景 隨著微服務化的系統越來越多,系統間的互動也呈現幾何倍增的趨勢,系統間面臨一致性問題越來越突出。為了保障服務提供方與服務消費方的一致性,特別是面臨最大努力通知型或補償性的技術需求,服務化前做法是服

設計師怎樣從零開始設計APP?

作為設計師最大的成就感,是著手一個專案,看著它從0到1,慢慢孵化成形,再接著改版進行優化,受到越來越多的使用者歡迎。這個系列的文章把整個過程的經驗總結成文,篇幅較長,逐點分享,今天是概述+立項。 從上圖可以知道,在整個過程中,設計師的工作可以分為做人和做事兩大類。 學會做人

從零開始設計APP之如何做原型圖

@Sophia的玲瓏閣 :這個系列的文章把整個設計過程的經驗總結成文,逐點分享,上期是概述+立項,這期聊聊低保真和高保真原型圖的作用、處理工具和檔案要求等。 Low-fi,即低保真原型圖,整個APP設計階段,設計師真正開始上手的環節。待PM製作好PRD文件和邏輯流程圖之後,

如何設計多場景分散式發號器(Vesta)

作者:李豔鵬,支付平臺架構師,專注線上和線下支付平臺的應用架構和技術架構的規劃與落地,負責交易、支付、渠道、賬務、計費、風控、對賬等系統的設計與實現,在移動支付、聚合支付、合規賬戶、掃碼支付、標記化支付等業務場景上有產品應用架構規劃的經驗。微信

Three.js中重新設定3D模型的中心點

最近有個新想法,要在網頁上展示3D重建的模型(obj + mtl 格式),並且可以拖拽縮放。 實施過程中發現模型的中心點是偏離到模型外部的,經過查閱Three.js資料發現兩個關鍵函式 geometry.computeBoundingBox();geometry.cent