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
英文地址,請注明出處:http://en.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版本的基礎知識與安裝實踐&…