geometry(ies) 几何体:
-
BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
width — Width; that is, the length of the edges parallel to the X axis. Optional; defaults to 1.
height — Height; that is, the length of the edges parallel to the Y axis. Optional; defaults to 1.
depth — Depth; that is, the length of the edges parallel to the Z axis. Optional; defaults to 1.
widthSegments — Number of segmented rectangular faces along the width of the sides. Optional; defaults to 1.
heightSegments — Number of segmented rectangular faces along the height of the sides. Optional; defaults to 1.
depthSegments — Number of segmented rectangular faces along the depth of the sides. Optional; defaults to 1.
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe:true })
// 参数 wireframe :线框模式,可以看到geometry后面三个参数设置不同的区别
// BoxGeometry 后面三个参数设置为1, 每一面就划分为2个三角形 triangle, 设置为2 就得到8个
创建自定义集合体
这种方式在r125版本后废弃了, 可以使用 BufferGeometry 实现相同功能
TIPS: buffer geometry 是性能最佳, 对GPU友好的一种 创建几 何体的方式。
1 import * as THREE from 'three'
2 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
3 import gsap from 'gsap'
4 import * as dat from 'dat.gui'
5 // Canvas
6 const canvas = document.querySelector('canvas.webgl')
7
8 // Scene
9 const scene = new THREE.Scene()
10
11
12 // Object
13 const geometry = new THREE.BoxBufferGeometry(1, 1, 1, 2,2,2)
14 // buffer geometry 集合体是性能最佳,最gpu最友好的 geometry。
15 // BoxGeometry 后面三个参数设置为1, 每一面就划分为2个三角形 triangle, 2 就得到八个
16
17 // 自定义一个geometry
18 // const geometry = new THREE.BufferGeometry();
19 // const vertices = new Float32Array([
20 // 0,0,0,
21 // 0,1,0,
22 // 1,0,0
23 // ])
24 // geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
25 const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe:false })
26 const mesh = new THREE.Mesh(geometry, material)
27 scene.add(mesh)
28
29 // define a color object
30 const obj = {
31 color:0xff0000,
32 spin:() => {
33 gsap.to(mesh.rotation, {duration:1, y:mesh.rotation.y + 5})
34 }
35 }
36
37 /* debug gui panel*/
38 const gui = new dat.GUI({
39 closed: true,
40 // 表示一开始 panel 先处于关闭状态
41 // width:400 设置panel width
42 })
43 //gui.hide() // 隐藏gui panel
44
45 gui.add(mesh.position, 'y', -3, 3, 0.01).name('positon-y') // 使用name() 重命名panel item title
46 gui.add(mesh.position, 'x').min(-3).max(3).step(0.01)// 用链式调用的方式也可以!
47 //设置控制mesh y坐标的panel Item,并且规定控制的最大值3,最小值-1, 移动步长为0.01
48
49 //控制 mesh 的属性 ,比如 visible:mesh 是否可见
50 gui.add(mesh, 'visible')
51 gui.add(material,'wireframe')
// dat.gui 改变obj的颜色时,将材质的颜色一并替换
52 gui.addColor(obj, 'color').onChange(() => {
53 material.color.set(obj.color)
54 })
55 gui.add(obj, 'spin')
56 // animation
57 const animations = () => {
58 gsap.to(mesh.position, { duration: 1, delay: 1, x: 2 })
59 gsap.to(mesh.position, { duration: 1, delay: 2, x: 0 })
60 }
61 animations()
62 // Sizes
63 const sizes = {
64 width: window.innerWidth,
65 height: window.innerHeight
66 }
67
68 // Camera
69 const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
70 camera.position.z = 3
71 scene.add(camera)
72
73 // controls
74
75 const controls = new OrbitControls(camera, canvas);
76 controls.enableDamping = true
77 //开启阻尼,也就是惯性, 然后需要在每一帧进行controls.update()
78 //
79 // controls.target.y = 2 //controls target 指向的是对象围绕的焦点
80 // controls.update()
81
82 // Renderer
83 const renderer = new THREE.WebGLRenderer({
84 canvas: canvas
85 })
86 const tick = () => {
87 controls.update()
88 renderer.render(scene, camera)
89 window.requestAnimationFrame(tick)
90 // 动画一定需要配合帧动画请求!!!
91 }
92 tick()
93 let cursor = {
94 x:0,
95 y:0
96 }
97 // 绑定鼠标事件
98 window.addEventListener('mousemove', (event) => {
99 // 这样子会使得x,y 坐标值会归于(-0.5-0.5 这个区间),
100 cursor.x = event.clientX / sizes.width - 0.5
101 cursor.y = -(event.clientY / sizes.height - 0.5)
102 // 不加符号,会使得鼠标上下移动的时候,mesh看起来是跟随鼠标方向的,但是其实移动相机,mesh最终效果是要跟鼠标反向运动(相机向右,以相机为参照物,其实mesh向左)。
103 //camera.position.x = cursor.x
104 //camera.position.y = cursor.y
105
106 // 让相机围绕着mesh 旋转(首先要清楚 这里实现旋转,改变位置的话,是 x和z方向旋转)
107 // camera.position.x = Math.sin(cursor.x * Math.PI * 2) * 3
108 // camera.position.z = Math.cos(cursor.x * Math.PI * 2) * 3
109 // camera.position.y = cursor.y * 6
110 // camera.lookAt(mesh.position)
111 })
112
113 //window resize handle
114 window.addEventListener('resize', () => {
115 sizes.width = window.innerWidth
116 sizes.height = window.innerHeight
117
118 camera.aspect = sizes.width / sizes.height
119 camera.updateProjectionMatrix()
120 //修改相机参数后,需要统计threejs 去更改 projectMatrix, 项目矩阵?
121
122 //renderer 修改画布的size
123 renderer.setSize(sizes.width, sizes.height)
124 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
125 })
126
127 // 绑定全屏事件
128 window.addEventListener('dblclick', () => {
129 // 注意,这个特性,对于 safari 浏览器无效
130 // if(!document.fullscreenElement) {
131 // canvas.requestFullscreen()
132 // }else {
133 // document.exitFullscreen()
134 // }
135
136 //最终兼容写法
137 const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement
138 if(!fullscreenElement) {
139 if(canvas.requestFullscreen) {
140 canvas.requestFullscreen()
141 }else if(canvas.webkitRequestFullscreen) {
142 canvas.webkitRequestFullscreen()
143 }
144 }else {
145 if(document.exitFullscreen) {
146 document.exitFullscreen()
147 }else if(document.webkitExitFullscreen) {
148 document.webkitExitFullscreen()
149 }
150 }
151 })
152
153 renderer.setSize(sizes.width, sizes.height)
154 // 规定渲染器,设定像素比 为1 or 2 有益于性能!!!
155 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
# [threejs-材质(textures)](https://www.cnblogs.com/Hijacku/p/17273355.html "发布于 2023-03-30 16:38")
# what is textures?

