WEB端三维可视化(threejs)02
程序员文章站
2022-06-11 10:58:22
...
前言(大部分解释都在代码注释上边)
上一个主要说自己选择的web引擎和前置安装步骤,接着直接开荤,进入正文。
本人的代码大部分都很简单,方便自己看,也方便各位同学们学习,所以不要吐槽。
个人认为:threejs相对来说最方便的是什么?他把webgl那些复杂的点、线、面等等封装成一个个组件,如果不做非常非常精细化的场景,对于展示物体,一些web端三维可视化项目之类的完全够用了。
一、场景scene:
首先,场景scene是什么?想要容纳万物,是不是要先开辟一方空间,而场景scene就相当于这一方空间,有了这一方空间,才能在这方空间里创造万物。
//页面上创建一个div用来盛放threejs的空间,执行渲染renderer之后会有一个canvas填充到这个div里
<div id="threecanvas"></div>
//首先引入threejs的基础库
import * as THREE from 'three'
1.创建场景
var scene
// 初始化场景
function initScene() {
// 实例化一个场景
scene = new THREE.Scene()
// 整个场景的颜色
scene.background = new THREE.Color( 0x000000 )
}
2.天空盒子
// 天空盒是以正方体6面结构贴图[贴图顺序:右、左、上、下、前、后]
var urls = [
'./static/skyBox/day/px.jpg',
'./static/skyBox/day/nx.jpg',
'./static/skyBox/day/py.jpg',
'./static/skyBox/day/ny.jpg',
'./static/skyBox/day/pz.jpg',
'./static/skyBox/day/nz.jpg'
]
//初始化一个场景
function initScene() {
// 实例化一个场景
scene = new THREE.Scene()
// 整个场景的颜色
scene.background = new THREE.Color( 0x000000 )
// 6图天空盒子[贴图顺序:右、左、上、下、前、后]
scene.background = new THREE.CubeTextureLoader().load(urls)
}
二、相机camera:
相机相当于人的眼睛,用于看到展示在视野内的物体。
var camera
// 初始化相机
function initCamera() {
//实例化一个相机,内部参数(角度,div的宽/div的高,距离视野中心最近距离,同前最远距离)
//角度:类似于手机狭角、广角的效果
//画面比例:div的宽高自己定义,全屏展示的话就按照官网给的window.innerWidth/window.innerHeight即可
//视野最大(小)远近距离根据自身项目来定
camera = new THREE.PerspectiveCamera(60,
document.getElementById('threecanvas').offsetWidth / document.getElementById('threecanvas').offsetHeight, 2, 5000)
camera.position.set(0, 100, -100)//相机位置
camera.lookAt(new THREE.Vector3(0, 0, 0))// 相机视野中心
//相机所展示画面的比例
camera.aspect = document.getElementById('threecanvas').offsetWidth / document.getElementById('threecanvas').offsetHeight
//更新相机投影变换矩阵
camera.updateProjectionMatrix()
//将相机加入到场景中
scene.add(camera)
}
三、渲染器renderer:
渲染器,顾名思义,就是把这个三维空间渲染到web页面上,前边我在页面上加了id为threecanvas的div便签,那我可以把场景渲染到threejscanvas里。
var renderer
// 初始化渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer({
alpha: false,// 是否可以设置背景色透明
antialias: true, // 抗锯齿
logarithmicDepthBuffer: true, // 图层叠加闪烁问题
precision: 'lowp', // 着色器精度
preserveDrawingBuffer: true, // 开启图层缓冲区
autoClear: true
})
renderer.setPixelRatio(window.devicePixelRatio)// 设置分辨率与电脑的分辨率相同
renderer.setSize(document.getElementById('threecanvas').offsetWidth, document.getElementById('threecanvas').offsetHeight)
renderer.shadowMap.enabled = true// 渲染器渲染阴影效果
renderer.shadowMap.type = THREE.PCFSoftShadowMap// 阴影类型
renderer.outputEncoding = THREE.sRGBEncoding// 色域,鲜明渲染,常规rgb颜色渲染
// 把这个canvas渲染到指定div里,不指定div则把setSize指定宽高
document.getElementById('threecanvas').appendChild(renderer.domElement)
}
四、控制器controls:
控制器,就是可以使用鼠标控制三维场景旋转等交互操作,变换视角,以达到三维效果,否则的话,web页面上渲染出来的只能算作平面三维物体,只能看,不能交互,意义不大。
//控制器需要引入控制器插件
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
var controls
// 初始化控制器
function initControls() {
controls = new OrbitControls(camera, renderer.domElement)
controls.listenToKeyEvents(window)//监听操作,具体有哪些可以去底层扒一扒
controls.enableDamping = true// 开启控制阻尼,是否有惯性
controls.dampingFactor = 0.05 // 阻尼强度,鼠标拖拽旋转灵敏度
controls.enableZoom = true// 是否可以缩放
controls.minDistance = 2// 相机距离原点最近距离
controls.maxDistance = 1000// 相机距离原点最远距离
controls.enablePan = true // 是否开启右键拖拽
controls.maxPolarAngle = Math.PI / 2.05 // 最大角度,实际项目中一些模型限制视角到地下
controls.screenSpacePanning = false //false时只能前后左右平移,不能上下平移,true时哪个方向都可以
controls.target = new THREE.Vector3(0, 0, 0)// 设置控制器的旋转原点
}
// 更新,实时渲染的时候加进去,有控制交互,就渲染
function update() {
controls.update()
}
五、光源light:
前边我创建好了场景、相机、渲染器、控制器,还有一个天空盒,这个时候场景中没有光源,什么都看不到,所以需要光源来照亮物体。
//这里我主要使用,环境光和平行光
//环境光是自然环境中全局的光线
//平行光是方向光类似于太阳光,主要用来模拟阴影
var ambient, directional
// 光源
function initLight() {
// 环境光AmbientLight,影响整个场景的光源
ambient = new THREE.AmbientLight(0xffffff, 1)
ambient.name = '环境光'
scene.add(ambient)
// 平行光DirectionalLight,模拟太阳光,用于渲染阴影
directional = new THREE.DirectionalLight(0xffffff, 1.2, 100) // 模拟远处类似太阳的光源
directional.name = '平行光'
directional.position.set(directionalx1, directionaly1, directionalz1)
directional.castShadow = true// 告诉平行光需要开启阴影投射
directional.shadowDarkness = 1
directional.shadow.mapSize.width = 512 * 4// 阴影分辨率,默认512
directional.shadow.mapSize.height = 512 * 4
// 平行光范围
directional.shadow.camera.left = -directionalvalue
directional.shadow.camera.right = directionalvalue
directional.shadow.camera.top = directionalvalue
directional.shadow.camera.bottom = -directionalvalue
directional.shadow.camera.near = 0.5
directional.shadow.camera.far = 1500
directional.shadow.bias = 0.0001// 阴影偏移,否则会有阴影锯齿出现,阴影条纹,嗯写过的人应该都遇到过,很恶心的东西,可以用这个bias稍作偏移,具体参数调整起来比较烦
scene.add(directional)
// 平行光辅助线,添加辅助线后可以看到平行光笼罩的范围,用于细节调整
const directionalhelper = new THREE.CameraHelper(directional.shadow.camera)
directionalhelper1.visible = true
// 平时不用,注掉这个add
scene.add(directionalhelper)
}
六、初始化所有组件:
创建一个函数,把所有组件放进去一起加载,这么写呢,主要是方便后期增补或者修改一些内容,这么做比较方便,毕竟商务和产品每次都说这个东西三天或者五天必须给出来,写的太乱了后期不好改。
// 初始化
function init() {
initScene()// 基础场景
initCamera()// 相机
initRenderer()// 渲染器
initControls()// 控制器
initLight()// 光源
}
init()//直接执行,或者HTML直接加onload
七、渲染:
// 循环渲染页面场景
function render() {
update()
requestAnimationFrame(render)// 执行一个动画.并在动画执行后重新渲染
// 传统渲染器,如果使用shader着色器,则注掉这个,增加效果合成器,增加通道渲染
renderer.render(scene, camera)
}
八、完整代码:
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
var scene, camera, controls, renderer, ambient, directional
// 天空盒是以正方体6面结构贴图[贴图顺序:右、左、上、下、前、后]
var urls = [
'./static/skyBox/day/px.jpg',
'./static/skyBox/day/nx.jpg',
'./static/skyBox/day/py.jpg',
'./static/skyBox/day/ny.jpg',
'./static/skyBox/day/pz.jpg',
'./static/skyBox/day/nz.jpg'
]
//初始化一个场景
function initScene() {
// 实例化一个场景
scene = new THREE.Scene()
// 整个场景的颜色
scene.background = new THREE.Color( 0x000000 )
// 6图天空盒子[贴图顺序:右、左、上、下、前、后]
scene.background = new THREE.CubeTextureLoader().load(urls)
}
// 初始化相机
function initCamera() {
//实例化一个相机,内部参数(角度,div的宽/div的高,距离视野中心最近距离,同前最远距离)
//角度:类似于手机狭角、广角的效果
//画面比例:div的宽高自己定义,全屏展示的话就按照官网给的window.innerWidth/window.innerHeight即可
//视野最大(小)远近距离根据自身项目来定
camera = new THREE.PerspectiveCamera(60,
document.getElementById('threecanvas').offsetWidth / document.getElementById('threecanvas').offsetHeight, 2, 5000)
camera.position.set(0, 100, -100)//相机位置
camera.lookAt(new THREE.Vector3(0, 0, 0))// 相机视野中心
//相机所展示画面的比例
camera.aspect = document.getElementById('threecanvas').offsetWidth / document.getElementById('threecanvas').offsetHeight
//更新相机投影变换矩阵
camera.updateProjectionMatrix()
//将相机加入到场景中
scene.add(camera)
}
// 初始化渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer({
alpha: false,// 是否可以设置背景色透明
antialias: true, // 抗锯齿
logarithmicDepthBuffer: true, // 图层叠加闪烁问题
precision: 'lowp', // 着色器精度
preserveDrawingBuffer: true, // 开启图层缓冲区
autoClear: true
})
renderer.setPixelRatio(window.devicePixelRatio)// 设置分辨率与电脑的分辨率相同
renderer.setSize(document.getElementById('threecanvas').offsetWidth, document.getElementById('threecanvas').offsetHeight)
renderer.shadowMap.enabled = true// 渲染器渲染阴影效果
renderer.shadowMap.type = THREE.PCFSoftShadowMap// 阴影类型
renderer.outputEncoding = THREE.sRGBEncoding// 色域,鲜明渲染,常规rgb颜色渲染
// 把这个canvas渲染到指定div里,不指定div则把setSize指定宽高
document.getElementById('threecanvas').appendChild(renderer.domElement)
}
// 初始化控制器
function initControls() {
controls = new OrbitControls(camera, renderer.domElement)
controls.listenToKeyEvents(window)//监听操作,具体有哪些可以去底层扒一扒
controls.enableDamping = true// 开启控制阻尼,是否有惯性
controls.dampingFactor = 0.05 // 阻尼强度,鼠标拖拽旋转灵敏度
controls.enableZoom = true// 是否可以缩放
controls.minDistance = 2// 相机距离原点最近距离
controls.maxDistance = 1000// 相机距离原点最远距离
controls.enablePan = true // 是否开启右键拖拽
controls.maxPolarAngle = Math.PI / 2.05 // 最大角度,实际项目中一些模型限制视角到地下
controls.screenSpacePanning = false //false时只能前后左右平移,不能上下平移,true时哪个方向都可以
controls.target = new THREE.Vector3(0, 0, 0)// 设置控制器的旋转原点
}
// 更新,实时渲染的时候加进去,有控制交互,就渲染
function update() {
controls.update()
}
// 光源
function initLight() {
// 环境光AmbientLight,影响整个场景的光源
ambient = new THREE.AmbientLight(0xffffff, 1)
ambient.name = '环境光'
scene.add(ambient)
// 平行光DirectionalLight,模拟太阳光,用于渲染阴影
directional = new THREE.DirectionalLight(0xffffff, 1.2, 100) // 模拟远处类似太阳的光源
directional.name = '平行光'
directional.position.set(directionalx1, directionaly1, directionalz1)
directional.castShadow = true// 告诉平行光需要开启阴影投射
directional.shadowDarkness = 1
directional.shadow.mapSize.width = 512 * 4// 阴影分辨率,默认512
directional.shadow.mapSize.height = 512 * 4
// 平行光范围
directional.shadow.camera.left = -directionalvalue
directional.shadow.camera.right = directionalvalue
directional.shadow.camera.top = directionalvalue
directional.shadow.camera.bottom = -directionalvalue
directional.shadow.camera.near = 0.5
directional.shadow.camera.far = 1500
directional.shadow.bias = 0.0001// 阴影偏移,否则会有阴影锯齿出现,阴影条纹,嗯写过的人应该都遇到过,很恶心的东西,可以用这个bias稍作偏移,具体参数调整起来比较烦
scene.add(directional)
// 平行光辅助线,添加辅助线后可以看到平行光笼罩的范围,用于细节调整
const directionalhelper = new THREE.CameraHelper(directional.shadow.camera)
directionalhelper1.visible = true
// 平时不用,注掉这个add
scene.add(directionalhelper)
}
// 初始化
function init() {
initScene()// 基础场景
initCamera()// 相机
initRenderer()// 渲染器
initControls()// 控制器
initLight()// 光源
}
// 循环渲染页面场景
function render() {
update()
requestAnimationFrame(render)// 执行一个动画.并在动画执行后重新渲染
// 传统渲染器,如果使用shader着色器,则注掉这个,增加效果合成器,增加通道渲染
renderer.render(scene, camera)
}
init()
render()
个人写的vue,分开function函数,原生HTML和vue都能用,包括小程序,可以单独把代码提取成js,使用export{…}导出属性或方法函数,直接在页面import引入即可。
正好今天又修改模型改动代码,重构的时候把代码扣出来,一边整合代码,一边写博客,可能时间有限,写的比较拉。