Three.js封裝了底層的圖形接口,使得程序員可以在無需掌握繁冗的圖形學知識的狀況下,也能用簡單的代碼實現三維場景的渲染,相對於webGL,Three.js封裝了底層的圖形接口,在不瞭解圖形學的狀況下,也能用簡單的代碼實現三維場景的渲染javascript
預覽地址html
CDN引入java
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
複製代碼
一個基本的Three.js程序至少要包括渲染器(Renderer)、場景(Scene)、照相機(Camera),以及你在場景中建立的物體。git
new scene = new THREE.Scene()
其中 透視投影相機 (PerspectiveCamera)更真實的模仿人眼中的現實世界,本例也將用到程序員
THREE.PerspectiveCamera(fov, aspect, near, far)
github
其構造函數接受四個不一樣的參數,接受參數類型皆爲Numberweb
fov — 攝像機視錐體垂直視野角度
aspect — 攝像機視錐體長寬比
near — 攝像機視錐體近端面
far — 攝像機視錐體遠端面
複製代碼
var camera = new THREE.PerspectiveCamera(
75,//視野縱橫比
window.innerWidth / window.innerHeight,//基於瀏覽器寬高
0.1,//近端距離 near
1000,//遠端距離 far
)
//設置相機在z軸上的位置
camera.position.z = 5;
複製代碼
var renderer = new THREE.WebGLRenderer({
antialias: true, //是否反鋸齒。默認爲false
/*
canvas: canvas, //供渲染器繪製其輸出的canvas,若是沒有傳這個參數,會建立一個新canvas
precision:'highp', // 着色器精度. highp|mediump|lowp|highp(默認)
alpha: flase, // canvas是否包含alpha (透明度)。默認爲 false
stencil: flase // 繪圖緩存是否有模板緩存。默認爲true
*/
});
renderer.setClearColor("#e5e5e5");
renderer.setSize(window.innerWidth,window.innerHeight);
複製代碼
建立好後把 renderer 生成的 dom 結構(其實就是一個 canvas 標籤)append 到 html 裏 document.body.appendChild(renderer.domElement);
ajax
環境佈置好了,還差環境裏的物體 Three.js 中提供了不少類型的物體,它們都繼承自 Object3D 類,包括線段(Line)、骨骼(Bone)、粒子系統(ParticleSystem)。比較常見的是Mesh(網格),網格是由頂點、邊、面等組成的物體,網格越多,物體表面越平滑,更接近模仿真實。canvas
任何物體都有形狀,材質api
//3d物體包括物理形狀和材料
var geometry = new THREE.BoxGeometry(1, 1, 1);//半徑、寬度、圓滑度
var material = new THREE.MeshLambertMaterial({color: 0xf7f7f7});
//建立MESH模型
var mesh = new THREE.Mesh(geometry, material);
複製代碼
場景和物體都有了, 這個時候打開瀏覽器看到的是一個黑不溜秋的醜醜正方形,好像和3d搭不上邊嗷...
Three.js 提供了包括環境光 (AmbientLight)、點光源 (PointLight)、聚光燈 (SpotLight)、方向光 (DirectionalLight)、半球光 (HemisphereLight) 等多種光源。 只要在場景中添加須要的光源,再加上必定的物體旋轉就行了。這裏用到PointLight,
var light = new THREE.PointLight(0xffffff, 1, 500);//顏色,強度,距離
light.position.set(0,0,10); //設置光源位置
scene.add(light);
mesh.rotation.set(45,45,0);
複製代碼
而後頁面上的模型效果是這樣
動效庫有不少,這裏用使用gasp(green sock)複雜動畫序列使用的時間軸插件TimelineMax,詳見文檔tweenmax中文手冊
瀏覽器是一個2d視口,而在裏面顯示three.js的內容是3d場景,因此,如今有一個問題就是如何將2d視口的x和y座標轉換成three.js場景中的3d座標。three.js已經有了解決相關問題的方案,那就是THREE.Raycaster射線,用於鼠標去獲取在3D世界被鼠標選中的一些物體
//聲明raycaster和mouse變量
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector3();
複製代碼
光線投射Raycaster使用的是官方文檔裏的案例光線投射
參數 | 類型 | 說明 |
---|---|---|
target | Object | 須要動畫的對象 |
duration | Number | 動畫持續的秒數(或幀) |
vars | Object | 動畫參數(CSS屬性、延遲、重複次數等) |
position | 插入動畫的位置 |
function onMouseMove(event){
event.preventDefault();
// 將鼠標位置歸一化爲設備座標。x 和 y 方向的取值範圍是 (-1 to +1)
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
//傳入光線,經過攝像機和鼠標位置更新射線
raycaster.setFromCamera( mouse, camera );
// 計算物體和射線的焦點
var intersects = raycaster.intersectObjects( scene.children ,true);
for(let i = 0; i<intersects.length ; i++){
//選中與射線相交的物體
this.tl = new TimelineMax().delay(.3);
//添加動效
this.tl.to(intersects[i].object.scale, 1, {x:2, ease: Expo.easeOut})//網點,持續時間
this.tl.to(intersects[i].object.scale, .5, {x:.5, ease: Expo.easeOut})
this.tl.to(intersects[i].object.position, .5, {x:2, ease: Expo.easeOut})
this.tl.to(intersects[i].object.rotation, .5, {y:Math.PI*.5, ease: Expo.easeOut}, "=-1.5")//提早-1.5s發生
}
}
render();
//添加監聽事件
window.addEventListener('mousemove', onMouseMove)
複製代碼
這個時候能夠看到物體已經動起來了
能夠看到最後的效果是隨機建立一個個模型並分散在頁面上的,因此這裏循環建立多個模型,經過random改變其在 x , y , z上的position來達到「迎面而來」 動畫效果
meshCount = 0;
for( var i = 0 ;i < 20 ;i++) {
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x =( Math.random() - 0.5) *10;
mesh.position.y =( Math.random() - 0.5) *10;
mesh.position.z =( Math.random() - 0.5) *10;
scene.add(mesh);
meshCount++;
}
複製代碼
這個時候能夠看出光是不夠的,須要再加一個光源,光源的位置座標、強度、距離、衰退量能夠根據本身的感受調節
var light = new THREE.PointLight(0xffffff, 1, 1000);//顏色,強度,距離
light.position.set(0,0,0);
scene.add(light);
複製代碼
多個隨機模型 效果如圖
經過瀏覽器大小自動改變渲染的模型大小
//監聽窗口改變同時更新
window.addEventListener('resize',()=>{
renderer.setSize(window.innerWidth,window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
//注意,最後必定要調用updateProjectionMatrix()方法更新
camera.updateProjectionMatrix();
})
//最後渲染
var render = function(){
//不會由於瀏覽器寬高影響圖形
requestAnimationFrame(render);
renderer.render(scene,camera);
}
複製代碼
最後加個標題就完成了
參考:
學習three.js,除了還有官方的文檔和案例 還有就是羨轍小姐姐的three.js人門指南。羨轍姐姐是我在GitHub上第一個關注的人,超級喜歡她~
第一次在掘金髮文章,但願你們多多指點 ~