什么是WebGL
WebGL(Web 圖形庫)是一種 JavaScript API,用於在任何兼容的 Web 瀏覽器中呈現交互式 3D 和 2D 圖形,而無需使用插件。WebGL 通過引入一個與 OpenGL ES 2.0 緊密相符合的 API,可以在 HTML5 <canvas> 元素中使用(簡介引自 MDN)。
以我的理解,WebGL 給我們提供了一系列的圖形接口,能夠讓我們通過 JavaScript 去使用 GPU 來進行瀏覽器圖形渲染的工具。
什么是Three.js
Three.js 是一款 webGL 框架,由於其易用性被廣泛應用。Three.js 在 WebGL 的 API 接口基礎上,又進行的一層封裝。它是由居住在西班牙巴塞羅那的程序員 Ricardo Cabbello Miguel 所開發,他更為人知的網名是 Mr.doob。
Three.js 以簡單、直觀的方式封裝了 3D 圖形編程中常用的對象。Three.js 在開發中使用了很多圖形引擎的高級技巧,極大地提高了性能。另外,由於內置了很多常用對象和極易上手的工具,Three.js 的功能也非常強大。最后,Three.js 還是完全開源的,你可以在 GitHub 上找到它的源代碼,並且有很多人貢獻代碼,幫助 Mr.doob 一起維護這個框架。
WebGL與Three.js的關系
WebGL 原生 API 是一種非常低級的接口,而且還需要一些數學和圖形學的相關技術。對於沒有相關基礎的人來說,入門真的很難,Three.js 將入門的門檻降低了一大截,對 WebGL 進行封裝,簡化我們創建三維動畫場景的過程。只要你有一定的 JavaScript 基礎,有一定的前端經驗,我堅信,用不了多長時間,三維制作會變得很簡單。
用最簡單的一句話概括:WebGL 和 Three.js 的關系,相當於 JavaScript 和 jQuery 的關系。
功能概述
Three.js 作為 WebGL 框架中的佼佼者,由於它的易用性和擴展性,使得它能夠滿足大部分的開發需求,Three.js 的具體功能如下:
1. Three.js 掩蓋了 3D 渲染的細節:Three.js 將 WebGL 原生 API 的細節抽象化,將 3D 場景拆解為網格、材質和光源(即它內置了圖形編程常用的一些對象種類)。
2. 面向對象:開發者可以使用上層的 JavaScript 對象,而不是僅僅調用 JavaScript 函數。
3. 功能非常豐富:Three.js 除封裝了 WebGL 原始 API 之外,Three.js 還包含了許多實用的內置對象,可以方便地應用於游戲開發、動畫制作、幻燈片制作、髙分辨率模型和一些特殊的視覺效果制作。
4. 速度很快:Three.js 采用了 3D 圖形最佳實踐來保證在不失可用性的前提下,保持極高的性能。
5. 支持交互:WebGL 本身並不提供拾取(Picking)功能(即是否知道鼠標正處於某個物體上)。而 Three.js 則固化了拾取支持,這就使得你可以輕松為你的應用添加交互功能。
6. 包含數學庫:Three.js 擁有一個強大易用的數學庫,你可以在其中進行矩陣、投影和矢量運算。
7. 內置文件格式支持:你可以使用流行的 3D 建模軟件導出文本格式的文件,然后使用 Three.js 加載,也可以使用 Three.js 自己的 JSON 格式或二進制格式。
8. 擴展性很強:為 Three.js 添加新的特性或進行自定義優化是很容易的事情。如果你需要某個特殊的數據結構,那么只需要封裝到 Three.js 即可。
9. 支持HTML5 Canvas:Three.js 不但支持 WebGL,而且還支持使用 Canvas2D、Css3D 和 SVG 進行渲染。在未兼容 WebGL 的環境中可以回退到其它的解決方案。
雖然 Three.js 的優勢很大,但是它也有它的不足之處:
1. 官網文檔非常粗糙,對於新手極度不友好。
2. 國內的相關資源匱乏。
3. Three.js 所有的資料都是以英文格式存在,對國內的朋友來說又提高了門檻。
4. Three.js 不是游戲引擎,一些游戲相關的功能沒有封裝在里面,如果需要相關的功能需要進行二次開發。
Three.js提供了幾種源碼獲取方式,我是用的BootCDN 提供的免費 CDN 加速服務(同時支持 HTTP 和 HTTPS 協議),直接引入方式為:
<script src="https://cdn.bootcss.com/three.js/r83/three.js"></script>
如果需要更新代碼,可以點擊這里查找最新版本地址引入即可。
入門程序:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <!-- 引入three.js--> <script src="https://cdn.bootcss.com/three.js/r83/three.js"></script> <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>--> <title>a</title> <style> /* 將margin設為0,overflow設為hidden,全屏顯示 */ body { margin: 0; overflow: hidden; /* 超出部分隱藏 */ } </style> </head> <body> <div id="webgl-output"></div> <script type="text/javascript"> // 一旦所有東西都被加載,我們運行我們的Three.js東西 function init() { // 創建一個場景,其中包含所有元素,如對象、相機和燈光 var scene = new THREE.Scene(); // 創建一個攝像頭,它定義了我們看的地方 // PerspectiveCamera(透視攝像機)、第一個屬性是視野角度(FOV)、第二個值是長寬比(aspect ratio)、接下來的兩個值是遠剪切面和近剪切面 var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000) // 創建一個渲染器(負責計算指定相機角度下瀏覽器中scene的樣子)和設置大小 var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); // 將renderer對象的背景色設置為0xEEEEEE renderer.setSize(window.innerWidth, window.innerHeight); // 讓renderer對象將scene渲染成多大的尺寸 renderer.shadowMapEnabled = true; // 告訴渲染器需要陰影⭐️ // 在屏幕中顯示軸 // var axes = new THREE.AxisHelper(20); // axes坐標軸對象 // scene.add(axes); // 把坐標軸添加到場景中去 // 創建接地面 var planeGeometry = new THREE.PlaneGeometry(60, 20); // PlaneGeometry: 平面幾何 (參數: 寬60, 高20) var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff}); // // MeshLambertMaterial:網格材質 (用來設置平面的外觀, 顏色,透明度等) var plane = new THREE.Mesh(planeGeometry, planeMaterial); // 把這2個對象合並到一個名為plane(平面)的Mesh(網格)對象中 // 旋轉並定位平面 plane.receiveShadow = true; // 平面接收陰影⭐️ plane.rotation.x = -0.5 * Math.PI; // 繞X軸旋轉90度 plane.position.x = 15; // 平面坐標位置 plane.position.y = 0; plane.position.z = 0; scene.add(plane); // 把平面添加到場景 // 創建一個立方體 var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); // 立方體幾何 var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000}); // 立方體材質(顏色、wireframe: true線框) var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); // 立方體和外觀合並 cube.castShadow = true; // 立方體陰影⭐️ cube.position.x = -4; // 立方體的坐標位置 cube.position.y = 3; cube.position.z = 0; scene.add(cube); //把立方體添加到場景 // 創建一個球體 var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); // 球體 var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff}); // 球體的外觀(顏色、wireframe: true線框) var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // 球體與外觀合並 sphere.castShadow = true; // 球體的陰影 sphere.position.x = 20; // 球體的位置 sphere.position.y = 4; sphere.position.z = 2; scene.add(sphere); // 把圓添加到場景 // 將攝像機定位並指向場景中心 camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); // lookAt函數指向場景的位置 // 添加一個光源⭐️ var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; // 讓光源產生陰影 scene.add(spotLight); // 將渲染器的輸出添加到html元素中 document.getElementById('webgl-output').appendChild(renderer.domElement); // 渲染的場景 renderer.render(scene, camera) } window.onload = init; </script> </body> </html>
結果: