threejs 实现720°全景图,;两种方式:环境贴图、CSS3DRenderer渲染

前提

有一个前提条件:六张大小一致的图片,六个图片分别对应的是720°全景图的六个面:上、下、左、右、前、后。
上
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这个不是那种无人机拍摄的全景图,是六个图片拼起来的,这样的取景方式要比无人机的要经济一些。
----------------------------------------------------------------------------------------------------------------------------

方式一: CSS3DRenderer方式

CSS3DRenderer 是 Three.js 提供的一个工具,用于将 HTML/CSS 元素(如按钮、文本)无缝集成到 WebGL(Three.js)的 3D 场景中。它通过将 DOM 元素作为纹理映射到 3D 几何体上,实现 2D UI 与 3D 场景的结合。

1. CSS3DRenderer 的作用

  • 桥接 2D 与 3D:将 HTML 元素渲染为 3D 对象,保留 CSS 样式和交互能力。
  • 高效渲染:通过 GPU 加速渲染 DOM 元素,避免频繁重绘。

2. 关键组件

  • CSS3DRenderer:继承自 THREE.Object3D,用于管理 DOM 元素的 3D 渲染。
  • CSS3DSprite:将单个 DOM 元素封装为可定位的 3D 对象。
  • CSS3DObject:支持嵌套多个子元素(需手动实现层级结构)。

3. 性能优化

  • 减少 DOM 元素数量:频繁操作 DOM 会显著降低性能。
  • 使用 requestAnimationFrame:确保渲染与主循环同步。
  • 限制纹理尺寸:过大的 DOM 元素会增加渲染开销。
  • 离屏渲染:复杂场景可将部分元素渲染到离屏 Canvas 再贴图。

具体实例代码

注意:

  • 版本兼容性:CSS3DRenderer 位于 examples/jsm 目录下,需单独引入。不同的three版本的CSS3DRenderer引入方式不一样,根据实际版本而定
  • 移动端适配:部分移动浏览器对 position: absolute 的 DOM 元素支持不佳,建议测试。
  • 替代方案:若仅需简单 2D 界面,可考虑 THREE.CanvasTexture 或 THREE.Texture 直接绘制。

代码思路:

思路和步骤

整体的实现思路可以分为以下几个步骤:

1. 初始化和设置场景

在组件挂载时,首先需要初始化一个 THREE.js 场景以及相关的相机、渲染器等对象。该过程包括以下步骤:

  • 初始化相机:设置透视相机(THREE.PerspectiveCamera),根据容器的宽高设置视野比例。
  • 初始化场景:创建一个新的 THREE.js 场景对象,用来容纳全景图的所有元素。
  • 创建六个面:该全景图是通过将六个面(前、后、左、右、上、下)贴图创建的,每个面都对应一个 CSS3DObject,并且每个面都有对应的纹理图像。
camera = new THREE.PerspectiveCamera(90, boxWidth / boxHeight, 0.1, 1000);
scene = new THREE.Scene();
  • 渲染器设置CSS3DRenderer 用来渲染带有 HTML 内容的 3D 场景。它允许你将普通的 HTML 元素(如 divimg 等)作为 3D 场景中的对象进行渲染。这里会设置它的大小并将其添加到 DOM 中。
renderer = new CSS3DRenderer();
renderer.setSize(boxWidth, boxHeight);
document.getElementById("surfaceBox").appendChild(renderer.domElement);

2. 创建全景图面 (六个面)

全景图的每一面都是一个 CSS3DObject,这是一种特殊的 THREE.js 对象,能够将 HTML 元素渲染到 3D 场景中。代码会为每个方向(前、后、左、右、上、下)创建一个面,并且通过 positionrotation 属性将它们放置到合适的空间。

const sides = [{ position: [-(boxWidth / 2 - 2), 0, 0], rotation: [0, Math.PI / 2, 0] },{ position: [boxWidth / 2 - 2, 0, 0], rotation: [0, -Math.PI / 2, 0] },{ position: [0, boxWidth / 2 - 2, 0], rotation: [Math.PI / 2, 0, Math.PI] },{ position: [0, -(boxWidth / 2 - 2), 0], rotation: [-Math.PI / 2, 0, Math.PI] },{ position: [0, 0, boxWidth / 2 - 2], rotation: [0, Math.PI, 0] },{ position: [0, 0, -(boxWidth / 2 - 2)], rotation: [0, 0, 0] },
];

3. 事件绑定与鼠标交互

