Three.js (一) WebGL、場景、相機(jī)、渲染器

概述

Canvas -> JavaScript -> Three.js -> WebGL -> OpenGL ->.... -> 顯卡

  • OpenGL是底層的驅(qū)動級的圖形接口(是顯卡有直接關(guān)系的) 類似于 DirectX
  • WebGL是瀏覽器API,允許JS去調(diào)用部分封裝過的 OpenGL ES2.0標(biāo)準(zhǔn)接口,并為Canvas提供硬件級別的3D圖形加速功能
  • Three.js 是使用 JavaScript對 WebGL接口進(jìn)行封裝與簡化而形成的一個易用的 3D庫。
  • Canvas區(qū)別于原本的 2dcontext,還可以作為WebGL的載體提供 webglcontext 。
Three.js基本組件關(guān)系

對比真實世界視覺形成
兼容性

WebGL本身可以通過引入WebGL.js進(jìn)行檢測

<script type="module">
  import { WEBGL } from '/js/three/WebGL.js';
  if(!WEBGL.isWebGLAvailable()){
    ...
  }
  if(WEBGL.isWebGL2Available()){
    ...
  }
</script>

除此之外還使用了以下特性或API,可能需要進(jìn)行Polyfills

  • Typed Arrays
  • Web Audio API
  • WebVR API
  • Blob

基本步驟

  1. 創(chuàng)建一個容納三維空間的場景 — Sence
  2. 將需要繪制的元素加入到場景中,對元素的形狀、材料、陰影等進(jìn)行設(shè)置
  3. 給定一個觀察場景的位置和角度 — Camera
  4. 將相機(jī)和場景通過渲染器呈現(xiàn)到頁面上 — Renderer
網(wǎng)格 ( Mesh ) 模型

場景 Scene

場景是各種繪制內(nèi)容的容器

  • 通過.add()可以向場景中添加內(nèi)容,默認(rèn)添加在(0,0,0)位置
var scene = new THREE.Scene();
  • 通過.remove()可以刪除場景中的內(nèi)容,注意刪除mesh時還要對其材料和紋理調(diào)用.dispose()
targetGold.geometry.dispose();
targetGold.material.dispose();
scene.remove(targetGold);
場景具有以下屬性
key 作用 默認(rèn)值
fog:Fog 定義了影響場景中的每個物體的霧的類型 null
overrideMaterial:Material 強(qiáng)制場景中的每個物體使用這里的材質(zhì)來渲染 null
autoUpdate:boolean 自動檢查每一幀是否需要更新場景及物體矩陣 true
background:Color/Texture 場景背景,且背景總是首先被渲染 null
霧化

場景中的物體離攝像機(jī)越遠(yuǎn)就會變得越模糊。
Fog( color : Integer, near : Float = 1, far : Float = 1000 )
分別為顏色、霧化開始時距離、全霧化處距離

scene.fog = new THREE.Fog(0xf7d9aa, 100, 950);

也可以隨著距離呈指數(shù)增長的霧化效果,只需要設(shè)置霧的顏色和濃度即可。如:

scene.fog = new THREE.FogExp2(0xffffff,0.02);
坐標(biāo)系

Three.js中使用的坐標(biāo)系為右手坐標(biāo)系。


scene.add(new THREE.AxisHelper(600));

相機(jī)

  • 當(dāng)窗口大小變化時保持物體尺寸不變
    視野高度計算公式:
    visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_from_camera;
  • 窗口大小變化時保持視野居中
    此時如果窗口高不變寬變短,則物體大小不變,依然居中
    此時如果窗口寬不變高變短,則物體變小
window.addEventListener('resize', handleWindowResize, false);
function handleWindowResize() {
  // update height and width of the renderer and the camera
  HEIGHT = window.innerHeight;
  WIDTH = window.innerWidth;
  renderer.setSize(WIDTH, HEIGHT);
  camera.aspect = WIDTH / HEIGHT;
  camera.updateProjectionMatrix();
}
正投影相機(jī) OrthographicCamera( left, right, top, bottom, near, far )

只是簡單的將三維空間法向投影到二維屏幕(相機(jī)),遠(yuǎn)近高低比例都相同。


通常我們將瀏覽器窗口的寬度和高度作為視景體的高度和寬度,相機(jī)正好在窗口的中心點上:

new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight  / 2, window.innerHeight / - 2, 1, 1000 );
透視投影相機(jī) PerspectiveCamera( fov, aspect, near, far )

近大遠(yuǎn)小,符合視覺的投影


  • fov 視角
    視角越小,物體看起來越大
  • aspect 寬高比
    通常等同于canvas寬高比,否則會失真
var camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight, 0.1, 1000);
position、lookAt
  • position屬性指定了相機(jī)所處的位置(即設(shè)置了camera.position.x、camera.position.ycamera.position.z)。
  • lookAt函數(shù)指定相機(jī)觀察的方向(即設(shè)置了相機(jī)角度),通常選擇場景中心。
  • up屬性指定了相機(jī)以哪個方向為上方(即設(shè)置了camera.up.x、camera.up.y、camera.up.z)。
