本文將會涵蓋如下內容css
THREE.Scene能夠說使場景的代碼化, 它保存了全部圖形場景的必要信息, 好比圖形對象, 光源, 和渲染所須要的其餘對象. 每一個添加到場景的對象, 甚至場景自己都是繼承自 THREE.Object3D
對象.web
// 導出給controller使用
export const scene = new THREE.Scene()
export const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100)
export const renderer = new THREE.WebGLRenderer()
export const planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1)
window.scene = scene
export const init = function() {
const axes = new THREE.AxesHelper(20)
scene.add(axes)
scene.add(camera)
renderer.setClearColor(new THREE.Color(0x000000))
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
const planeMaterial = new THREE.MeshLambertMaterial({
color: 'red',
})
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
plane.receiveShadow = true
plane.rotation.x = -0.5 * Math.PI
plane.position.x = 0
plane.position.y = 0
plane.position.z = 0
plane.name = 'plane'
scene.add(plane)
camera.position.x = -30
camera.position.y = 40
camera.position.z = 30
camera.lookAt(plane.position)
// 使材質對光產生反應
const ambientLight = new THREE.AmbientLight(0x3c3c3c)
scene.add(ambientLight)
// 建立一個點光源
const spotLight = new THREE.SpotLight(0xffffff, 1.2, 150, 120)
spotLight.position.set(-40, 60, -10)
spotLight.castShadow = true
scene.add(spotLight)
document.getElementById('webgl-output').appendChild(renderer.domElement)
renderer.render(scene, camera)
}
複製代碼
建立一個輔助控制器, 能夠動態往場景裏添加cube並查看有多少個cubeapp
const gui = new dat.GUI()
const addBlock = function() {
this.numberOfCubes += 1
const cubeL = Math.random() * 5
const cubeGeometry = new THREE.BoxGeometry(cubeL, cubeL, cubeL)
const cubeMaterial = new THREE.MeshLambertMaterial({
color: Math.random() * 0xffffff,
})
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
cube.castShadow = true
cube.position.x = camera.position.x + Math.round(Math.random() * planeGeometry.parameters.width)
cube.position.y = Math.round(Math.random() * 5)
cube.position.z = -20 + Math.round(Math.random() * planeGeometry.parameters.height)
cube.name='cube-'+this.numberOfCubes
scene.add(cube)
this.numberOfObjects = scene.children.length,
renderer.render(scene, camera)
}
const removeBlock = function() {
if (this.numberOfCubes > 0) {
const lastOne = scene.getObjectByName(`cube-${this.numberOfCubes}`)
scene.remove(lastOne)
this.numberOfCubes -= 1
renderer.render(scene, camera)
this.numberOfObjects = scene.children.length
}
}
export const controller = {
addBlock: () => addBlock.call(controller),
numberOfCubes: 0,
numberOfObjects: scene.children.length,
removeBlock: () => removeBlock.call(controller),
}
// 選擇哪些參數須要添加到控制GUI中
gui.add(controller, 'addBlock')
gui.add(controller, 'numberOfCubes').listen()
gui.add(controller, 'numberOfObjects').listen()
gui.add(controller, 'removeBlock')
複製代碼
運行截圖dom
以上代碼分別使用了scene的如下方法:ide
下面添加一個動畫, 讓添加的cube自動旋轉起來函數
// controller.js
gui.add(controller, 'rotationSpeed', 0, 0.5)
export const controller = {
// ...
rotationSpeed: 0,
}
// animation.js
export const animationRender = function render() {
scene.traverse((obj) => {
if (obj.name.includes('cube')) {
obj.rotation.x += controller.rotationSpeed
obj.rotation.y += controller.rotationSpeed
obj.rotation.Z += controller.rotationSpeed
}
})
requestAnimationFrame(animationRender)
renderer.render(scene, camera)
}
複製代碼
這裏又使用了一個新的scene的方法, traverse, 遍歷全部的子對象樹, 不過與scene.children.forEach
的差異在於: 若是子對象自己還有子對象, 最會在該子對象上執行traverse方法. 使用requestAnimationFrame使動畫連貫. 遞歸執行動畫
fog表示場景的霧化屬性, 霧化的效果使: 場景中的物體離得越遠越模糊, 跟拍照同樣.webgl
添加的方法使:ui
// 添加白色霧化效果, near和far值
scene.fog = new THREE.Fog(0xffffff, 0.015, 100)
// 指數增加的霧化濃度
scene.fog = new THREE.FogExp(0xffffff, 0.01)
複製代碼
線性漸變截圖this
指數漸變截圖
可使用這一屬性批量修改在場景中的全部物體的材質, 方便進行統一的控制, 即便是物體自己設置了屬性.
scene.overrideMaterial = new THREE.MeshLambertMaterial({
color: 0xfffffff
})
複製代碼
覆蓋截圖:
上述內容便是關於場景的全部經常使用屬性的描述
用於填充場景, 表現具體的物體內容.
大多數幾何體均是三維空間的點集(vertex, 頂點)和將這些點鏈接起來的面.以立方體爲例
// customeCube.js
const vertices = [
new THREE.Vector3(1, 3, 1),
new THREE.Vector3(1, 3, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(-1, 3, -1),
new THREE.Vector3(-1, 3, 1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1),
]
const faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
new THREE.Face3(7, 6, 2),
new THREE.Face3(6, 3, 2),
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
]
const gem = new THREE.Geometry()
gem.vertices = vertices
gem.faces = faces
gem.computeFaceNormals()
const mat = [
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}),
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),
]
const group = new THREE.Group()
for ( let i = 0, l = mat.length; i < l; i ++ ) {
group.add( new THREE.Mesh( gem, mat[i] ) )
}
// 遍歷全部mesh
group.children.forEach((mesh) => mesh.castShadow = true)
group.name = 'customCube'
export default group
複製代碼
最終展現的效果:
注意在建立faces的時候, 若是須要讓這個面, 面向攝像機, 那麼3個點須要按照順時針方向添加,反之爲逆時針
最後一個clone方法
const clone = function() {
const geo = scene.getObjectByName('customCube').children[0].geometry
const mats = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}),
]
const group = new THREE.Group()
for (let i = 0, l=mats.length; i < l; i ++) {
group.add(new THREE.Mesh(geo, mats[i]))
}
group.translateX(10 * (Math.random() + 1))
group.translateY(3)
group.name = 'clone'
scene.remove(scene.getObjectByName('clone'))
scene.add(group)
}
複製代碼
clone能夠克隆整個物體, 也能夠只複製geometry, 再從新給material.
網格的建立須要一個幾何體以及一個或多個材質, 建立完成以後, 添加到場景中進行渲染. 如下屬性用於改變網格在場景中的位置和顯示的效果
degree * (Math.PI/180)
須要注意的是dat.GUI的用法, 如下是設置controller
const controls = new function () {
this.scaleX = 1;
this.scaleY = 1;
this.scaleZ = 1;
this.positionX = 0;
this.positionY = 4;
this.positionZ = 0;
this.rotationX = 0;
this.rotationY = 0;
this.rotationZ = 0;
this.scale = 1;
this.translateX = 0;
this.translateY = 0;
this.translateZ = 0;
this.visible = true;
// 點擊時調用函數
this.translate = function () {
cube.translateX(controls.translateX);
cube.translateY(controls.translateY);
cube.translateZ(controls.translateZ);
controls.positionX = cube.position.x;
controls.positionY = cube.position.y;
controls.positionZ = cube.position.z;
}
};
複製代碼
按類別添加到dat.GUI中, 並監聽變化進行響應
const gui = new dat.GUI();
// addFolder, 添加一個文件夾的層級
guiScale = gui.addFolder('scale');
guiScale.add(controls, 'scaleX', 0, 5);
guiScale.add(controls, 'scaleY', 0, 5);
guiScale.add(controls, 'scaleZ', 0, 5);
guiPosition = gui.addFolder('position');
const contX = guiPosition.add(controls, 'positionX', -10, 10);
const contY = guiPosition.add(controls, 'positionY', -4, 20);
const contZ = guiPosition.add(controls, 'positionZ', -10, 10);
// 監聽器
contX.listen();
// 響應, 每次更改時觸發
contX.onChange(function (value) {
cube.position.x = controls.positionX;
});
contY.listen();
contY.onChange(function (value) {
cube.position.y = controls.positionY;
});
contZ.listen();
contZ.onChange(function (value) {
cube.position.z = controls.positionZ;
});
複製代碼
一個場景的渲染若是沒有攝像機就沒法被展現出來, 一共有兩種攝像機
建立透視投影的參數有:
建立正交投影的參數爲, 很像一個長方體:
攝像機都有一個方法: lookAt(new THREE.Vector3(x,y,z))
表示攝像機應該指向的地方, 能夠指向一個點, 也能夠指向一個具體的物體, 好比plane, 下一部分會詳細說明攝像機的具體用法, 此處先帶過
上述部分講述了THREE.Scene的全部屬性和方法, THREE.Geometry對象或使用內置幾何體建立幾何體, 最後是兩種攝像機的簡介.相信大家能夠製做一些簡單的場景和幾何體了.