通过监听 mousemovemousedownmouseup 事件,实现用户与全景图的交互。具体来说,用户通过鼠标拖动来控制全景图的旋转。代码的核心是通过监听鼠标的移动事件来更新 lon(经度)和 lat(纬度),控制视角的改变。

  • 鼠标按下 (mousedown):当用户按下鼠标时,开始监听鼠标的移动事件,用来更新视角。
  • 鼠标移动 (mousemove):当鼠标移动时,根据鼠标的移动距离来更新 lonlat,实现图像的旋转。
  • 鼠标抬起 (mouseup):鼠标抬起时,停止监听鼠标移动事件。
function onDocumentMouseMove(event) {var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;targetLon -= movementX * 0.1;  // 水平拖动影响 lontargetLat += movementY * 0.1;  // 垂直拖动影响 lattargetLat = Math.max(-85, Math.min(85, targetLat)); // 限制 lat 范围
}

4. 视角和动画渲染

通过 animate 函数实现场景的动画和相机视角的动态更新。animate 函数会通过 requestAnimationFrame 来不断更新视图。相机的 lookAt 方法确保相机始终指向一个目标点,从而实现平滑的旋转效果。

function animate() {requestAnimationFrame(animate);// 视角的平滑过渡lon += (targetLon - lon) * 0.1;lat += (targetLat - lat) * 0.1;lat = Math.max(-85, Math.min(85, lat));phi = THREE.MathUtils.degToRad(90 - lat);theta = THREE.MathUtils.degToRad(lon);target.x = Math.sin(phi) * Math.cos(theta);target.z = Math.cos(phi);target.y = Math.sin(phi) * Math.sin(theta);camera.lookAt(target);  // 相机朝向目标renderer.render(scene, camera);  // 渲染场景
}

5. 响应式设计和窗口缩放

通过 onWindowResize 函数监听浏览器窗口的变化,自动调整相机的宽高比和渲染器的大小,确保全景图在不同屏幕和窗口大小下都能正常显示。

function onWindowResize() {const boxWidth = document.querySelector(".surface_box").offsetWidth;const boxHeight = document.querySelector(".surface_box").offsetHeight;camera.aspect = boxWidth / boxHeight;camera.updateProjectionMatrix();renderer.setSize(boxWidth, boxHeight);
}

6. 触摸支持

为了支持移动设备的触摸事件,使用了 touchstarttouchmove 事件来替代 mousemove 事件。触摸事件处理函数会跟踪触摸点的变化,并根据触摸的移动更新视角。

function onDocumentTouchStart(event) {event.preventDefault();const touch = event.touches[0];touchX = touch.screenX;touchY = touch.screenY;
}function onDocumentTouchMove(event) {event.preventDefault();const touch = event.touches[0];targetLon -= (touch.screenX - touchX) * 0.2;targetLat += (touch.screenY - touchY) * 0.2;touchX = touch.screenX;touchY = touch.screenY;
}

完整代码

~~

