前提
有一个前提条件:六张大小一致的图片,六个图片分别对应的是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
,并且每个面都有对应的纹理图像。
javascript
camera = new THREE.PerspectiveCamera(90, boxWidth / boxHeight, 0.1, 1000);
scene = new THREE.Scene();
- 渲染器设置 :
CSS3DRenderer
用来渲染带有 HTML 内容的 3D 场景。它允许你将普通的 HTML 元素(如div
、img
等)作为 3D 场景中的对象进行渲染。这里会设置它的大小并将其添加到 DOM 中。
javascript
renderer = new CSS3DRenderer();
renderer.setSize(boxWidth, boxHeight);
document.getElementById("surfaceBox").appendChild(renderer.domElement);
2. 创建全景图面 (六个面)
全景图的每一面都是一个 CSS3DObject
,这是一种特殊的 THREE.js
对象,能够将 HTML 元素渲染到 3D 场景中。代码会为每个方向(前、后、左、右、上、下)创建一个面,并且通过 position
和 rotation
属性将它们放置到合适的空间。
javascript
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. 事件绑定与鼠标交互
通过监听 mousemove
、mousedown
和 mouseup
事件,实现用户与全景图的交互。具体来说,用户通过鼠标拖动来控制全景图的旋转。代码的核心是通过监听鼠标的移动事件来更新 lon
(经度)和 lat
(纬度),控制视角的改变。
- 鼠标按下 (
mousedown
):当用户按下鼠标时,开始监听鼠标的移动事件,用来更新视角。 - 鼠标移动 (
mousemove
) :当鼠标移动时,根据鼠标的移动距离来更新lon
和lat
,实现图像的旋转。 - 鼠标抬起 (
mouseup
):鼠标抬起时,停止监听鼠标移动事件。
javascript
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; // 水平拖动影响 lon
targetLat += movementY * 0.1; // 垂直拖动影响 lat
targetLat = Math.max(-85, Math.min(85, targetLat)); // 限制 lat 范围
}
4. 视角和动画渲染
通过 animate
函数实现场景的动画和相机视角的动态更新。animate
函数会通过 requestAnimationFrame
来不断更新视图。相机的 lookAt
方法确保相机始终指向一个目标点,从而实现平滑的旋转效果。
javascript
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
函数监听浏览器窗口的变化,自动调整相机的宽高比和渲染器的大小,确保全景图在不同屏幕和窗口大小下都能正常显示。
javascript
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. 触摸支持
为了支持移动设备的触摸事件,使用了 touchstart
和 touchmove
事件来替代 mousemove
事件。触摸事件处理函数会跟踪触摸点的变化,并根据触摸的移动更新视角。
javascript
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;
}
完整代码
~~
js
<template>
<div class="surface_box" id="surfaceBox">
<!--
6个面:代码中通过6个 div(每个 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-2
rotation: [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)], //hou
rotation: [0, 0, 0],
},
];
//根据六个面的信息,创建六个对象放入场景中
for (let i = 0; i < sides.length; i++) {
let side = sides[i];
// 获取平面的dom
let 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; // 水平拖动,调整 lon
targetLat -= 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()
CubeTextureLoader
是Three.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
) :加载完成后的回调函数。这里将加载的纹理设置为场景的背景:javascriptscene.background = texture;
-
第三个参数 (
onProgress
) :加载进度的回调函数。可以用来显示加载进度,例如:javascriptconsole.log(`加载进度: ${(progress.loaded / progress.total) * 100}%`);
-
第四个参数 (
onError
):加载失败的回调函数。如果某张图片加载失败,会触发该函数并输出错误信息。
-
3. scene.background = texture
- 将加载的立方体纹理设置为场景的背景。
scene.background
是一个特殊属性,用于设置场景的背景,可以是颜色(如0x000000
)或纹理(如CubeTexture
)。- 设置为
CubeTexture
后,场景会被六张图片包围,形成一个 360 度的全景环境。
运行效果
- 六张图片会被加载并组合成一个立方体纹理,作为场景的背景。
- 用户可以通过
OrbitControls
拖拽相机,查看不同方向的背景。 - 如果某张图片加载失败,会在控制台输出错误信息。
总结
这段代码的核心功能是:
- 使用
CubeTextureLoader
加载六张图片,生成一个立方体纹理。 - 将立方体纹理设置为场景的背景,形成一个 360 度的全景环境。
- 提供加载完成、加载进度和加载失败的回调函数,方便调试和监控资源加载状态。
完整代码
js
<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>
<div
id="cubeContainer"
style="width: 100%; height: 100vh; background: #000"
></div>
</template>
<style scoped>
#cubeContainer {
overflow: hidden;
}
</style>
----------------------------------------------------------------------------------------------------------------------------
三、两种方式的区别:
THREE.CubeTextureLoader
和 CSS3DRenderer
是 Three.js
中两种不同的技术,用于生成 3D 全景图。它们的实现方式、适用场景、性能以及用户体验各有不同。以下是对两者的详细分析和对比:
1. THREE.CubeTextureLoader
CubeTextureLoader
是 Three.js
提供的一种加载立方体纹理的方法,通常用于创建环境贴图(Environment Map)或背景全景图。
工作原理
- 使用六张图片(分别对应立方体的六个面:前、后、左、右、上、下)加载一个立方体纹理。
- 将立方体纹理设置为场景的背景(
scene.background
),或者映射到物体的材质上(如envMap
)。 - 用户通过相机的旋转来查看不同方向的背景。
优势
- 高性能 :
- 立方体纹理直接由 GPU 渲染,性能非常高。
- 适合大规模场景或需要实时渲染的应用(如游戏、虚拟现实)。
- 真实感强 :
- 支持环境反射(
envMap
)和折射效果,可以用于模拟真实的光照和反射。 - 适合需要高质量渲染的场景。
- 支持环境反射(
- 简单易用 :
- 只需提供六张图片即可生成全景图。
- 与
Three.js
的其他功能(如光照、材质)无缝集成。
劣势
- 灵活性较低 :
- 只能用于渲染静态背景,无法直接嵌入动态 HTML 内容。
- 不支持直接操作 DOM 元素。
- 对图片要求较高 :
- 六张图片需要严格按照立方体的六个方向(前、后、左、右、上、下)排列,且需要无缝拼接。
- 图片分辨率较高时可能会占用较多内存。
用户体验
- 用户可以通过鼠标拖拽(结合
OrbitControls
)查看全景图,体验流畅。 - 背景的渲染质量高,适合需要沉浸式体验的场景(如虚拟现实、3D 游戏)。
性能
- GPU 加速 :
CubeTexture
由 GPU 直接渲染,性能非常高。 - 内存占用:六张高分辨率图片可能会占用较多显存,但渲染效率高。
2. CSS3DRenderer
CSS3DRenderer
是 Three.js
提供的一种特殊渲染器,用于将 HTML/CSS 元素嵌入到 3D 场景中。
工作原理
- 使用 HTML 和 CSS 元素(如
div
、img
)作为 3D 对象,通过 CSS3 的transform
属性(如translate3d
、rotate3d
)来模拟 3D 效果。 - 通过
CSS3DObject
将 HTML 元素添加到场景中,并设置其位置和旋转角度。
优势
- 灵活性高 :
- 可以直接嵌入动态 HTML 内容(如文本、按钮、视频等)。
- 支持 DOM 操作,适合需要动态交互的场景。
- 易于集成 :
- 可以与现有的 HTML/CSS 代码无缝结合,适合需要与前端 UI 交互的场景。
- 轻量级 :
- 不需要复杂的纹理处理,直接使用 HTML 元素即可。
劣势
- 性能较低 :
- 由于使用的是 DOM 元素,渲染性能依赖于浏览器的 CSS 引擎,性能不如 WebGL。
- 在复杂场景中可能会出现卡顿。
- 渲染质量有限 :
- 不支持光照、反射等高级渲染效果。
- 渲染效果依赖于 CSS 的能力,无法达到 GPU 渲染的真实感。
- 图片拼接复杂 :
- 如果使用图片作为背景,需要手动拼接六个面,且可能出现接缝问题。
用户体验
- 用户可以通过鼠标拖拽查看全景图,但由于性能限制,可能会出现卡顿。
- 支持动态内容(如按钮、文本),适合需要交互的场景。
性能
- CPU 渲染 :
CSS3DRenderer
使用浏览器的 CSS 引擎进行渲染,性能依赖于 CPU。 - 内存占用:由于使用 DOM 元素,内存占用较低,但渲染效率较低。
对比总结
特性 | THREE.CubeTextureLoader |
CSS3DRenderer |
---|---|---|
渲染方式 | WebGL(GPU 加速) | CSS3(CPU 渲染) |
灵活性 | 低:仅支持静态背景 | 高:支持动态 HTML 内容 |
渲染质量 | 高:支持光照、反射等高级效果 | 中:依赖 CSS,无法实现真实感渲染 |
性能 | 高:适合复杂场景 | 较低:适合简单场景 |
图片要求 | 六张无缝拼接的高质量图片 | 六张图片,需要手动拼接 |
用户体验 | 流畅、真实感强 | 灵活,但可能卡顿 |
适用场景 | 游戏、虚拟现实、沉浸式全景图 | 动态交互、嵌入 HTML 内容的全景图 |
适用场景建议
-
使用
THREE.CubeTextureLoader
的场景:- 需要高质量的全景图渲染(如 3D 游戏、虚拟现实)。
- 需要环境反射或折射效果。
- 场景较复杂,且对性能要求较高。
-
使用
CSS3DRenderer
的场景:- 需要嵌入动态 HTML 内容(如按钮、文本、视频)。
- 需要与前端 UI 进行交互。
- 场景较简单,且对渲染质量要求不高。
总结
- 如果你需要高性能、高质量的全景图渲染,推荐使用
THREE.CubeTextureLoader
。 - 如果你需要动态交互或嵌入 HTML 内容,推荐使用
CSS3DRenderer
。