camera.position.set(30, 40, 50);
camera.up.set(0, 0, 1);
camera.lookAt(scene.position);//new THREE.Vector3(0, 0, 0)

如僅改變.position而不重新調(diào)用.lookAt(),則視角不變,等于相機(jī)在場景中平移。

updateProjectionMatrix

改變相機(jī)實例構(gòu)造函數(shù)入?yún)?yīng)屬性時,需要調(diào)用camera.updateProjectionMatrix()才會生效。

camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
相機(jī)縮放

通常使用以下屬性

  • .getFocalLength () : Float
    返回當(dāng)前.fov(視野角度)相對于.filmGauge(膠片尺寸)的焦距。
  • .setFocalLength ( focalLength : Float ) : null
    通過相對于當(dāng)前.filmGauge的焦距,設(shè)置FOV。
  document.body.addEventListener('mousewheel', (e) => {
    e.preventDefault();
    var isDown = (e.wheelDelta < 0);
    var m = camera.getFocalLength();
    if (isDown) {
      if (m > _minFocalLength) m -= m * 0.05;
    } else {
      if (m < _maxFocalLength) m += m * 0.05;
    }
    camera.setFocalLength(m);

  }, { passive: false })
相機(jī)旋轉(zhuǎn)

場景Scene、相機(jī)Camera、物體模型Object Model,均可以旋轉(zhuǎn)

  1. 歐拉角旋轉(zhuǎn)
    最常用的旋轉(zhuǎn)方式,直接指定圍繞其自身的一條軸旋轉(zhuǎn)(因此當(dāng)相機(jī)自身lookAt不是正交坐標(biāo)軸時,如果進(jìn)行旋轉(zhuǎn),看到的內(nèi)容也是傾斜的)
//旋轉(zhuǎn)90°
camera.rotateY(Math.PI / 2);
camera.rotation.y = Math.PI / 2;
  1. 矩陣(Matrix)
    mutiply():矩陣的乘法。
    transpose():矩陣轉(zhuǎn)置。
    getInverse(m):求逆矩陣。
    makeRotationFromEuler(euler) :通過一個歐拉類型的值來設(shè)置矩陣的值。
    makeRotationFromQuaternion(q):通過一個四元數(shù)類型的值來設(shè)置矩陣。
    makeRotationonAxis(axis,theta):按一個軸旋轉(zhuǎn)θ°,然后設(shè)置矩陣的值。

  2. 四元數(shù)(Quaternion)

獲取相機(jī)當(dāng)前旋轉(zhuǎn)向量的三個方法
var vector1 = new THREE.Vector3(0, 0, - 1);
vector1.applyQuaternion(camera.quaternion);
console.log(vector1);

var vector2 = new THREE.Vector3(0, 0, -1);
vector2.applyEuler(camera.rotation, camera.eulerOrder);
console.log(vector2);

var vector3 = new THREE.Vector3(0, 0, 0);
camera.getWorldDirection( vector3 );
console.log(vector3);

渲染器

渲染器需要與一個canvas元素綁定,可以在實例化時就指定一個現(xiàn)有的canvas元素。此時可以直接使用WebGL2。

var canvas = document.getElementById('canvas');
var context = canvas.getContext('webgl2', { alpha: false });
var renderer = new THREE.WebGLRenderer({ canvas: canvas, context: context });

如未指定則renderer.domElement將是一個虛擬dom元素

var renderer = new THREE.WebGLRenderer();
renderer.render(scene, camera);
document.getElementById("container").appendChild(renderer.domElement);
實例化參數(shù)
key 作用 默認(rèn)值
canvas 綁定渲染器的canvas null
context 將渲染器附加到已有的渲染環(huán)境中 null
antialias 抗鋸齒 false
alpha canvas是否支持透明度 (不透明時canvas內(nèi)無法有透明物體,且canvas下的html也總是被覆蓋) false
常用屬性、方法
key 作用 默認(rèn)值
autoClear 每次render是否自動清除上一次內(nèi)容,若為false則每次渲染會疊加 true
domElement 一個canvas,渲染器在其上繪制輸出。渲染器的構(gòu)造函數(shù)會自動創(chuàng)建(如果沒有傳入canvas參數(shù)) null
shadowMap 關(guān)于陰影的一些屬性配置 -
.clear( color : Boolean = true, depth : Boolean = true, stencil : Boolean = true) 清除緩存 -
.dispose() 清理渲染器 -
.render() 進(jìn)行渲染 -
.setClearColor(color:Color, alpha:Float) 設(shè)置默認(rèn)顏色和透明度 -
.setSize( width : Integer, height : Integer, updateStyle : Boolean ) 調(diào)整大小,通常使用入?yún)?code>window.innerWidth,window.innerHeight -
.setPixelRatio(value : number) 設(shè)置設(shè)備像素比。通常用于避免HiDPI設(shè)備上繪圖模糊,通常入?yún)⒅苯邮褂?code>window.devicePixelRatio -
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容