本文将会涵盖如下内容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对象或使用内置几何体建立几何体, 最后是两种摄像机的简介.相信大家能够制做一些简单的场景和几何体了.