|
@@ -1,13 +1,22 @@
|
|
-import React, { useCallback, useEffect, useRef } from 'react'
|
|
|
|
|
|
+import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
import styles from './index.module.scss'
|
|
import styles from './index.module.scss'
|
|
|
|
|
|
import * as THREE from 'three'
|
|
import * as THREE from 'three'
|
|
|
|
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
|
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
|
|
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
|
|
-import { USDZLoader } from 'three/addons/loaders/USDZLoader.js'
|
|
|
|
|
|
+import { USDZLoader as USDZLoader1 } from 'three/addons/loaders/USDZLoader.js'
|
|
|
|
+// import { USDZLoader as USDZLoader1 } from 'three/examples/jsm/loaders/USDZLoader.js'
|
|
|
|
+
|
|
|
|
+// import { USDZInstance } from 'three-usdz-loader/lib/USDZInstance'
|
|
|
|
+// import { USDZLoader as USDZLoader2 } from 'three-usdz-loader'
|
|
|
|
+
|
|
|
|
+import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
|
|
|
|
|
|
function A1home() {
|
|
function A1home() {
|
|
|
|
+ // 进度条
|
|
|
|
+ const [loding, setLoding] = useState(0)
|
|
|
|
+
|
|
const camera = useRef(
|
|
const camera = useRef(
|
|
new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100)
|
|
new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100)
|
|
)
|
|
)
|
|
@@ -31,30 +40,115 @@ function A1home() {
|
|
// 获取地址栏参数
|
|
// 获取地址栏参数
|
|
const fileName = window.location.href.split('?m=')[1]
|
|
const fileName = window.location.href.split('?m=')[1]
|
|
|
|
|
|
- camera.current.position.set(0, 0.75, -3.5)
|
|
|
|
|
|
+ if (!fileName) return alert('参数错误')
|
|
|
|
|
|
const rgbeLoader = new RGBELoader().setPath('./modelFile/')
|
|
const rgbeLoader = new RGBELoader().setPath('./modelFile/')
|
|
|
|
|
|
- const usdzLoader = new USDZLoader().setPath('./modelFile/')
|
|
|
|
-
|
|
|
|
- const [texture, model] = await Promise.all([
|
|
|
|
- rgbeLoader.loadAsync(`saeukkang.hdr`),
|
|
|
|
- usdzLoader.loadAsync(`${fileName}.usdz`)
|
|
|
|
- ])
|
|
|
|
-
|
|
|
|
- // environment
|
|
|
|
-
|
|
|
|
- texture.mapping = THREE.EquirectangularReflectionMapping
|
|
|
|
-
|
|
|
|
- scene.current.background = texture
|
|
|
|
- scene.current.backgroundBlurriness = 0.5
|
|
|
|
- scene.current.environment = texture
|
|
|
|
-
|
|
|
|
- // model
|
|
|
|
-
|
|
|
|
- model.position.y = 0.25
|
|
|
|
- model.position.z = -0.25
|
|
|
|
- scene.current.add(model)
|
|
|
|
|
|
+ const usdzLoader = new USDZLoader1().setPath('./modelFile/')
|
|
|
|
+
|
|
|
|
+ let textureProgress = 0,
|
|
|
|
+ modelProgress = 0
|
|
|
|
+ try {
|
|
|
|
+ camera.current.position.set(0, 0.75, -3.5)
|
|
|
|
+
|
|
|
|
+ // 加载资源(改用回调形式)
|
|
|
|
+
|
|
|
|
+ const texturePromise: Promise<any> = new Promise((resolve, reject) => {
|
|
|
|
+ rgbeLoader.load(
|
|
|
|
+ 'setting.hdr',
|
|
|
|
+ resolve,
|
|
|
|
+ (xhr: any) => {
|
|
|
|
+ textureProgress = (xhr.loaded / xhr.total) * 50 // HDR占50%权重
|
|
|
|
+ updateProgress()
|
|
|
|
+ },
|
|
|
|
+ reject
|
|
|
|
+ )
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const modelPromise: Promise<any> = new Promise((resolve, reject) => {
|
|
|
|
+ usdzLoader.load(
|
|
|
|
+ `${fileName}`,
|
|
|
|
+ resolve,
|
|
|
|
+ (xhr: any) => {
|
|
|
|
+ modelProgress = (xhr.loaded / xhr.total) * 50 // USDZ占50%权重
|
|
|
|
+ updateProgress()
|
|
|
|
+ },
|
|
|
|
+ reject
|
|
|
|
+ )
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const updateProgress = () => {
|
|
|
|
+ const total = Math.floor(textureProgress + modelProgress)
|
|
|
|
+ setLoding(total)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 等待所有资源加载
|
|
|
|
+ const [texture, model] = await Promise.all([texturePromise, modelPromise])
|
|
|
|
+
|
|
|
|
+ // environment
|
|
|
|
+
|
|
|
|
+ texture.mapping = THREE.EquirectangularReflectionMapping
|
|
|
|
+
|
|
|
|
+ scene.current.background = texture
|
|
|
|
+ scene.current.backgroundBlurriness = 0.5
|
|
|
|
+ scene.current.environment = texture
|
|
|
|
+
|
|
|
|
+ // model
|
|
|
|
+
|
|
|
|
+ model.position.y = 0.25
|
|
|
|
+ model.position.z = -0.25
|
|
|
|
+ scene.current.add(model)
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(123, error)
|
|
|
|
+ if (1 + 1 === 2) return
|
|
|
|
+ console.log('usdz是二进制,转成glb格式')
|
|
|
|
+
|
|
|
|
+ camera.current.position.set(0, 0.75, 0.75)
|
|
|
|
+
|
|
|
|
+ // 这里显示的应该是二进制的usdz文件
|
|
|
|
+ renderer.current.setClearColor(0xffffff)
|
|
|
|
+ // 添加光源
|
|
|
|
+ const ambientLight = new THREE.AmbientLight(0xffffff, 1)
|
|
|
|
+ scene.current.add(ambientLight)
|
|
|
|
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
|
|
|
|
+ directionalLight.position.set(5, 5, 5)
|
|
|
|
+ scene.current.add(directionalLight)
|
|
|
|
+
|
|
|
|
+ // 加载管理器与进度处理
|
|
|
|
+ const loadingManager = new THREE.LoadingManager()
|
|
|
|
+ loadingManager.onProgress = (url, loaded, total) => {
|
|
|
|
+ setLoding((loaded / total) * 100)
|
|
|
|
+ }
|
|
|
|
+ loadingManager.onLoad = () => {}
|
|
|
|
+
|
|
|
|
+ // 加载GLB模型
|
|
|
|
+ const loader = new GLTFLoader(loadingManager)
|
|
|
|
+ loader.load(
|
|
|
|
+ `./modelFile/${fileName.replace('usdz', 'glb')}`,
|
|
|
|
+ (gltf: any) => {
|
|
|
|
+ const model = gltf.scene
|
|
|
|
+ scene.current.add(model)
|
|
|
|
+
|
|
|
|
+ model.position.y = -0.2
|
|
|
|
+
|
|
|
|
+ // 播放动画(如果有)
|
|
|
|
+ if (gltf.animations?.length) {
|
|
|
|
+ const mixer = new THREE.AnimationMixer(model)
|
|
|
|
+ const action = mixer.clipAction(gltf.animations[0])
|
|
|
|
+ action.play()
|
|
|
|
+ // 动画循环
|
|
|
|
+ const animate = () => {
|
|
|
|
+ requestAnimationFrame(animate)
|
|
|
|
+ mixer.update(0.01)
|
|
|
|
+ renderer.current.render(scene.current, camera.current)
|
|
|
|
+ }
|
|
|
|
+ animate()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // (xhr: any) => console.log('加载进度:', xhr.loaded / xhr.total),
|
|
|
|
+ // (error: any) => console.error('加载失败:', error)
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
|
|
// renderer
|
|
// renderer
|
|
|
|
|
|
@@ -63,11 +157,12 @@ function A1home() {
|
|
renderer.current.setAnimationLoop(animate)
|
|
renderer.current.setAnimationLoop(animate)
|
|
renderer.current.toneMapping = THREE.ACESFilmicToneMapping
|
|
renderer.current.toneMapping = THREE.ACESFilmicToneMapping
|
|
renderer.current.toneMappingExposure = 2.0
|
|
renderer.current.toneMappingExposure = 2.0
|
|
- document.querySelector('#A1home')!.appendChild(renderer.current.domElement)
|
|
|
|
|
|
+
|
|
|
|
+ document.querySelector('.usdzBox')!.appendChild(renderer.current.domElement)
|
|
|
|
|
|
const controls = new OrbitControls(camera.current, renderer.current.domElement)
|
|
const controls = new OrbitControls(camera.current, renderer.current.domElement)
|
|
- controls.minDistance = 1
|
|
|
|
- controls.maxDistance = 8
|
|
|
|
|
|
+ controls.minDistance = 0.5
|
|
|
|
+ controls.maxDistance = 10
|
|
// controls.target.y = 15;
|
|
// controls.target.y = 15;
|
|
// controls.update();
|
|
// controls.update();
|
|
|
|
|
|
@@ -78,7 +173,18 @@ function A1home() {
|
|
init()
|
|
init()
|
|
}, [init])
|
|
}, [init])
|
|
|
|
|
|
- return <div className={styles.A1home} id='A1home'></div>
|
|
|
|
|
|
+ return (
|
|
|
|
+ <div className={styles.A1home}>
|
|
|
|
+ <div className='usdzBox'></div>
|
|
|
|
+ {loding >= 100 ? null : (
|
|
|
|
+ <div className='loding'>
|
|
|
|
+ <div className='lodingTiao'>
|
|
|
|
+ <div style={{ width: loding + '%' }}></div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
}
|
|
}
|
|
|
|
|
|
const MemoA1home = React.memo(A1home)
|
|
const MemoA1home = React.memo(A1home)
|