UV:

UV coordinate 决定了 材质在mesh上贴 、铺的方式和位置
[](<> "复制代码")
// add texture
// //第一种方式 // const image = new Image(); // const texture = new THREE.Texture(image)
// image.onload = () => { // texture.needsUpdate = true // // 通知texture 更新 // } // image.src = './static/textures/door/color.jpg'
let texture = new THREE.TextureLoader(LoadingManager) // 第二种方式 //可以在TextureLoader中传入loadingmanager const colorTexture2 = texture.load('/static/textures/door/color.jpg', // () => { // console.log('load') // }, // () => { // console.log('load progress') // }, // () => { // console.log('load error') // } // 可以有三个回调函数 ) const alphaTexture = texture.load('/static/textures/door/alpha.jpg') const heightTexture = texture.load('/static/textures/door/height.jpg') const normalTexture = texture.load('/static/textures/door/normal.jpg') const ambientOcclusionTexture = texture.load('/static/textures/door/ambientOcclusion.jpg') const metalnessTexture = texture.load('/stati c/textures/door/metalness.jpg') const roughnessTexture = texture.load('/static/textures/door/roughness.jpg')
/* edit texture (transforming texture) 例如css中的背景重复(repeat) */ // colorTexture2.repeat.x = 2 // colorTexture2.repeat.y = 3 //wrapS x 方向是重复, wrapT y方向上重复(RepeatWrapping) MirroredRepeatWrapping(镜像反转后重复!!) // colorTexture2.wrapS = THREE.MirroredRepeatWrapping // colorTexture2.wrapT = THREE.RepeatWrapping // //texture 偏移 // colorTexture2.offset.x = 0.5 // colorTexture2.offset.y = 0.5 // texture rotation colorTexture2.rotation = Math.PI * 0.25 colorTexture2.center.x = 0.5 colorTexture2.center.y = 0.5
// filtering and mip mapping // colorTexture2.minFilter = THREE.NearestFilter // 如果设置了colorTexture2.minFilter = THREE.NearestFilter // ,可以设置 colorTexture2.generateMipmaps = false 获得好的性能 // 如果一张分辨率很小的贴图,会出现模糊 blurry。 设置magFilter = THREE.NearestFilter, 就会清晰很多 colorTexture2.magFilter = THREE.NearestFilter
// texture format and optimisation(最优化) // 贴图 texture 图片的体积越小越有利于gpu处理 // 贴图尺寸 widthheight 最好是 2的指数倍。 比如 128 256 512 1024 2048... 也就是 512512 512*2048这种尺寸的更利于gpu处理!
/* texture support transparency but we can't have transparency in .jpg,if we want to have only one texture that combine color and alpha, we better use .png file lf we are using a normal texture we want to have the exact values which is why we shouldn't apply lossy compression and we better use .png for those
*/
threejs-css2dObject操作之物体遮挡标签后应该隐藏,而不是出现透视效果
先看coding之前的效果:
这些在背面的标签的,转到一定角度,被模型遮挡后,理论上就不应该被看到。这才是比较符合实际的
coding之后(另一侧对称点就被隐藏):
具体代码(j借助于光线投影):
// 绑定鼠标事件,当用户移动视角后触发()
function bindRayShotEvent() {
document.addEventListener('mouseup', () => {
if (clusterOf2D.value.length > 0) {
clusterOf2D.value.forEach((c: any) => {
raycasterCollsionDetect(c)
})
}
})
}
function raycasterCollsionDetect(wavesLabel: CSS2DObject) {
const labelPosition = wavesLabel.position.clone()
//计算出标签和相机之前的距离(需要看备份一下坐标,不然执行下面转换NDC坐标后,计算会不准)
const labelDistance = labelPosition.distanceTo(camera.value.position)
//转换 向量到从世界空间投影到相机的标准化坐标(NDC)
labelPosition.project(camera.value)
raycaster.setFromCamera(labelPosition, camera.value)
let model = scene!.children.filter(v => {
return v instanceof THREE.Group
})
//过滤出模型
if (model.length == 1) {
const intersects = raycaster.intersectObjects(model[0].children)
if (intersects.length == 0) {
// 如果标签没有被model遮挡,应该全部显示
wavesLabel.element.classList.add('visible')
} else {
const minDistance = intersects[0].distance
if (minDistance < labelDistance) {
// 如果模型到相机的距离小于标签到相机的距离,说明光线射线先经过模型
// 表面此时标签其实在模型的后面,应该被遮挡而看不见
wavesLabel.element.classList.remove('visible')
wavesLabel.element.classList.add('hidden')
} else {
wavesLabel.element.classList.add('visible')
wavesLabel.element.classList.remove('hidden')
}
}
}
}