import * as THREE from "../js/three.module.js" import initTinyUSDZ from "../js/tinyusdz.js" import { OrbitControls } from "../js/OrbitControls.js" const urlAll = window.location.href.split("?m=")[1] // console.log(123456,urlAll); // const USDZ_FILEPATH = `https://4dkankan.oss-cn-shenzhen.aliyuncs.com/sxz/${urlAll}.usdz`; // const USDZ_FILEPATH = `https://us-test.4dkankan.com/20241202dome/Shuiyueguanyin.usdz`; const USDZ_FILEPATH = `https://swkz-1332577016.cos.ap-guangzhou.myqcloud.com/kanzhan/2025/06/23/data.usdz`; // const USDZ_FILEPATH = `https://3d-usdz.4dkankan.com/sxz/${urlAll}.usdz` document.addEventListener("DOMContentLoaded", async () => { const loadingBar = document.getElementById("loading") // 获取加载条元素 loadingBar.style.display = "block" // 显示加载条 const usd_res = await fetch(USDZ_FILEPATH) const totalBytes = parseInt(usd_res.headers.get("Content-Length"), 10) // 获取总字节数 const reader = usd_res.body.getReader() // 获取读取器 const chunks = [] // 存储数据块 let receivedLength = 0 // 已接收字节数 let timeOut = -1 // 更新加载条的函数 const updateLoadingBar = (loaded) => { let percentage = (loaded / totalBytes) * 100 if (percentage >= 100) { percentage = 100 // 隐藏加载条 clearTimeout(timeOut) timeOut = setTimeout(() => { const loadingBoxDom = document.querySelector(".loadingBox") loadingBoxDom.style.opacity = 0 loadingBoxDom.style.pointerEvents = "none" }, 300) } loadingBar.style.width = `${percentage}%` // 更新加载条宽度 } // 读取数据流 while (true) { const { done, value } = await reader.read() // 读取数据 if (done) break // 如果读取完成,退出循环 chunks.push(value) // 存储数据块 receivedLength += value.length // 更新已接收字节数 updateLoadingBar(receivedLength) // 更新加载条 } const usd_data = new Uint8Array(receivedLength) // 创建最终数据数组 let position = 0 for (const chunk of chunks) { usd_data.set(chunk, position) // 将数据块写入最终数组 position += chunk.length // 更新位置 } // const usd_binary = new Uint8Array(usd_data); // 加载 TinyUSDZ initTinyUSDZ().then(function (TinyUSDZLoader) { const usd = new TinyUSDZLoader.TinyUSDZLoader(usd_data) // console.log(usd.numMeshes()); // 隐藏加载条 loadingBar.style.display = "none" const scene = new THREE.Scene() // 添加渐变背景 const bgTexture = new THREE.TextureLoader().load('./bg.png') scene.background = bgTexture const camera = new THREE.PerspectiveCamera( 85, window.innerWidth / window.innerHeight, 0.1, 1000 ) const renderer = new THREE.WebGLRenderer({ alpha: true, // 关键配置,设置背景透明 antialias: true, // 可选抗锯齿 }) renderer.setClearColor(0x000000, 1) // 第二个参数为透明度(0表示完全透明) renderer.setSize(window.innerWidth, window.innerHeight) renderer.setAnimationLoop(animate) // 设置输出颜色空间为线性SRGB renderer.outputColorSpace = THREE.LinearSRGBColorSpace document.body.appendChild(renderer.domElement) // First mesh only const mesh = usd.getMesh(0) //console.log("usd", usd) //console.log("mesh", mesh); //const geometry = new THREE.BoxGeometry( 1, 1, 1 ); const geometry = new THREE.BufferGeometry() geometry.setAttribute( "position", new THREE.BufferAttribute(mesh.points, 3) ) // TODO: set normal from mesh if (mesh.hasOwnProperty("texcoords")) { // console.log(mesh.texcoords); geometry.setAttribute("uv", new THREE.BufferAttribute(mesh.texcoords, 2)) } const usdMaterial = usd.getMaterial(mesh.materialId) //console.log("usdMat", usdMaterial); //if (usdMaterial.aaa) { // console.log("aaa"); //} var material if (usdMaterial.hasOwnProperty("diffuseColorTextureId")) { const diffTex = usd.getTexture(usdMaterial.diffuseColorTextureId) const img = usd.getImage(diffTex.textureImageId) // console.log(img); // assume RGBA for now. let image8Array = new Uint8ClampedArray(img.data) let imgData = new ImageData(image8Array, img.width, img.height) const texture = new THREE.DataTexture(imgData, img.width, img.height) texture.flipY = true texture.needsUpdate = true material = new THREE.MeshBasicMaterial({ map: texture, }) } else { material = new THREE.MeshNormalMaterial() } // Assume triangulated indices. geometry.setIndex( new THREE.Uint32BufferAttribute(mesh.faceVertexIndices, 1) ) geometry.computeVertexNormals() //const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); const cube = new THREE.Mesh(geometry, material) // 缩放模型 cube.scale.set(7, 7, 7) cube.updateMatrixWorld(true) // 强制更新世界矩阵[3](@ref) // 计算包围盒 const box = new THREE.Box3().setFromObject(cube) const center = new THREE.Vector3() box.getCenter(center) // 居中模型 cube.position.sub(center) // 计算尺寸并调整相机 const size = box.getSize(new THREE.Vector3()).length() camera.near = size / 100 camera.far = size * 100 camera.updateProjectionMatrix() camera.position.set(size * 0.5, size * 0.5, size * 0.5) camera.lookAt(0, 0, 0) // 向上移动模型 // cube.position.y += 0.5 // 向上 scene.add(cube) const controls = new OrbitControls(camera, renderer.domElement) controls.enablePan = true // 禁用右键平移功能 controls.enableZoom = true // 必须禁用轨道控制器的默认缩放[1](@ref) controls.enableDamping = true controls.dampingFactor = 0.25 controls.screenSpacePanning = false controls.minPolarAngle = Math.PI / 180 * 1 // 1 度(约 0.01745 弧度) controls.maxPolarAngle = Math.PI - Math.PI / 180 * 1 // 179 度(约 3.124 弧度) // 兼容鼠标滚轮与触摸屏双指缩放 // 兼容鼠标滚轮与触摸屏双指缩放 // const handleZoom = (delta) => { // // console.log('--------',delta); // cube.updateMatrixWorld(true); // // 计算包围盒 // const box = new THREE.Box3().setFromObject(cube); // const center = new THREE.Vector3(); // box.getCenter(center); // // 居中模型 // cube.position.sub(center); // cube.scale.multiplyScalar(delta); // cube.scale.clampScalar(0.5, 4); // 限制缩放范围0.5-3倍[1,6](@ref) // }; // 鼠标滚轮事件 // window.addEventListener( // "wheel", // (e) => { // e.preventDefault(); // const zoomFactor = e.deltaY > 0 ? 0.95 : 1.05; // handleZoom(zoomFactor); // }, // { passive: false } // ); // 触摸屏双指缩放 // let initialDistance = 0; // window.addEventListener("touchstart", (e) => { // if (e.touches.length === 2) { // initialDistance = Math.hypot( // e.touches[0].pageX - e.touches[1].pageX, // e.touches[0].pageY - e.touches[1].pageY // ); // } // }); // window.addEventListener("touchmove", (e) => { // if (e.touches.length === 2) { // const currentDistance = Math.hypot( // e.touches[0].pageX - e.touches[1].pageX, // e.touches[0].pageY - e.touches[1].pageY // ); // const zoomFactor = currentDistance > initialDistance ? 1.01 : 0.99; // handleZoom(zoomFactor); // initialDistance = currentDistance; // } // }); function animate() { //cube.rotation.x += 0.01; // cube.rotation.y += 0.02; controls.update() renderer.render(scene, camera) } window.addEventListener("resize", () => { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) }) }) })