1
- import React , { useEffect , useRef } from 'react'
1
+ import React , { useEffect , useRef , useState } from 'react'
2
2
import * as THREE from 'three'
3
3
// 导入轨道控制器
4
4
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
@@ -9,7 +9,9 @@ import styles from './car.module.scss'
9
9
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
10
10
// 导入draco解码器
11
11
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
12
+ import { Col , Radio , RadioChangeEvent , Row } from 'antd'
12
13
const Car = ( ) => {
14
+ const [ count , setCount ] = useState ( 0 )
13
15
const canvasDom = useRef < HTMLDivElement > ( null )
14
16
// 创建场景
15
17
const scene = new THREE . Scene ( )
@@ -47,15 +49,24 @@ const Car = () => {
47
49
// 更新相机投影矩阵
48
50
camera . updateProjectionMatrix ( )
49
51
}
52
+ let requestAnimation : number
50
53
function render ( ) {
51
- controller . update ( )
54
+ controller && controller . update ( )
52
55
renderer . render ( scene , camera )
53
- requestAnimationFrame ( render )
56
+ requestAnimation = window . requestAnimationFrame ( render )
54
57
}
55
58
56
- let wheels = [ ]
59
+ let wheels : THREE . Mesh [ ] = [ ]
57
60
// 车身,车前脸,引擎盖,挡风玻璃
58
- let carBody , frontCar , hoodCar , glassCar
61
+ let carBody : THREE . Mesh <
62
+ THREE . BufferGeometry < THREE . NormalBufferAttributes > ,
63
+ THREE . Material | THREE . Material [ ] ,
64
+ THREE . Object3DEventMap
65
+ > ,
66
+ frontCar ,
67
+ hoodCar ,
68
+ glassCar
69
+
59
70
// 创建材质
60
71
// 车身物理材质
61
72
const bodyMaterial = new THREE . MeshPhysicalMaterial ( {
@@ -65,21 +76,46 @@ const Car = () => {
65
76
clearcoat : 1 , // 清漆
66
77
clearcoatRoughness : 0 // 清漆粗糙度
67
78
} )
79
+
80
+ const frontMaterial = new THREE . MeshPhysicalMaterial ( {
81
+ color : 0xff0000 ,
82
+ metalness : 1 , // 金属度
83
+ roughness : 0.5 , // 粗糙程度
84
+ clearcoat : 1 , // 清漆
85
+ clearcoatRoughness : 0 // 清漆粗糙度
86
+ } )
87
+ const hoodMaterial = new THREE . MeshPhysicalMaterial ( {
88
+ color : 0xff0000 ,
89
+ metalness : 1 , // 金属度
90
+ roughness : 0.5 , // 粗糙程度
91
+ clearcoat : 1 , // 清漆
92
+ clearcoatRoughness : 0 // 清漆粗糙度
93
+ } )
94
+ const wheelsMaterial = new THREE . MeshPhysicalMaterial ( {
95
+ color : 0xff0000 ,
96
+ metalness : 1 , // 金属度
97
+ roughness : 0.1 // 粗糙程度
98
+ } )
99
+ const glassMaterial = new THREE . MeshPhysicalMaterial ( {
100
+ color : 0xffffff ,
101
+ metalness : 0 ,
102
+ transmission : 1 , // 透明度
103
+ transparent : true ,
104
+ roughness : 0
105
+ } )
106
+ // 初始化渲染器,渲染背景
107
+ renderer . setClearColor ( '#000' )
108
+ scene . background = new THREE . Color ( '#ccc' )
109
+ render ( )
110
+ // 添加网格地面
111
+ const gridHelper = new THREE . GridHelper ( )
112
+ gridHelper . material . opacity = 0.2
113
+ gridHelper . material . transparent = true
114
+ scene . add ( gridHelper )
115
+ // // 实例化加载器gltf
116
+
68
117
useEffect ( ( ) => {
69
118
canvasDom . current ! . appendChild ( renderer . domElement )
70
- onresize ( )
71
- window . addEventListener ( 'resize' , onresize )
72
- // 初始化渲染器,渲染背景
73
- renderer . setClearColor ( '#000' )
74
- scene . background = new THREE . Color ( '#ccc' )
75
- render ( )
76
- // 添加网格地面
77
- const gridHelper = new THREE . GridHelper ( )
78
- gridHelper . material . opacity = 0.2
79
- gridHelper . material . transparent = true
80
- scene . add ( gridHelper )
81
-
82
- // 实例化加载器gltf
83
119
const gltfLoader = new GLTFLoader ( )
84
120
// 实例化加载器draco
85
121
const dracoLoader = new DRACOLoader ( )
@@ -92,26 +128,31 @@ const Car = () => {
92
128
'/models/bmw01.glb' ,
93
129
// 加载完成回调
94
130
( gltf ) => {
95
- console . log ( gltf )
96
131
const bmw = gltf . scene
97
132
scene . add ( bmw )
98
133
bmw . traverse ( ( child ) => {
99
134
if ( ( child as THREE . Mesh ) ?. isMesh ) {
100
135
if ( child . name . includes ( '轮毂' ) ) {
101
- wheels . push ( child )
136
+ wheels . push ( child as THREE . Mesh )
137
+ wheels . forEach ( ( child ) => {
138
+ child . material = wheelsMaterial
139
+ } )
102
140
}
103
141
if ( child . name . includes ( 'Mesh002' ) ) {
104
142
carBody = child as THREE . Mesh
105
143
carBody . material = bodyMaterial
106
144
}
107
145
if ( child . name . includes ( '前脸' ) ) {
108
146
frontCar = child as THREE . Mesh
147
+ frontCar . material = frontMaterial
109
148
}
110
149
if ( child . name . includes ( '引擎盖_1' ) ) {
111
150
hoodCar = child as THREE . Mesh
151
+ hoodCar . material = hoodMaterial
112
152
}
113
153
if ( child . name . includes ( '挡风玻璃' ) ) {
114
154
glassCar = child as THREE . Mesh
155
+ glassCar . material = glassMaterial
115
156
}
116
157
}
117
158
} )
@@ -146,14 +187,89 @@ const Car = () => {
146
187
const light9 = new THREE . DirectionalLight ( 0xffffff , 1 )
147
188
light9 . position . set ( - 5 , 10 , 0 )
148
189
scene . add ( light9 )
190
+ return ( ) => {
191
+ window . cancelAnimationFrame ( requestAnimation )
192
+ }
193
+ } , [ ] )
194
+
195
+ useEffect ( ( ) => {
196
+ onresize ( )
197
+ window . addEventListener ( 'resize' , onresize )
149
198
return ( ) => {
150
199
window . removeEventListener ( 'resize' , onresize )
151
200
}
152
201
} )
202
+ interface GlassMaterialItem {
203
+ label : string
204
+ value : number
205
+ }
206
+ const bodyColors = [ 'red' , 'blue' , 'green' , 'gray' , 'orange' , 'purple' ]
207
+ const glassMaterials : GlassMaterialItem [ ] = [
208
+ {
209
+ label : '磨砂' ,
210
+ value : 1
211
+ } ,
212
+ {
213
+ label : '冰晶' ,
214
+ value : 0
215
+ }
216
+ ]
217
+ const [ currentColor , setCurrentColor ] = useState ( 'red' )
218
+ const [ currentGlassMaterial , setCurrentGlassMaterial ] = useState ( 0 )
219
+
220
+ function onGlassChange ( e : RadioChangeEvent ) {
221
+ // setCurrentGlassMaterial(e.target.value)
222
+ bodyMaterial . clearcoatRoughness = e . target . value
223
+ frontMaterial . clearcoatRoughness = e . target . value
224
+ hoodMaterial . clearcoatRoughness = e . target . value
225
+ }
226
+ function onColorChange ( color : string ) {
227
+ // setCurrentColor(color)
228
+ bodyMaterial . color . set ( color )
229
+ frontMaterial . color . set ( color )
230
+ hoodMaterial . color . set ( color )
231
+ wheelsMaterial . color . set ( color )
232
+ }
153
233
return (
154
- < div className = "page-container" >
155
- { import . meta. env . PUBLIC_URL }
156
- < div className = { styles . canvasContainer } ref = { canvasDom } > </ div >
234
+ < div className = "page-container" style = { { position : 'relative' } } >
235
+ < div
236
+ id = "canvasDom"
237
+ className = { styles . canvasContainer }
238
+ ref = { canvasDom }
239
+ > </ div >
240
+ < div className = { styles . selector } >
241
+ < div className = { styles . selectorTitle } > 汽车展示与选配</ div >
242
+ < div className = { styles . selectorTitleSecond } > 选择车身颜色</ div >
243
+ < div className = { styles . colorBox } >
244
+ < Row gutter = { 20 } >
245
+ { bodyColors . map ( ( color , index ) => {
246
+ return (
247
+ < Col key = { index } >
248
+ < div
249
+ onClick = { ( ) => onColorChange ( color ) }
250
+ style = { {
251
+ backgroundColor : color
252
+ } }
253
+ className = {
254
+ styles . colorItem +
255
+ ' ' +
256
+ ( currentColor == color ? styles . currentColor : '' )
257
+ }
258
+ > </ div >
259
+ </ Col >
260
+ )
261
+ } ) }
262
+ </ Row >
263
+ </ div >
264
+ < div className = { styles . selectorTitleSecond } > 选择贴膜材质</ div >
265
+ < Radio . Group
266
+ options = { glassMaterials }
267
+ onChange = { onGlassChange }
268
+ value = { currentGlassMaterial }
269
+ optionType = "button"
270
+ buttonStyle = "solid"
271
+ />
272
+ </ div >
157
273
</ div >
158
274
)
159
275
}
0 commit comments