贴图创建虚假的反光效果,使用CubeTextureLoader创建全景贴图,使用envMap创建静态环境贴图(vue中使用three.js82)"/>
three.js使用环境贴图创建虚假的反光效果,使用CubeTextureLoader创建全景贴图,使用envMap创建静态环境贴图(vue中使用three.js82)
使用环境贴图创建虚假的反光效果
- 1.demo效果
- 2. 实现要点
- 2.1 创建场景的全景贴图
- 2.2 创建场景中的模型
- 2.3 属性更新处理
- 2.4 模型旋转更新
- 3. demo代码
1.demo效果
2. 实现要点
2.1 创建场景的全景贴图
在创建场景函数中,使用 CubeTextureLoader 创建全景贴图,然后将全景贴图赋值给场景的 background 属性
// 创建场景
createScene() {this.scene = new THREE.Scene()const publicPath = process.env.BASE_URL//创建全景贴图设置为场景背景this.scene.background = new THREE.CubeTextureLoader().setPath(`${publicPath}textures/cubemap/parliament/`).load(['posx.jpg','negx.jpg','posy.jpg','negy.jpg','posz.jpg','negz.jpg'])
}
2.2 创建场景中的模型
模型包括一个立方体和一个球体,要注意一下几点
- 创建材质
创建好材质后把材质的环境贴图 (material.envMap属性) 设置为场景的背景,即上一步创建好的全景贴图 - 创建方块
只需要使用BoxGeometry创建一个立方体模型,然后和上面创建的材质共同创建Mesh对象即可 - 创建球体
使用SphereGeometry创建一个球体模型,这里需要 clone一下材质 ,然后使用克隆的材质和球体模型创建Mesh对象
// 创建模型
createModels() {const material = new THREE.MeshPhongMaterial()material.envMap = this.scene.background //场景背景设置为材质的环境贴图//创建方块const boxGeometry = new THREE.BoxGeometry(10, 15, 15)this.cube = new THREE.Mesh(boxGeometry, material)this.cube.rotation.y = 0.5this.cube.position.x = -12this.cube.position.y = 5this.scene.add(this.cube)//创建球体const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)this.sphere = new THREE.Mesh(sphereGeometry, material.clone()) //材质需要克隆一份,否则方块材质改变球体也会跟着发生改变this.sphere.rotation.y = -0.5this.sphere.position.x = 12this.sphere.position.y = 5this.scene.add(this.sphere)
}
2.3 属性更新处理
为满足demo可以为方块选择不同的纹理贴图和对方块和球体调整反射光折射率,这里需要做一些处理
- 方块纹理处理
如果选择的纹理贴图不是none则加载对应的map贴图和normal贴图,赋值到方块材质的map属性和normalMap属性上,同时设置方块材质的normalScale属性,用来调整法线贴图的凹凸深度,如果没有为方块选择纹理贴图,将方块的材质重置为envMap是场景背景的材质 - 反射光折射率处理
方块和球体都需要处理,将球体和方块各自的材质中的material.reflectivity属性设置为页面中设置的值即可 - 材质更新
由于调整过参数后模型的材质会发生改变,所以需要显示的告诉计算机重新编译材质,将它们材质的material.needsUpdate 属性设置为true
2.4 模型旋转更新
demo中勾选了rotate后,方块可以立方体可以旋转,在这里需要支持一下
//模型旋转更新
updateRotation() {if (this.properties.rotate) {this.cube.rotation.x += 0.01this.cube.rotation.y += 0.01this.sphere.rotation.y -= 0.01}
}
3. demo代码
<template><div><div id="container" /><div class="controls-box"><section><el-row><el-checkbox v-model="properties.rotate">rotate</el-checkbox></el-row><el-row><div v-for="(item,key) in properties" :key="key"><div v-if="item&&item.name!=undefined"><el-col :span="8"><span class="vertice-span">{{ item.name }}</span></el-col><el-col :span="13"><el-slider v-model="item.value" :min="item.min" :max="item.max" :step="item.step" :format-tooltip="formatTooltip" @change="propertiesChange" /></el-col><el-col :span="3"><span class="vertice-span">{{ item.value }}</span></el-col></div></div></el-row><el-row><el-col :span="8" class="label-col"><label>texture</label></el-col><el-col :span="16"><el-select v-model="properties.textureType" placeholder="请选择" @change="propertiesChange"><el-option v-for="item in texturesOptions" :key="item.value" :label="item.label" :value="item.value" /></el-select></el-col></el-row></section></div></div>
</template><script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default {data() {return {texturesOptions: [{value: 'bathroom',label: 'bathroom'},{value: 'plaster',label: 'plaster'},{value: 'metal-floor',label: 'metal-floor'},{value: 'none',label: 'none'}],properties: {normalScale: {name: 'normalScale',value: 1,min: -2,max: 2,step: 0.1},reflectivity: {name: 'reflectivity',value: 1,min: 0,max: 2,step: 0.1},textureType: 'none',rotate: false},cube: null,sphere: null,camera: null,scene: null,renderer: null,controls: null,sphereLightMesh: null,pointLight: null,invert: 1,phase: 0}},mounted() {this.init()},methods: {formatTooltip(val) {return val},// 初始化init() {this.createScene() // 创建场景this.createCamera() // 创建相机this.createLight() // 创建光源this.createModels() // 创建模型this.createRender() // 创建渲染器this.createControls() // 创建控件对象this.render() // 渲染},// 创建场景createScene() {this.scene = new THREE.Scene()const publicPath = process.env.BASE_URL//创建全景贴图设置为场景背景this.scene.background = new THREE.CubeTextureLoader().setPath(`${publicPath}textures/cubemap/parliament/`).load(['posx.jpg','negx.jpg','posy.jpg','negy.jpg','posz.jpg','negz.jpg'])},// 创建模型createModels() {const material = new THREE.MeshPhongMaterial()material.envMap = this.scene.background //场景背景设置为材质的环境贴图//创建方块const boxGeometry = new THREE.BoxGeometry(10, 15, 15)this.cube = new THREE.Mesh(boxGeometry, material)this.cube.rotation.y = 0.5this.cube.position.x = -12this.cube.position.y = 5this.scene.add(this.cube)//创建球体const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)this.sphere = new THREE.Mesh(sphereGeometry, material.clone()) //材质需要克隆一份,否则方块材质改变球体也会跟着发生改变this.sphere.rotation.y = -0.5this.sphere.position.x = 12this.sphere.position.y = 5this.scene.add(this.sphere)},// 创建光源createLight() {// 环境光const ambientLight = new THREE.AmbientLight(0xffffff) // 创建环境光this.scene.add(ambientLight) // 将环境光添加到场景const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯spotLight.position.set(0, 30, 30)spotLight.intensity = 2.2this.scene.add(spotLight)// 点光源const pointColor = '#ff5808'this.pointLight = new THREE.PointLight(pointColor)this.pointLight.intensity = 4.5this.scene.add(this.pointLight)this.createSmallSphereLight()},// 创建球形光源createSmallSphereLight() {const sphereLight = new THREE.SphereGeometry(0.2)const sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25})this.sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial)this.sphereLightMesh.castShadow = true// this.sphereLightMesh.position = new THREE.Vector3(3, 3, 3)this.scene.add(this.sphereLightMesh)},// 创建相机createCamera() {const element = document.getElementById('container')const width = element.clientWidth // 窗口宽度const height = element.clientHeight // 窗口高度const k = width / height // 窗口宽高比// PerspectiveCamera( fov, aspect, near, far )this.camera = new THREE.PerspectiveCamera(45, k, 0.1, 1000)this.camera.position.set(0, 12, 68) // 设置相机位置this.camera.lookAt(new THREE.Vector3(0, 0, 0)) // 设置相机方向this.scene.add(this.camera)},// 创建渲染器createRender() {const element = document.getElementById('container')this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸this.renderer.shadowMap.enabled = true // 显示阴影// this.renderer.shadowMap.type = THREE.PCFSoftShadowMapthis.renderer.setClearColor(0xeeeeee, 1) // 设置背景颜色element.appendChild(this.renderer.domElement)},propertiesChange() {const publicPath = process.env.BASE_URL//如果不为none为方块加载纹理贴图if (this.properties.textureType !== 'none') {const texture = new THREE.TextureLoader().load(`${publicPath}textures/general/` +this.properties.textureType +'.jpg')this.cube.material.map = textureconst normal = new THREE.TextureLoader().load(`${publicPath}textures/general/` +this.properties.textureType +'-normal.jpg')this.cube.material.normalMap = normal// 更新法线缩放this.cube.material.normalScale.set(this.properties.normalScale.value,this.properties.normalScale.value) // normalScale(x,y)} else {this.cube.material = new THREE.MeshPhongMaterial({envMap: this.scene.background})}//更新模型的材质折射率this.cube.material.reflectivity = this.properties.reflectivity.valuethis.sphere.material.reflectivity = this.properties.reflectivity.value//更新材质中的纹理this.cube.material.needsUpdate = truethis.sphere.material.needsUpdate = true},//模型旋转更新updateRotation() {if (this.properties.rotate) {this.cube.rotation.x += 0.01this.cube.rotation.y += 0.01this.sphere.rotation.y -= 0.01}},//球形光运动smallShpereLightAnimation() {if (this.phase > 2 * Math.PI) {this.invert = this.invert * -1this.phase -= 2 * Math.PI} else {this.phase += 0.03}this.sphereLightMesh.position.z = +(21 * Math.sin(this.phase))this.sphereLightMesh.position.x = -14 + 14 * Math.cos(this.phase)if (this.invert < 0) {const pivot = 0this.sphereLightMesh.position.x =this.invert * (this.sphereLightMesh.position.x - pivot) + pivot}this.pointLight.position.copy(this.sphereLightMesh.position) // 把小球光源的坐标复制给点光源},render() {requestAnimationFrame(this.render)this.smallShpereLightAnimation() //球形光位置更新this.updateRotation() //模型旋转更新this.renderer.render(this.scene, this.camera)},// 创建控件对象createControls() {this.controls = new OrbitControls(this.camera, this.renderer.domElement)}}
}
</script><style>
#container {position: absolute;width: 100%;height: 100%;
}
.controls-box {position: absolute;right: 5px;top: 5px;width: 300px;padding: 10px;background-color: #fff;border: 1px solid #c3c3c3;
}
.label-col {padding: 8px 5px;
}.vertice-span {line-height: 38px;padding: 0 2px 0 10px;
}
</style>
更多推荐
three.js使用环境贴图创建虚假的反光效果,使用CubeTextureLoader创建全景贴图,使用envMap创建静态环境贴图(vue中使用three.j
发布评论