<template><div class="surface_box" id="surfaceBox"><!-- 6个面:代码中通过6div(每个 div对应一个 surface_x)来显示六个图像,这些图像分别代表立方体的六个面(前、后、左、右、上、下)。这些图像被作为 img 标签嵌入,每个面上展示一个不同的图片。--><div id="surface_0" class="surface"><img class="bg" src="../assets/img/posx.jpg" alt="" /></div><div id="surface_1" class="surface"><img class="bg" src="../assets/img/negx.jpg" alt="" /></div><div id="surface_2" class="surface"><img class="bg" src="../assets/img/posy.jpg" alt="" /></div><div id="surface_3" class="surface"><img class="bg" src="../assets/img/negy.jpg" alt="" /></div><div id="surface_4" class="surface"><img class="bg" src="../assets/img/posz.jpg" alt="" /></div><div id="surface_5" class="surface"><img class="bg" src="../assets/img/negz.jpg" alt="" /></div></div>
</template><script setup>
import { nextTick, onMounted } from "vue";
import * as THREE from "three";
import { CSS3DRenderer } from "three/examples/jsm/renderers/CSS3DRenderer.js";
import { CSS3DObject } from "three/examples/jsm/renderers/CSS3DRenderer.js";
// ******************创建一个全景场景*************
/*** 变量定义:
scene、camera 和 renderer 用于构建 three.js 场景。
lon 和 lat 控制视角的旋转,phi 和 theta 用来转换为弧度。
touchX 和 touchY 用于处理触摸事件* */
let scene, camera, renderer;
let touchX, touchY;
let lon = 90,lat = 90; // 初始化视角
let targetLon = lon,targetLat = lat; // 目标视角
let phi = 0,theta = 0;var target = new THREE.Vector3();
// 场景初始化
function init() {/*** PerspectiveCamera:定义了一个视角为 75 度的透视相机,* 宽高比根据窗口大小计算。该相机会用来显示 3D 场景。* */let boxWidth = document.querySelector(".surface_box").offsetWidth;let boxHeight = document.querySelector(".surface_box").offsetHeight;// console.log(boxHeight, boxWidth, "匡高");camera = new THREE.PerspectiveCamera(90, boxWidth / boxHeight, 0.1, 1000);scene = new THREE.Scene();/*** sides 数组:每个面的位置和旋转角度都被定义了(单位是像素和弧度),* 通过这些数据,可以设置每个面在三维空间中的具体位置和方向。* */// console.log(boxWidth / 2 - 2, "boxWidth / 2-2");let sides = [{//多余2像素 用于闭合正方体position: [-(boxWidth / 2 - 2), 0, 0], //位置:表示左面,中心点在 X 轴负方向,距离立方体中心 boxWidth / 2-2rotation: [0, Math.PI / 2, 0], //角度: 表示该面绕 Y 轴旋转 90 度(右面)。},{position: [boxWidth / 2 - 2, 0, 0], //右面rotation: [0, -Math.PI / 2, 0],},{position: [0, boxWidth / 2 - 2, 0], //上面rotation: [Math.PI / 2, 0, Math.PI],},{position: [0, -(boxWidth / 2 - 2), 0], //下面rotation: [-Math.PI / 2, 0, Math.PI],},{position: [0, 0, boxWidth / 2 - 2], //前面rotation: [0, Math.PI, 0],},{position: [0, 0, -(boxWidth / 2 - 2)], //hourotation: [0, 0, 0],},];//根据六个面的信息,创建六个对象放入场景中for (let i = 0; i < sides.length; i++) {let side = sides[i];//  获取平面的domlet element = document.getElementById("surface_" + i);// 设置平面的宽度element.width = boxWidth;element.height = boxHeight;//创建CSS3DObject对象// 创建 CSS3DObject:通过 CSS3DObject//  将每个 HTML 元素(每个面)转化为三维对象,// 并将其添加到 three.js 的场景中。var object = new CSS3DObject(element);// 设置对象的位置和旋转object.position.fromArray(side.position);object.rotation.fromArray(side.rotation);scene.add(object);}// 使用 CSS3DRenderer 渲染器,来渲染场景中的 CSS3DObject(而不是 WebGL 渲染器)。// 这样可以将 DOM 元素(如图片)渲染到 3D 场景中renderer = new CSS3DRenderer();// 渲染到surface_box盒子中renderer.setSize(boxWidth, boxHeight);//添加渲染器到页面/*** 鼠标和触摸事件:用于交互式控制全景图的旋转和缩放:
鼠标拖动旋转全景图:通过 mousedown、mousemove 和 mouseup 事件实现。
鼠标滚轮缩放:通过 wheel 事件控制相机的视野。
触摸控制:通过 touchstart 和 touchmove 控制触摸屏上的旋转* */surfaceBox.appendChild(renderer.domElement);surfaceBox.addEventListener("mousedown", onDocumentMouseDown, false); //鼠标按下事件surfaceBox.addEventListener("wheel", onDocumentMouseWheel, false); //鼠标滚轮事件surfaceBox.addEventListener("touchstart", onDocumentTouchStart, false); //触摸开始事件surfaceBox.addEventListener("touchmove", onDocumentTouchMove, false); //触摸移动事件window.addEventListener("resize", onWindowResize, false); //窗口大小改变事件
}
/*** 动画循环:每次更新时,都会通过 lat 和 lon 计算新的 phi 和 theta,* 并通过 camera.lookAt(target) 来改变相机的朝向。* 渲染器渲染场景和相机的视图。* */
function animate() {requestAnimationFrame(animate);lat = Math.max(-85, Math.min(85, lat)); // 限制上下视角范围phi = THREE.MathUtils.degToRad(90 - lat);theta = THREE.MathUtils.degToRad(lon);target.x = Math.sin(phi) * Math.cos(theta);target.z = Math.cos(phi);target.y = Math.sin(phi) * Math.sin(theta);camera.lookAt(target);/*** 通过传入的scene和camera* 获取其中object在创建时候传入的element信息* 以及后面定义的包括位置,角度等信息* 根据场景中的obj创建dom元素* 插入render本身自己创建的场景div中* 达到渲染场景的效果*/renderer.render(scene, camera);
}
/*** onWindowResize:监听窗口大小变化,调整相机的纵横比并更新渲染器大小。* */
function onWindowResize() {let boxWidth = document.querySelector(".surface_box").offsetWidth;let boxHeight = document.querySelector(".surface_box").offsetHeight;camera.aspect = boxWidth / boxHeight;camera.updateProjectionMatrix();renderer.setSize(boxWidth, boxHeight);
}
/*** onDocumentMouseDown:鼠标按下事件,启动鼠标移动和鼠标抬起事件。** */
function onDocumentMouseDown(event) {event.preventDefault();surfaceBox.addEventListener("mousemove", onDocumentMouseMove, false);surfaceBox.addEventListener("mouseup", onDocumentMouseUp, false);surfaceBox.addEventListener("mouseleave", onDocumentMouseUp, false);
}
/*** onDocumentMouseMove: 鼠标移动事件,根据鼠标移动的距离,更新相机的旋转角度。* */
function onDocumentMouseMove(event) {// // 计算鼠标移动的位置X// var movementX =//   event.movementX || event.mozMovementX || event.webkitMovementX || 0;// // 计算鼠标移动的位置Y// var movementY =//   event.movementY || event.mozMovementY || event.webkitMovementY || 0;// lon -= movementX * 0.2;// lat -= movementY * 0.2;var movementX =event.movementX || event.mozMovementX || event.webkitMovementX || 0;var movementY =event.movementY || event.mozMovementY || event.webkitMovementY || 0;// 调整灵敏度和方向targetLon += movementX * 0.2; // 水平拖动,调整 lontargetLat -= movementY * 0.2; // 垂直拖动,调整 lat// 限制 lat 范围,防止过度拖动targetLat = Math.max(-85, Math.min(85, targetLat));lon = targetLon;lat = targetLat;// 调试输出// console.log(//   `movementX: ${movementX}, movementY: ${movementY}, targetLon: ${targetLon}, targetLat: ${targetLat}`// );
}
/*** onDocumentMouseUp: 鼠标抬起事件,移除鼠标移动和鼠标抬起事件的监听。* */
function onDocumentMouseUp(event) {surfaceBox.removeEventListener("mousemove", onDocumentMouseMove);surfaceBox.removeEventListener("mouseup", onDocumentMouseUp);
}
/*** onDocumentMouseWheel: 鼠标滚轮事件,根据滚轮的滚动距离,更新相机的视野。* */function onDocumentMouseWheel(event) {camera.fov += event.deltaY * 0.02; // 调整缩放因子// camera.fov = Math.max(30, Math.min(100, camera.fov)); // 限制缩放范围camera.updateProjectionMatrix();
}
/*** onDocumentTouchStart: 触摸开始事件,记录触摸的初始位置。* */
function onDocumentTouchStart(event) {event.preventDefault();var touch = event.touches[0];touchX = touch.screenX;touchY = touch.screenY;
}
/*** onDocumentTouchMove: 触摸移动事件,根据触摸移动的距离,更新相机的旋转角度。* */
function onDocumentTouchMove(event) {event.preventDefault();var touch = event.touches[0];lon -= (touch.screenX - touchX) * 0.2;lat += (touch.screenY - touchY) * 0.2;touchX = touch.screenX;touchY = touch.screenY;
}onMounted(() => {nextTick(() => {// 初始化场景init();// 启动动画循环animate();// 确保DOM更新后再执行});
});
</script><style lang="less" scoped>
.surface_box {width: 800px;height: 800px;background-color: #000000;margin: 0;cursor: move;overflow: hidden;
}
.surface {width: 800px;height: 800px;background-size: cover;position: absolute;
}
.surface .bg {position: absolute;width: 800px;height: 800px;
}
</style>

-------------------------------------------------------------------------------------------------------------------------------

方式二:环境贴图

代码思路

加载六张图片作为环境贴图,并将其设置为场景的背景:

1. new THREE.CubeTextureLoader()
  • CubeTextureLoaderThree.js 提供的一个工具,用于加载立方体纹理(CubeTexture)。
  • 立方体纹理由六张图片组成,分别对应立方体的六个面(右、左、上、下、前、后)。
  • 这些图片通常用于创建环境贴图(Environment Map),模拟一个包围场景的立方体。
2. textureLoader.load([...], onLoad, onProgress, onError)
  • load 方法用于加载六张图片并生成一个 CubeTexture 对象。
  • 参数说明:
    • 第一个参数:一个数组,包含六张图片的路径,分别对应立方体的六个面:
      • posXimg:右面(+X)
      • negXimg:左面(-X)
      • posYimg:上面(+Y)
      • negYimg:下面(-Y)
      • posZimg:前面(+Z)
      • negZimg:后面(-Z)
    • 第二个参数 (onLoad):加载完成后的回调函数。这里将加载的纹理设置为场景的背景:
      scene.background = texture;
      
    • 第三个参数 (onProgress):加载进度的回调函数。可以用来显示加载进度,例如:
      console.log(`加载进度: ${(progress.loaded / progress.total) * 100}%`);
      
    • 第四个参数 (onError):加载失败的回调函数。如果某张图片加载失败,会触发该函数并输出错误信息。
3. scene.background = texture
  • 将加载的立方体纹理设置为场景的背景。
  • scene.background 是一个特殊属性,用于设置场景的背景,可以是颜色(如 0x000000)或纹理(如 CubeTexture)。
  • 设置为 CubeTexture 后,场景会被六张图片包围,形成一个 360 度的全景环境。

运行效果

  • 六张图片会被加载并组合成一个立方体纹理,作为场景的背景。
  • 用户可以通过 OrbitControls 拖拽相机,查看不同方向的背景。
  • 如果某张图片加载失败,会在控制台输出错误信息。

总结

这段代码的核心功能是:

  1. 使用 CubeTextureLoader 加载六张图片,生成一个立方体纹理。
  2. 将立方体纹理设置为场景的背景,形成一个 360 度的全景环境。
  3. 提供加载完成、加载进度和加载失败的回调函数,方便调试和监控资源加载状态。

完整代码

<script setup>
import { onMounted, nextTick, ref } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import posXimg from "../assets/img/posx.jpg";
import negXimg from "../assets/img/negx.jpg";
import posYimg from "../assets/img/posy.jpg";
import negYimg from "../assets/img/negy.jpg";
import posZimg from "../assets/img/posz.jpg";
import negZimg from "../assets/img/negz.jpg";let scene, camera, renderer, cube, controls, raycaster, mouse;function init() {const container = document.getElementById("cubeContainer");// 初始化场景scene = new THREE.Scene();// 初始化相机camera = new THREE.PerspectiveCamera(75,container.clientWidth / container.clientHeight,0.1,1000);camera.position.z = 5;// 初始化渲染器renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(container.clientWidth, container.clientHeight);container.appendChild(renderer.domElement);// 加载六张图片作为环境贴图const textureLoader = new THREE.CubeTextureLoader();const texture = textureLoader.load([posXimg, // 右面negXimg, // 左面posYimg, // 上面negYimg, // 下面posZimg, // 前面negZimg, // 后面],() => {console.log("环境贴图加载成功!");scene.background = texture; // 将加载的环境贴图设置为场景的背景},(progress) => {console.log(`加载进度: ${(progress.loaded / progress.total) * 100}%`);},(error) => {console.error("环境贴图加载失败", error);});// 创建立方体const geometry = new THREE.BoxGeometry();const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); // 绿色cube = new THREE.Mesh(geometry, material);scene.add(cube);// 添加坐标轴辅助工具const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);// 添加控制器controls = new OrbitControls(camera, renderer.domElement);// 初始化 Raycaster 和鼠标位置raycaster = new THREE.Raycaster();mouse = new THREE.Vector2();// 响应窗口大小变化window.addEventListener("resize", onWindowResize);
}function animate() {requestAnimationFrame(animate);// 可选:让立方体旋转cube.rotation.x += 0.01;cube.rotation.y += 0.01;controls.update();renderer.render(scene, camera);
}
// 
function onWindowResize() {const container = document.getElementById("cubeContainer");camera.aspect = container.clientWidth / container.clientHeight;camera.updateProjectionMatrix();renderer.setSize(container.clientWidth, container.clientHeight);
}onMounted(() => {nextTick(() => {init();animate();});
});
</script><template><divid="cubeContainer"style="width: 100%; height: 100vh; background: #000"></div>
</template><style scoped>
#cubeContainer {overflow: hidden;
}
</style>

----------------------------------------------------------------------------------------------------------------------------

三、两种方式的区别:

THREE.CubeTextureLoaderCSS3DRendererThree.js 中两种不同的技术,用于生成 3D 全景图。它们的实现方式、适用场景、性能以及用户体验各有不同。以下是对两者的详细分析和对比:


1. THREE.CubeTextureLoader

CubeTextureLoaderThree.js 提供的一种加载立方体纹理的方法,通常用于创建环境贴图(Environment Map)或背景全景图。

工作原理
  • 使用六张图片(分别对应立方体的六个面:前、后、左、右、上、下)加载一个立方体纹理。
  • 将立方体纹理设置为场景的背景(scene.background),或者映射到物体的材质上(如 envMap)。
  • 用户通过相机的旋转来查看不同方向的背景。
优势
  1. 高性能
    • 立方体纹理直接由 GPU 渲染,性能非常高。
    • 适合大规模场景或需要实时渲染的应用(如游戏、虚拟现实)。
  2. 真实感强
    • 支持环境反射(envMap)和折射效果,可以用于模拟真实的光照和反射。
    • 适合需要高质量渲染的场景。
  3. 简单易用
    • 只需提供六张图片即可生成全景图。
    • Three.js 的其他功能(如光照、材质)无缝集成。
劣势
  1. 灵活性较低
    • 只能用于渲染静态背景,无法直接嵌入动态 HTML 内容。
    • 不支持直接操作 DOM 元素。
  2. 对图片要求较高
    • 六张图片需要严格按照立方体的六个方向(前、后、左、右、上、下)排列,且需要无缝拼接。
    • 图片分辨率较高时可能会占用较多内存。
用户体验
  • 用户可以通过鼠标拖拽(结合 OrbitControls)查看全景图,体验流畅。
  • 背景的渲染质量高,适合需要沉浸式体验的场景(如虚拟现实、3D 游戏)。
性能
  • GPU 加速CubeTexture 由 GPU 直接渲染,性能非常高。
  • 内存占用:六张高分辨率图片可能会占用较多显存,但渲染效率高。

2. CSS3DRenderer

CSS3DRendererThree.js 提供的一种特殊渲染器,用于将 HTML/CSS 元素嵌入到 3D 场景中。

工作原理
  • 使用 HTML 和 CSS 元素(如 divimg)作为 3D 对象,通过 CSS3 的 transform 属性(如 translate3drotate3d)来模拟 3D 效果。
  • 通过 CSS3DObject 将 HTML 元素添加到场景中,并设置其位置和旋转角度。
优势
  1. 灵活性高
    • 可以直接嵌入动态 HTML 内容(如文本、按钮、视频等)。
    • 支持 DOM 操作,适合需要动态交互的场景。
  2. 易于集成
    • 可以与现有的 HTML/CSS 代码无缝结合,适合需要与前端 UI 交互的场景。
  3. 轻量级
    • 不需要复杂的纹理处理,直接使用 HTML 元素即可。
劣势
  1. 性能较低
    • 由于使用的是 DOM 元素,渲染性能依赖于浏览器的 CSS 引擎,性能不如 WebGL。
    • 在复杂场景中可能会出现卡顿。
  2. 渲染质量有限
    • 不支持光照、反射等高级渲染效果。
    • 渲染效果依赖于 CSS 的能力,无法达到 GPU 渲染的真实感。
  3. 图片拼接复杂
    • 如果使用图片作为背景,需要手动拼接六个面,且可能出现接缝问题。
用户体验
  • 用户可以通过鼠标拖拽查看全景图,但由于性能限制,可能会出现卡顿。
  • 支持动态内容(如按钮、文本),适合需要交互的场景。
性能
  • CPU 渲染CSS3DRenderer 使用浏览器的 CSS 引擎进行渲染,性能依赖于 CPU。
  • 内存占用:由于使用 DOM 元素,内存占用较低,但渲染效率较低。

对比总结

特性THREE.CubeTextureLoaderCSS3DRenderer
渲染方式WebGL(GPU 加速)CSS3(CPU 渲染)
灵活性低:仅支持静态背景高:支持动态 HTML 内容
渲染质量高:支持光照、反射等高级效果中:依赖 CSS,无法实现真实感渲染
性能高:适合复杂场景较低:适合简单场景
图片要求六张无缝拼接的高质量图片六张图片,需要手动拼接
用户体验流畅、真实感强灵活,但可能卡顿
适用场景游戏、虚拟现实、沉浸式全景图动态交互、嵌入 HTML 内容的全景图

适用场景建议

  1. 使用 THREE.CubeTextureLoader 的场景

    • 需要高质量的全景图渲染(如 3D 游戏、虚拟现实)。
    • 需要环境反射或折射效果。
    • 场景较复杂,且对性能要求较高。
  2. 使用 CSS3DRenderer 的场景

    • 需要嵌入动态 HTML 内容(如按钮、文本、视频)。
    • 需要与前端 UI 进行交互。
    • 场景较简单,且对渲染质量要求不高。

总结

  • 如果你需要高性能、高质量的全景图渲染,推荐使用 THREE.CubeTextureLoader
  • 如果你需要动态交互或嵌入 HTML 内容,推荐使用 CSS3DRenderer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85667.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

老牌软件 Ghost 备份还原操作基础

一、Ghost 简介 Symantec Ghost&#xff08;也称为 Norton Ghost&#xff09; 是一款强大的磁盘克隆和备份还原工具&#xff0c;广泛用于系统部署、数据恢复和灾难恢复。其主要功能包括&#xff1a; 创建磁盘镜像&#xff08;.GHO文件&#xff09;备份/还原分区或整个硬盘支持…

SSH连接服务器并同步本地文件

SSH连接服务器并同步本地文件 1. 复制本地公钥 cat ~/.ssh/id_rsa.pub如果不确定本地是否有公钥 ls ~/.ssh/id_rsa.pub# 如果出现如下&#xff0c;则说明你本地存在公钥 # /Users/username/.ssh/id_rsa.pub若没有公钥&#xff0c;需生成 # 使用下面命令&#xff0c;然后一路回…

中英泰马来语订货系统:助力东南亚批发贸易企业数字化转型升级

随着全球数字化转型浪潮的推进&#xff0c;东南亚地区的批发贸易企业也正逐步迈向数字化发展道路。特别是在中英泰马来语订货系统的推动下&#xff0c;东南亚的批发商和零售商能够更高效、便捷地开展跨国贸易与供应链管理。这不仅帮助传统企业提高了运营效率&#xff0c;还助力…

微信小程序获取指定元素,滚动页面到指定位置

微信小程序获取指定元素&#xff0c;滚动页面到指定位置 微信小程序获取指定元素的宽高等信息,并滚动页面到指定位置 微信小程序获取指定元素的宽高等信息,并滚动页面到指定位置 注&#xff1a;原生小程序开发&#xff1a; createSelectorQuery() 创建一个选择器查询实例。 sel…

LeetCode热题100—— 118. 杨辉三角

https://leetcode.cn/problems/pascals-triangle/description/?envTypestudy-plan-v2&envIdtop-100-liked 题解 代码 public List<List<Integer>> generate(int numRows) {List<List<Integer>> datatList new ArrayList<>();for(int i …

Python函数/Lambda/nested function/decorator/kwargs:全面教程

目录 函数简介基本函数语法函数参数返回值高级函数概念列表推导式与Lambda函数实用示例 函数简介 函数是可重用的代码块&#xff0c;用于执行特定任务。它们有助于组织代码&#xff0c;促进复用&#xff0c;并使程序更易于维护。可以将函数视为程序中的小型程序。 基本函数…

UG NX二次开发(C++)-创建草图(基于平面、X轴和参考点)

文章目录 1、前言2、在UG NX中的操作3、代码实现3.1 添加头文件3.2 在项目中声明一个创建草图的函数3.3 创建草图函数的实现代码3.4 函数调用3.5 实现效果1、前言 作为一款大型的CAD/CAM软件,UG NX在建模中草图的作用非常重要,功能也非常强大,所以在UG NX中学会草图的二次开…

计算机视觉课程笔记-机器学习中典型的有监督与无监督学习方法的详细分类、标签空间性质、解释说明,并以表格形式进行总结

✅ 一、有监督学习&#xff08;Supervised Learning&#xff09; 定义&#xff1a;有监督学习中&#xff0c;模型训练依赖于已标注的样本&#xff0c;即输入和输出&#xff08;标签&#xff09;成对出现。 标签空间可能是&#xff1a; 离散型&#xff08;Discrete&#xff09…

HTTPS加密原理

一、什么是HTTPS&#xff1f; 1.1 https是在http协议上加了一层加密解密层 如图&#xff1a; https协议就是在http协议的基础上经过一层加密解密层发送&#xff0c;然后接收端同样需要经过加密解密层才能获取到发送过来的数据&#xff0c;这样就可以保证数据传输的安全性&…

无人机测量风速的思路

无人机测量风速主要依靠两种思路&#xff1a;直接测量和间接测量&#xff08;估算&#xff09;。具体方法取决于无人机的类型、搭载的传感器以及应用场景。 以下是主要的测量方法&#xff1a; 直接测量法&#xff08;使用气象传感器&#xff09;&#xff1a; 原理&#xff1a;…

24. 开发者常用工具:抓包,弱网模拟,元素检查

打开网页F12进入开发者页面。 ctrl shift n进入无痕模式&#xff0c;不会自动清理cookie&#xff0c;便于保持登陆状态 本文介绍浏览器开发者工具中三个常用功能&#xff1a;抓包并导入 Postman、模拟弱网环境、检查页面元素与样式。可用于前端调试、接口分析、页面优化等场景…

将 Burp Suite 的请求复制到 Postman

将 Burp Suite 的请求复制到 Postman 的步骤如下&#xff1a; 方法 1&#xff1a;直接复制原始请求&#xff08;推荐&#xff09; 在 Burp 中捕获请求 在 Proxy → HTTP history 或 Target → Site map 中找到目标请求。右键请求 → &#xff08;Copy&#xff09; → Copy as c…

MySQL RC隔离级别惊现间隙锁:是bug吗?

在MySQL的默认事务隔离级别——读已提交&#xff08;Read Committed, RC&#xff09;中&#xff0c;开发者普遍认为不会出现间隙锁&#xff08;Gap Lock&#xff09;。这一认知源于RC级别的设计原则&#xff1a;仅通过行锁确保已提交数据的可见性&#xff0c;而将幻读问题交由应…

恢复MacOS 26系统后台的动作命令

1、终端 输入 sudo mkdir -p /Library/Preferences/FeatureFlags/Domain回车后输入mac解锁密码。 2、输入强制关闭命令 sudo defaults write /Library/Preferences/FeatureFlags/Domain/SpotlightUI.plist SpotlightPlus -dict Enabled -bool false它会“强制关闭 Spotlight…

01-JS资料

JS数据类型 var str abc; var num 123; var bool true; var und undefined; var n null; var arr[x,y,z]; var obj {}; var fun function() {}; console.log(typeof str); //string console.log(typeof num); //number console.log(typeof bool); //boolean consol…

学习日记-day34-6.20

知识点&#xff1a; 1.快速入门 知识点 核心内容 重点 IOC容器创建 通过ClassPathXmlApplicationContext加载XML配置文件创建容器&#xff0c;关联beans.xml 容器与配置文件的绑定关系&#xff08;多配置文件支持&#xff09; Bean获取方式 1. getBean(String id)返回…

如何使用 neptune.ai 优化模型训练期间的 GPU 使用率

GPU 可以大大加速深度学习模型的训练&#xff0c;因为它们专门用于执行神经网络核心的张量运算。 由于 GPU 是昂贵的资源&#xff0c;因此充分利用它们至关重要。GPU 使用率、内存利用率和功耗等指标可以洞悉资源利用率及其改进潜力。提高 GPU 使用率的策略包括混合精度训练、优…

腾讯混元3D制作简单模型教程-1

腾讯混元3D制作简单模型的零门槛教程,涵盖新手快速入门与进阶操作,结合官方工具特性及行业实践,分为两个核心板块: 🎯 一、新手零门槛:5分钟生成可打印模型(适合完全小白) 通过腾讯元宝APP的“3D角色梦工厂”功能,无需任何建模基础: 上传照片 打开腾讯元宝APP → …

一个库,比如kott_tinymce ,想把的依赖库从kotti升级到kotti2 ,请问我是不是查找替换,把所有的kotti字符替换成kotti2就行了?

一个库&#xff0c;比如kott_tinymce ,想把的依赖库从kotti升级到kotti2 &#xff0c;请问我是不是查找替换&#xff0c;把所有的kotti字符替换成kotti2就行了&#xff1f; kotti和kotti2的包结构、模块路径、接口完全一样&#xff0c;除了import kotti 变成kotti2 如果 kotti…

企业实践 | 银河麒麟KylinOS-V10(SP3)高级服务器操作系统基础安装指南

前言&#xff1a;国产操作系统的崛起与实践背景 在国产化浪潮与信息技术自主可控的大背景下&#xff0c;银河麒麟操作系统作为国产操作系统的代表之一&#xff0c;正逐步成为企业级应用的重要选择。本文将详细介绍银河麒麟高级服务器操作系统V10 SP3版本的基础知识与安装实践&…