Three.js 中的 Reflector 类
Posted 脉望
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Three.js 中的 Reflector 类相关的知识,希望对你有一定的参考价值。
说明
Reflector 是 three.js 中的一个类,用于创建反射效果的对象。它继承自 Mesh,可以添加到场景中作为一个可渲染的物体。
Reflector 的构造函数如下:
constructor(geometry?: BufferGeometry, options?: ReflectorOptions)
其中,geometry 参数是可选的,用于指定 Reflector 的几何形状。options 参数也是可选的,是一个配置选项对象,包含以下属性:
color
: 反射面的颜色,可以是一个 CSS 颜色字符串或是一个 three.js 的 Color 对象,默认值是 0x7F7F7F。textureWidth
: 反射纹理的宽度,单位是像素,默认值是 512。textureHeight
: 反射纹理的高度,单位是像素,默认值是 512。clipBias
: 剪裁偏移值,用于控制剪裁平面的位置,可以用于解决渲染的反射对象和原始对象之间的闪烁问题,默认值是 0。shader
: 用于渲染反射效果的着色器程序,可以是一个 three.js 的 ShaderMaterial 对象,默认值是 undefined,表示使用内置的着色器。encoding
: 反射纹理的编码格式,默认值是 LinearEncoding。multisample
: 反射纹理的多重采样级别,用于抗锯齿,默认值是 0,表示不使用多重采样。
Reflector 对象有以下方法:
getRenderTarget()
: 获取渲染到的反射纹理对象,可以用于后续的处理。dispose()
: 释放 Reflector 对象的资源,包括纹理和几何形状。
Reflector 对象可以通过以下步骤使用:
- 创建一个 Reflector 对象,可以指定几何形状和配置选项。
import Reflector from \'three\';
const geometry = new PlaneBufferGeometry(10, 10);
const options =
color: 0x7F7F7F,
textureWidth: 512,
textureHeight: 512,
clipBias: 0,
shader: undefined,
encoding: LinearEncoding,
multisample: 0
;
const reflector = new Reflector(geometry, options);
- 将 Reflector 对象添加到场景中。
scene.add(reflector);
- 渲染场景,并将渲染结果显示到屏幕上。
renderer.render(scene, camera);
Reflector 对象会根据设置的几何形状和配置选项,在指定位置渲染反射效果,可以通过调整配置选项来控制反射效果的外观和行为。当不再需要使用 Reflector 对象时,可以调用 dispose()
方法来释放资源。
示例:
效果:
代码:
<template>
<div ref="containerRef" class="container"></div>
</template>
<script setup>
import * as THREE from \'three\'
import useRoute from \'vue-router\'
import onMounted, ref, onUnmounted from \'vue\'
import OrbitControls from \'three/examples/jsm/controls/OrbitControls.js\'
import Reflector from \'three/examples/jsm/objects/Reflector.js\'
// import EffectComposer from \'three/examples/jsm/postprocessing/EffectComposer.js\'
// import RenderPass from \'three/examples/jsm/postprocessing/RenderPass.js\'
// import UnrealBloomPass from \'three/examples/jsm/postprocessing/UnrealBloomPass.js\'
const route = useRoute()
document.title = route.meta.title
const containerRef = ref(null)
let camera, scene, renderer
let cameraControls
let sphereGroup, smallSphere
let groundMirror, verticalMirror
THREE.ColorManagement.enabled = true
// renderer
renderer = new THREE.WebGLRenderer( antialias: true )
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
// scene
scene = new THREE.Scene()
// camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500)
camera.position.set(0, 75, 160)
cameraControls = new OrbitControls(camera, renderer.domElement)
cameraControls.target.set(0, 40, 0)
cameraControls.maxDistance = 400
cameraControls.minDistance = 10
cameraControls.update()
const planeGeo = new THREE.PlaneGeometry(100.1, 100.1)
// reflectors/mirrors
let geometry, material
geometry = new THREE.CircleGeometry(40, 64)
groundMirror = new Reflector(geometry,
clipBias: 0.003,
textureWidth: window.innerWidth * window.devicePixelRatio,
textureHeight: window.innerHeight * window.devicePixelRatio,
color: \'#b5b5b5\'
)
groundMirror.position.y = 0.5
groundMirror.rotateX(- Math.PI / 2)
scene.add(groundMirror)
geometry = new THREE.PlaneGeometry(100, 100)
verticalMirror = new Reflector(geometry,
clipBias: 0.003,
textureWidth: window.innerWidth * window.devicePixelRatio,
textureHeight: window.innerHeight * window.devicePixelRatio,
color: \'#c1cbcb\'
)
verticalMirror.position.y = 50
verticalMirror.position.z = - 50
scene.add(verticalMirror)
sphereGroup = new THREE.Object3D()
scene.add(sphereGroup)
geometry = new THREE.CylinderGeometry(0.1, 15 * Math.cos(Math.PI / 180 * 30), 0.1, 24, 1)
material = new THREE.MeshPhongMaterial( color: 0xffffff, emissive: \'#8d8d8d\' )
const sphereCap = new THREE.Mesh(geometry, material)
sphereCap.position.y = - 15 * Math.sin(Math.PI / 180 * 30) - 0.05
sphereCap.rotateX(- Math.PI)
geometry = new THREE.SphereGeometry(15, 24, 24, Math.PI / 2, Math.PI * 2, 0, Math.PI / 180 * 120)
const halfSphere = new THREE.Mesh(geometry, material)
halfSphere.add(sphereCap)
halfSphere.rotateX(- Math.PI / 180 * 135)
halfSphere.rotateZ(- Math.PI / 180 * 20)
halfSphere.position.y = 7.5 + 15 * Math.sin(Math.PI / 180 * 30)
sphereGroup.add(halfSphere)
geometry = new THREE.IcosahedronGeometry(5, 0)
material = new THREE.MeshPhongMaterial( color: 0xffffff, emissive: \'#7b7b7b\', flatShading: true )
smallSphere = new THREE.Mesh(geometry, material)
scene.add(smallSphere)
// walls
const planeTop = new THREE.Mesh(planeGeo, new THREE.MeshPhongMaterial( color: 0xffffff ))
planeTop.position.y = 100
planeTop.rotateX(Math.PI / 2)
scene.add(planeTop)
const planeBottom = new THREE.Mesh(planeGeo, new THREE.MeshPhongMaterial( color: 0xffffff ))
planeBottom.rotateX(- Math.PI / 2)
scene.add(planeBottom)
const planeFront = new THREE.Mesh(planeGeo, new THREE.MeshPhongMaterial( color: 0xbbbbfe ))
planeFront.position.z = 50
planeFront.position.y = 50
planeFront.rotateY(Math.PI)
scene.add(planeFront)
const planeRight = new THREE.Mesh(planeGeo, new THREE.MeshPhongMaterial( color: 0x00ff00 ))
planeRight.position.x = 50
planeRight.position.y = 50
planeRight.rotateY(- Math.PI / 2)
scene.add(planeRight)
const planeLeft = new THREE.Mesh(planeGeo, new THREE.MeshPhongMaterial( color: 0xff0000 ))
planeLeft.position.x = - 50
planeLeft.position.y = 50
planeLeft.rotateY(Math.PI / 2)
scene.add(planeLeft)
// lights
const mainLight = new THREE.PointLight(\'#e7e7e7\', 1.5, 250)
mainLight.position.y = 60
scene.add(mainLight)
const greenLight = new THREE.PointLight(\'#00ff00\', 0.25, 1000)
greenLight.position.set(550, 50, 0)
scene.add(greenLight)
const redLight = new THREE.PointLight(\'#ff0000\', 0.25, 1000)
redLight.position.set(- 550, 50, 0)
scene.add(redLight)
const blueLight = new THREE.PointLight(\'#bbbbfe\', 0.25, 1000)
blueLight.position.set(0, 50, 550)
scene.add(blueLight)
// 后期模糊处理
/* const composer = new EffectComposer(renderer)
const renderPass = new RenderPass(scene, camera)
composer.addPass(renderPass)
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.5, 0.4, 0.85)
composer.addPass(bloomPass) */
function animate()
requestAnimationFrame(animate)
const timer = Date.now() * 0.01
sphereGroup.rotation.y -= 0.002
smallSphere.position.set(
Math.cos(timer * 0.1) * 30,
Math.abs(Math.cos(timer * 0.2)) * 20 + 5,
Math.sin(timer * 0.1) * 30
)
smallSphere.rotation.y = (Math.PI / 2) - timer * 0.1
smallSphere.rotation.z = timer * 0.8
renderer.render(scene, camera)
// composer.render()
function onWindowResize()
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
groundMirror.getRenderTarget().setSize(
window.innerWidth * window.devicePixelRatio,
window.innerHeight * window.devicePixelRatio
)
verticalMirror.getRenderTarget().setSize(
window.innerWidth * window.devicePixelRatio,
window.innerHeight * window.devicePixelRatio
)
onMounted(() =>
containerRef.value.appendChild(renderer.domElement)
animate()
window.addEventListener(\'resize\', onWindowResize)
)
onUnmounted(() =>
window.removeEventListener(\'resize\', onWindowResize)
)
</script>
Three.js 中的 BoxBufferGeometry 与 BoxGeometry 有啥区别?
【中文标题】Three.js 中的 BoxBufferGeometry 与 BoxGeometry 有啥区别?【英文标题】:What is difference between BoxBufferGeometry vs BoxGeometry in Three.js?Three.js 中的 BoxBufferGeometry 与 BoxGeometry 有什么区别? 【发布时间】:2018-10-02 01:02:40 【问题描述】:我正在学习 Three.js。我找不到关于 BoxBufferGeometry 与 BoxGeometry 之间区别的正确答案。帮帮我。
【问题讨论】:
【参考方案1】:[Primitive]Geometry
类对所有 JS 几何类的操作友好,内存不友好。
这意味着定义此几何图形的每条数据都存储为某个类的实例 (Vector3
,Vector2
,Face3
) 等。这些带有方便的方法,因此您可以点一个顶点使用其他向量,平移顶点,修改 uvs,修改法线等。但它在内存和性能方面有开销(创建所有这些实例,存储它们)。
[Primitive]BufferGeometry
类是性能友好的几何类,它们依赖于类型化数组以 WebGL 友好的格式存储数据。
这意味着顶点不是Vector3
s 的数组,而是类型化数组:
Array[v0,v1... vN]
vs:
Float32Array[v0x,v0y,v0z,v1x,v1y,v1z... vNx,vNy,vNz]
它们的存储效率更高,但更难操作。
如果你想修改一个顶点:
与Geometry
//with Geometry you just get vertex 5 and have access to it's x...
//AND the methods of the class -> Vector3.add(Vector3)
myGeom.vertices[5].add(new THREE.Vector3(1,2,3))
与BufferGeometry
//xyz are just numbers, so with a stride of 3
//we select x , and then the next two for y and z
//we have to know that the 15th number in this array is x of vertex 5...
const stride = 3
const index = 5
let offset = index * stride
myGeom.attributes.position.array[offset++] += 1
myGeom.attributes.position.array[offset++] += 2
myGeom.attributes.position.array[offset ] += 3
但是
THREE.BufferAttribute
确实有几种方法可以从该数组中写入和读取内容。它仍然更加冗长:
//add x: 1 y: 2 z: 3 to 5th vertex
const index = 5
const attribute = myGeometry.attributes.position
const v3add = new THREE.Vector3(1,2,3)
attribute.setXYZ(
index,
attribute.getX(index) + v3add.x,
attribute.getY(index) + v3add.y,
attribute.getZ(index) + v3add.z
)
【讨论】:
虽然更容易阅读,但我倾向于说BufferGeometry
更改示例是不正确的。 1) 标准[Primitive]BufferGeometry
对象的顶点存储在myGeom.attributes.position
中。除非您为自定义着色器添加自定义属性,否则没有 vertices
属性。 2) 您仍然可以通过索引获取和设置值,只是有点冗长。 var pos = myGeom.attributes.position; pos.setXYZ(5, pos.getX(5) + 1, pos.getY(5) + 2, pos.getZ(5) + 3);
.
这个答案有多个错误,@pailhead 更清楚。
请编辑一下,这主要是伪代码,add(1,2,3)
也没有意义。
这个想法是从概念上解释差异,而不是给出确切的名称和属性。这里的重要概念是数组本身,而不是它所在的位置,但我已经编辑了答案。【参考方案2】:
@Pailhead 的回答是正确的。如果您需要以某种方式修改盒子.. 通过移动它的顶点或更改 texcoords,操作 BoxGeometry 会更容易,但 BoxBufferGeometry 的渲染效率更高。您可以使用 .fromGeometry 和 .fromBufferGeometry 在类型之间进行转换。
【讨论】:
这确实应该是对 pailhead 答案的评论,而不是单独的答案。以上是关于Three.js 中的 Reflector 类的主要内容,如果未能解决你的问题,请参考以下文章
Three.js 中的“THREE.OrbitControls”中的相机位置变化