使用CubeCamera創建反光效果
- 1.demo效果
- 2. 實作要點
- 2.1 創建立方體相機CubeCamera
- 2.2 使用動態環境貼圖材質
- 2.3 render中更新立方體相機
- 2.4 創建場景的全景貼圖
- 2.5 創建場景中的模型
- 3. demo代碼
1.demo效果



2. 實作要點
2.1 創建立方體相機CubeCamera
創建立方體的語法如下
const cubeCamera = new THREE.CubeCamera( near, far, cubeRenderTarget)
引數說明
- near – 遠剪切面的距離
- far – 近剪切面的距離
- cubeRenderTarget – 立方體渲染器目標物件
如上引數可知創建CubeCamera物件需要三個引數,其中第三個引數是一個WebGLCubeRenderTarget 型別的物件,所以需要首先創建這樣一個物件,然后創建立方體物件,具體代碼如下:
//創建立方體渲染器目標物件
this.cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
format: THREE.RGBFormat,
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter
})
//創建立方體相機
this.cubeCamera = new THREE.CubeCamera(1, 100000, this.cubeRenderTarget)
this.scene.add(this.cubeCamera)
2.2 使用動態環境貼圖材質
上一步中我們創建完立方體相機后,立方體渲染器目標物件上邊生成了有相機獲取的圖形生成的紋理,并保存在cubeRenderTarget.texture之中,接下來把它當環境貼圖創建材質,隨后使用這個材質創建一個球體Mesh
//創建球體
this.renderer.renderTarget
const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
envMap: this.cubeRenderTarget.texture
})
const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
this.scene.add(this.sphere)
2.3 render中更新立方體相機
this.cubeCamera.update(this.renderer, this.scene) //立方體相機更新
通過以上三步就可以實作將場景中除球體以外的所有模型作為環境貼圖添加到球體上,支持動態變化,除此之外還有幾點需要說明一下,具體詳見以下步驟
2.4 創建場景的全景貼圖
這一步與上一篇文章一樣,代碼如下
// 創建場景
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.5 創建場景中的模型
模型包括一個立方體和一個球體,要注意一下幾點
- 創建靜態環境貼圖材質
這里就是使用場景的背景創建環境貼圖材質,只需要將場景的背景賦值給材質的envMap即可 - 創建方塊和圓環
這里使用BoxGeometry創建一個立方體模型,使用TorusGeometry創建一個圓環,它們使用的材質都是剛剛創建的環境貼圖材質 - 創建動態環境貼圖的球體
這里文章中 2.2 已有說明,請直接看代碼
// 創建模型
createModels() {
const material = new THREE.MeshPhongMaterial()
material.envMap = this.scene.background //場景背景設定為材質的環境貼圖
//創建方塊
const boxGeometry = new THREE.BoxGeometry(15, 15, 15)
this.cube = new THREE.Mesh(boxGeometry, material)
this.cube.position.set(-22, 0, 0)
this.scene.add(this.cube)
//構建圓環
const torusGeometry = new THREE.TorusGeometry(8, 3, 16, 100)
this.torus = new THREE.Mesh(torusGeometry, material)
this.torus.position.set(22, 0, 0)
this.scene.add(this.torus)
//創建球體
this.renderer.renderTarget
const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
envMap: this.cubeRenderTarget.texture
})
const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
this.scene.add(this.sphere)
}
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,
torus: null,
camera: null,
cubeCamera: null,
cubeRenderTarget: null,
scene: null,
renderer: null,
controls: null
}
},
mounted() {
this.init()
},
methods: {
formatTooltip(val) {
return val
},
// 初始化
async init() {
this.createScene() // 創建場景
await this.createRender() // 創建渲染器
this.createCamera() // 創建相機
this.createLight() // 創建光源
this.createModels() // 創建模型
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(15, 15, 15)
this.cube = new THREE.Mesh(boxGeometry, material)
this.cube.position.set(-22, 0, 0)
this.scene.add(this.cube)
//構建圓環
const torusGeometry = new THREE.TorusGeometry(8, 3, 16, 100)
this.torus = new THREE.Mesh(torusGeometry, material)
this.torus.position.set(22, 0, 0)
this.scene.add(this.torus)
//創建球體
this.renderer.renderTarget
const dynamicEnvMapMaterial = new THREE.MeshPhongMaterial({
envMap: this.cubeRenderTarget.texture
})
const sphereGeometry = new THREE.SphereGeometry(10, 15, 15)
this.sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMapMaterial)
this.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, 50, 50)
spotLight.intensity = 2.2
this.scene.add(spotLight)
},
// 創建相機
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)
const renderTarget = this.renderer.getRenderTarget()
//創建立方體渲染器目標物件
this.cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
format: THREE.RGBFormat,
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter
})
//創建立方體相機
this.cubeCamera = new THREE.CubeCamera(1, 100000, this.cubeRenderTarget)
this.scene.add(this.cubeCamera)
},
// 創建渲染器
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.PCFSoftShadowMap
this.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 = texture
const 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.torus.material = this.cube.material.clone()
//更新模型的材質折射率
this.cube.material.reflectivity = this.properties.reflectivity.value
this.torus.material.reflectivity = this.properties.reflectivity.value
//更新材質中的紋理
this.cube.material.needsUpdate = true
this.torus.material.needsUpdate = true
},
//模型旋轉更新
updateRotation() {
if (this.properties.rotate) {
this.cube.rotation.x += 0.01
this.cube.rotation.y += 0.01
this.torus.rotation.x += 0.01
this.torus.rotation.y += 0.01
}
},
render() {
requestAnimationFrame(this.render)
this.updateRotation() //模型旋轉更新
this.cubeCamera.update(this.renderer, this.scene) //立方體相機更新
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>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/286332.html
標籤:其他
下一篇:SpringBoot + Layui + Mysql + Flutter (PC + 移動端)實作大學課程平時成績管理
