|
|
@@ -1,181 +1,182 @@
|
|
|
-import * as THREE from "../js/three.module.js";
|
|
|
+import * as THREE from "../js/three.module.js"
|
|
|
|
|
|
-import initTinyUSDZ from "../js/tinyusdz.js";
|
|
|
+import initTinyUSDZ from "../js/tinyusdz.js"
|
|
|
|
|
|
-import { OrbitControls } from "../js/OrbitControls.js";
|
|
|
+import { OrbitControls } from "../js/OrbitControls.js"
|
|
|
|
|
|
-const urlAll = window.location.href.split("?m=")[1];
|
|
|
+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://4dkankan.oss-cn-shenzhen.aliyuncs.com/sxz/${urlAll}.usdz`;
|
|
|
// const USDZ_FILEPATH = `https://us-test.4dkankan.com/20241202dome/Shuiyueguanyin.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 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; // 已接收字节数
|
|
|
+ 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;
|
|
|
+ let timeOut = -1
|
|
|
|
|
|
// 更新加载条的函数
|
|
|
const updateLoadingBar = (loaded) => {
|
|
|
- let percentage = (loaded / totalBytes) * 100;
|
|
|
+ let percentage = (loaded / totalBytes) * 100
|
|
|
if (percentage >= 100) {
|
|
|
- percentage = 100;
|
|
|
+ percentage = 100
|
|
|
// 隐藏加载条
|
|
|
|
|
|
- clearTimeout(timeOut);
|
|
|
+ clearTimeout(timeOut)
|
|
|
timeOut = setTimeout(() => {
|
|
|
- const loadingBoxDom = document.querySelector(".loadingBox");
|
|
|
- loadingBoxDom.style.opacity = 0;
|
|
|
- loadingBoxDom.style.pointerEvents = "none";
|
|
|
- }, 300);
|
|
|
+ const loadingBoxDom = document.querySelector(".loadingBox")
|
|
|
+ loadingBoxDom.style.opacity = 0
|
|
|
+ loadingBoxDom.style.pointerEvents = "none"
|
|
|
+ }, 300)
|
|
|
}
|
|
|
|
|
|
- loadingBar.style.width = `${percentage}%`; // 更新加载条宽度
|
|
|
- };
|
|
|
+ loadingBar.style.width = `${percentage}%` // 更新加载条宽度
|
|
|
+ }
|
|
|
|
|
|
// 读取数据流
|
|
|
while (true) {
|
|
|
- const { done, value } = await reader.read(); // 读取数据
|
|
|
- if (done) break; // 如果读取完成,退出循环
|
|
|
- chunks.push(value); // 存储数据块
|
|
|
- receivedLength += value.length; // 更新已接收字节数
|
|
|
- updateLoadingBar(receivedLength); // 更新加载条
|
|
|
+ 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;
|
|
|
+ const usd_data = new Uint8Array(receivedLength) // 创建最终数据数组
|
|
|
+ let position = 0
|
|
|
for (const chunk of chunks) {
|
|
|
- usd_data.set(chunk, position); // 将数据块写入最终数组
|
|
|
- position += chunk.length; // 更新位置
|
|
|
+ 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);
|
|
|
+ const usd = new TinyUSDZLoader.TinyUSDZLoader(usd_data)
|
|
|
// console.log(usd.numMeshes());
|
|
|
// 隐藏加载条
|
|
|
- loadingBar.style.display = "none";
|
|
|
+ loadingBar.style.display = "none"
|
|
|
|
|
|
- const scene = new THREE.Scene();
|
|
|
+ const scene = new THREE.Scene()
|
|
|
const camera = new THREE.PerspectiveCamera(
|
|
|
75,
|
|
|
window.innerWidth / window.innerHeight,
|
|
|
0.1,
|
|
|
1000
|
|
|
- );
|
|
|
+ )
|
|
|
|
|
|
const renderer = new THREE.WebGLRenderer({
|
|
|
alpha: true, // 关键配置,设置背景透明
|
|
|
antialias: true, // 可选抗锯齿
|
|
|
- });
|
|
|
+ })
|
|
|
|
|
|
- renderer.setClearColor(0x000000, 0); // 第二个参数为透明度(0表示完全透明)
|
|
|
+ renderer.setClearColor(0x000000, 0) // 第二个参数为透明度(0表示完全透明)
|
|
|
|
|
|
- renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
- renderer.setAnimationLoop(animate);
|
|
|
+ renderer.setSize(window.innerWidth, window.innerHeight)
|
|
|
+ renderer.setAnimationLoop(animate)
|
|
|
// 设置输出颜色空间为线性SRGB
|
|
|
- renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
|
|
|
- document.body.appendChild(renderer.domElement);
|
|
|
+ renderer.outputColorSpace = THREE.LinearSRGBColorSpace
|
|
|
+ document.body.appendChild(renderer.domElement)
|
|
|
|
|
|
// First mesh only
|
|
|
- const mesh = usd.getMesh(0);
|
|
|
+ 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();
|
|
|
+ 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));
|
|
|
+ geometry.setAttribute("uv", new THREE.BufferAttribute(mesh.texcoords, 2))
|
|
|
}
|
|
|
|
|
|
- const usdMaterial = usd.getMaterial(mesh.materialId);
|
|
|
+ const usdMaterial = usd.getMaterial(mesh.materialId)
|
|
|
//console.log("usdMat", usdMaterial);
|
|
|
//if (usdMaterial.aaa) {
|
|
|
// console.log("aaa");
|
|
|
//}
|
|
|
|
|
|
- var material;
|
|
|
+ var material
|
|
|
|
|
|
if (usdMaterial.hasOwnProperty("diffuseColorTextureId")) {
|
|
|
- const diffTex = usd.getTexture(usdMaterial.diffuseColorTextureId);
|
|
|
+ const diffTex = usd.getTexture(usdMaterial.diffuseColorTextureId)
|
|
|
|
|
|
- const img = usd.getImage(diffTex.textureImageId);
|
|
|
+ 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);
|
|
|
+ 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;
|
|
|
+ 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();
|
|
|
+ material = new THREE.MeshNormalMaterial()
|
|
|
}
|
|
|
|
|
|
// Assume triangulated indices.
|
|
|
geometry.setIndex(
|
|
|
new THREE.Uint32BufferAttribute(mesh.faceVertexIndices, 1)
|
|
|
- );
|
|
|
+ )
|
|
|
|
|
|
- geometry.computeVertexNormals();
|
|
|
+ geometry.computeVertexNormals()
|
|
|
|
|
|
//const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
|
|
|
- const cube = new THREE.Mesh(geometry, material);
|
|
|
+ const cube = new THREE.Mesh(geometry, material)
|
|
|
|
|
|
// 缩放模型
|
|
|
- cube.scale.set(2, 2, 2);
|
|
|
- cube.updateMatrixWorld(true); // 强制更新世界矩阵[3](@ref)
|
|
|
+ cube.scale.set(2, 2, 2)
|
|
|
+ cube.updateMatrixWorld(true) // 强制更新世界矩阵[3](@ref)
|
|
|
|
|
|
// 计算包围盒
|
|
|
- const box = new THREE.Box3().setFromObject(cube);
|
|
|
- const center = new THREE.Vector3();
|
|
|
- box.getCenter(center);
|
|
|
+ const box = new THREE.Box3().setFromObject(cube)
|
|
|
+ const center = new THREE.Vector3()
|
|
|
+ box.getCenter(center)
|
|
|
|
|
|
// 居中模型
|
|
|
- cube.position.sub(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);
|
|
|
+ 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)
|
|
|
|
|
|
- scene.add(cube);
|
|
|
+ scene.add(cube)
|
|
|
|
|
|
- const controls = new OrbitControls(camera, renderer.domElement);
|
|
|
+ const controls = new OrbitControls(camera, renderer.domElement)
|
|
|
|
|
|
- controls.enablePan = false; // 禁用右键平移功能
|
|
|
+ controls.enablePan = false // 禁用右键平移功能
|
|
|
|
|
|
- controls.enableZoom = true; // 必须禁用轨道控制器的默认缩放[1](@ref)
|
|
|
+ controls.enableZoom = true // 必须禁用轨道控制器的默认缩放[1](@ref)
|
|
|
|
|
|
- controls.enableDamping = true;
|
|
|
- controls.dampingFactor = 0.25;
|
|
|
- controls.screenSpacePanning = false;
|
|
|
- controls.maxPolarAngle = Math.PI / 2;
|
|
|
+ controls.enableDamping = true
|
|
|
+ controls.dampingFactor = 0.25
|
|
|
+ controls.screenSpacePanning = false
|
|
|
+ controls.maxPolarAngle = Math.PI / 2
|
|
|
|
|
|
// 兼容鼠标滚轮与触摸屏双指缩放
|
|
|
// const handleZoom = (delta) => {
|
|
|
@@ -232,15 +233,15 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
//cube.rotation.x += 0.01;
|
|
|
// cube.rotation.y += 0.02;
|
|
|
|
|
|
- controls.update();
|
|
|
+ controls.update()
|
|
|
|
|
|
- renderer.render(scene, camera);
|
|
|
+ renderer.render(scene, camera)
|
|
|
}
|
|
|
|
|
|
window.addEventListener("resize", () => {
|
|
|
- camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
- camera.updateProjectionMatrix();
|
|
|
- renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
- });
|
|
|
- });
|
|
|
-});
|
|
|
+ camera.aspect = window.innerWidth / window.innerHeight
|
|
|
+ camera.updateProjectionMatrix()
|
|
|
+ renderer.setSize(window.innerWidth, window.innerHeight)
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|