Realsee 以 WebGPU 全面重寫了空間渲染器,目標是追求極致 3D 體驗。重寫覆蓋從全景與模型顯示,到高清圖塊、材質、插件和圖像輸出的完整鏈路。
用戶轉動視角、放大細節、在拍攝位置間移動,或切換帶紋理的模型查看佈局時,渲染器都要承接這些操作。標註、視頻、測量與導覽,也要與空間中的具體位置保持對應。[1]
高清資源要跟隨當前視野,影像與模型要保持一致的材質與顏色處理。主播放器、空間插件、輔助畫布和截圖,也要共享同一套資源與輸出規則。
WebGPU 與 WebGL、WebGL2 的區別
WebGL、WebGL2 和 WebGPU 都能使用 GPU 繪製三維畫面。WebGL2 在 WebGL 的基礎上擴展圖形能力,將實例化繪製、多渲染目標等納入核心,並增加統一變量緩衝、三維紋理和 Transform Feedback。Transform Feedback 可以把頂點著色器的輸出保存到緩衝區,供後續處理使用。[2] [3]
WebGPU 面向 Metal、Vulkan、Direct3D 12 等現代圖形接口,重新組織管線、資源綁定和命令提交,同時提供通用 GPU 計算。[4]
| 對比 | WebGL | WebGL2 | WebGPU |
|---|---|---|---|
| API 設計基礎 | OpenGL ES 2.0 | OpenGL ES 3.0 | 面向現代 GPU 接口 |
| 核心能力 | 圖形繪製 | 更完整的圖形繪製與數據處理 | 圖形繪製與通用 GPU 計算 |
| GPU 數據計算 | 利用著色器與紋理組織計算 | 還可用 Transform Feedback 保存頂點結果 | 計算管線、可讀寫存儲緩衝和工作組 |
| 應用側任務組織 | 修改上下文狀態,發出繪製調用 | 延續該模型,增加批量傳參等能力 | 明確管線與資源綁定,編碼命令後提交隊列 |
| 著色器語言 | GLSL ES 1.00 | 支持 GLSL ES 3.00,並保留 1.00 能力 | WGSL |
繪製狀態可以更明確地組織和複用。 WebGPU 把著色器、頂點佈局、深度和混合狀態等配置組織為管線對象。[5] 繪製時選擇管線並綁定資源,多個繪製任務可以複用固定配置;命令緩衝則讓瀏覽器和驅動基於一批任務安排執行。Chrome 官方將降低相同畫面所需的 JavaScript 工作量列為 WebGPU 的主要收益。[6]
圖形與計算擁有各自的程序模型。 計算管線、存儲緩衝和間接調度可以承載並行數據處理,為引擎擴展算法提供基礎。[5] 日常全景與紋理模型瀏覽主要通過圖形管線完成:CPU 組織視野相關資源,GPU 負責圖像採樣、材質計算和場景繪製。
擴展亮度可以接入畫布輸出。 對帶 HDR 數據的全景,恢復出的高亮值需要沿渲染過程保留下來。WebGPU 的半浮點畫布格式配合 extended 輸出模式,可把這些數值用於支持 HDR 的顯示環境。[7] 這讓全景影像的亮度信息能夠一直參與到最終呈現。
全景與模型怎樣共同成像
全景照片提供表面顏色,模型提供空間位置與形狀。模型材質根據表面位置,以及全景的拍攝位置和方向計算採樣,再組合全景顏色與模型自身的材質輸出。場景還保留全景背景,用來覆蓋模型表面之外的視野。
帶過渡的點位切換需要同步處理相機和圖像。前後兩個點位的全景資源參與材質更新,相機的位置、朝向和視場角隨所選移動效果變化,兩組全景顏色按過渡規則組合。進入模型視圖時,再調整全景與模型材質的呈現權重,讓用戶從照片細節轉向觀察整體結構。遷移材質時,這些採樣關係和過渡行為需要一起保留。
高清圖塊按當前視野加載
全景的清晰度需求隨視場角、畫布尺寸和像素比變化。我們據此選擇圖塊級別,再由 CPU 檢查圖塊是否與當前視錐相交。請求按較低級別優先、同級靠近畫面中心優先的順序安排,並限制同時進行的請求數量。用戶放大窗邊或牆面的細節時,資源加載便優先補充當前視野需要的區域。
基礎全景先提供完整內容,新圖塊加載後逐漸顯現。基礎圖與已加載的高清圖塊被繪製成對應當前視角的細節紋理,再交給主場景材質按投影位置採樣。視野細節紋理與最終場景畫面承擔不同任務:前者為全景材質補充清晰度,後者包含場景繪製結果,供輸出和後處理使用。

視野細節紋理用於全景材質採樣,場景畫面用於輸出和可選後處理。
全線遷移涉及哪些挑戰
Realsee 把主 VR、空間插件、戶型圖、導覽、小地圖、商品與模型預覽,以及截圖和封面輸出,都納入這輪渲染體系遷移。主場景之外,一些組件擁有獨立的相機和畫布;另一些組件依賴已有材質、顏色和截圖約定。遷移需要讓這些入口共同使用新的渲染能力。
材質遷移要保留既有視覺行為
Three.js 的 WebGPU 渲染器使用節點材質,原有自定義 GLSL 材質需要改寫為 Three.js 著色語言(TSL)。TSL 用節點組合描述著色過程,並可根據後端生成 WGSL 或 GLSL。[8]
我們遷移了全景視頻、導覽線、小模型背景和粒子等材質,同時保留它們的投影、遮罩、漸隱和深度關係。測量線還有一個容易漏掉的狀態:用戶剛開始操作,第一段線尚未形成。這裡需要先準備合法的幾何輸入佈局,把可見實例數保持為零,等端點齊備後再繪製。
跨包依賴也要一起調整。主引擎和空間插件的 Three.js 依賴由宿主提供;插件打包時外置這項依賴,宿主統一版本與解析入口。獨立模型預覽再註冊主引擎使用的模型材質映射,讓加載出的模型進入對應的節點材質體系。
顏色和透明度要沿著合成過程核對
同一段視頻換到新渲染器後,可能出現偏亮。我們定位到的一類原因是:視頻像素已經採用 sRGB 編碼,卻被當作線性顏色,再做了一次輸出編碼。處理辦法是明確聲明視頻紋理的顏色空間,讓輸入解碼與最終輸出轉換各司其職。Three.js 的視頻紋理文檔也明確了這一輸入要求。[9]
透明媒體、導覽線和已有標註還要與背景合成。透明媒體分別設置顏色與 alpha 的混合方式,線條保留已經繪製的背景;已有標註則在合成邊界處理工作空間與顯示編碼,讓保存的顏色沿用原有含義。這裡需要同時看輸入顏色、線性工作空間與顯示編碼;單獨調整亮度會掩蓋轉換環節的錯誤。[10]
初始化、退出和設備重建要形成完整生命週期
WebGPU 渲染器的初始化是異步過程。[8] 模型預覽和獨立指南針會等待渲染器準備完成,再建立依賴資源或開始繪製。用戶快速切換預覽時,模型加載結果還要確認自己屬於當前請求;已經過期的結果直接釋放,當前畫面繼續響應最新操作。
關閉商品預覽時,先取消請求與動畫、移除監聽;待初始化結束後釋放實例並移除畫布。GPU 設備丟失則進入另一條處理路徑:主視圖先保存瀏覽狀態,釋放舊會話,再建立新會話,按資源加載順序恢復視角和樓層。採用共享獨立渲染器封裝的插件畫布,會重建渲染器,恢復尺寸、像素比和透明背景,待新實例就緒後替換畫布。主視圖與這些插件畫布分別負責各自的資源重建。
截圖和封面也要適配新的像素輸出
這條截圖路徑先把所需區域繪製到 RGBA8 目標,再異步將像素從 GPU 讀回 CPU。使用 WebGPU 的 copyTextureToBuffer 複製多行這類像素時,行步長需要是 256 字節的整數倍。例如,寬 100 像素的 RGBA8 圖像,每行有 400 字節顏色數據,複製佈局可以採用 512 字節的行步長;交給普通圖像處理之前,要取出每行的 400 字節有效像素。[5]
讀回層先檢查數據長度:已經緊密排列就直接複製,帶有行末空隙時逐行取出有效像素。宿主再按所用 SDK 的實際後端行為統一輸出行向。裁剪區域仍沿用底部原點座標,輸出像素行按從上到下排列後交給圖像畫布。裁剪和封面共用這層適配,臨時隱藏的輔助元素在截圖結束後恢復。
讓沒有變化的畫面繼續使用
畫面複用與按需更新適用於 WebGL2 和 WebGPU 兩種後端,由渲染引擎決定更新規則。相機停在一個位置時,場景可能已經靜止,某個動畫效果卻還在運行。如果每次更新效果都重新處理整個場景,就會重複執行本來沒有變化的工作。
在 Realsee 的渲染實現中,我們把場景合成與後處理分開。場景合成產生一幅中間畫面,後處理在這幅畫面上繼續添加效果。只要場景內容沒有發生相關變化,這個中間結果就可以留給後續繪製使用。
這個中間結果有明確的失效條件:
| 發生的變化 | 渲染器需要做什麼 |
|---|---|
| 相機或場景內容變化 | 重新合成場景;舊畫面已經不再對應當前視圖 |
| 圖像資源到達、視頻有新幀 | 將變化傳給場景更新,避免繼續顯示舊內容 |
| 後處理仍啟用,且啟用數量或依賴的輸入種類變化 | 重新準備對應的合成結果 |
| 關閉最後一個後處理 | 應用請求一次更新,輸出不含該效果的畫面 |
| 視口尺寸變化 | 重建輸出資源,再按新尺寸合成 |
| 場景不變,但動畫類後處理繼續運行 | 複用場景畫面,繼續計算後處理效果 |
切換效果時,調用方需要請求一幀更新;關閉最後一個後處理時,這一幀把不含該效果的畫面輸出到屏幕。隨後,未啟用後處理且場景沒有更新時,渲染器可以跳過畫面輸出。仍啟用後處理時,處理步驟繼續讀取保留的場景畫面,新工作照常編碼並提交給 GPU。
保存中間畫面會佔用顯存,格式選擇也會影響讀寫量。以保存顏色輸出的紋理,也就是顏色附件為例:尺寸為 1920 × 1080,單層、單採樣,不生成多級紋理(mipmap)。RGBA8 由四個 8 位通道組成,RGBA16F 則是四個 16 位浮點通道;按 texel(紋理像素)計算存儲量:[5]
| 顏色格式 | 每個 texel | 宽 × 高 × 字节数 |
存儲量 |
|---|---|---|---|
| RGBA8 | 4 字節 | 1920 × 1080 × 4 | 約 7.9 MiB |
| RGBA16F | 8 字節 | 1920 × 1080 × 8 | 約 15.8 MiB |
這裡 1 MiB = 1,048,576 字節,深度、緩衝副本、其他附件和分配對齊另行計入。寬和高都變為原來的兩倍,同格式的顏色存儲就會變為原來的四倍。這些數值描述顏色 texel 的存儲空間;一幀的讀寫成本還取決於渲染過程怎樣訪問這些紋理。選擇輸出精度時,需要同時考慮容量和訪問方式。Three.js 的文檔也將畫質與內存、帶寬作為共同取捨。[11]
圖塊的資源複用另有一層管理。近期使用、仍在緩存中的圖塊可以繼續提供紋理,超出緩存範圍後再釋放資源;需要新的紋理對象時,複用池按尺寸和顏色空間匹配。這樣既能保留已加載的細節,也能讓顏色圖與數據紋理沿用各自正確的解釋方式。
讓視頻驅動畫面更新
按需渲染需要知道場景何時改變。相機靜止時,全景裡播放的視頻仍會產生新內容,所以媒體組件也要負責通知渲染器。
收到“開始播放”的事件時,未必已經有可供繪製的視頻幀。我們的組件會檢查當前幀是否可用,以及視頻是否屬於正在觀看的全景,再讓它進入場景。播放期間,組件持續請求場景重繪,並在紋理尚未更新時補充更新請求;即使相機沒有移動,媒體畫面也能繼續推進。
暫停時,組件撤銷播放期間的繪製調度;銷燬時,釋放視頻紋理、幾何和材質。對遲到的播放、暫停或卸載事件,還要結合組件當前狀態處理,避免上一段播放過程干擾新畫面。
兼容 WebGPU 與 WebGL 2
WebGPU 的可用性取決於瀏覽器、操作系統和 GPU。瀏覽器除了提供相應接口,還需要提供滿足應用要求的可用 GPU 設備。[6] [4]
Three.js 的 WebGPU 渲染器支持 WebGPU 和 WebGL 2 兩種後端。[11] Realsee 保留了對應的渲染路徑,並在初始化後確認實際後端。全景、模型和空間組件使用與後端匹配的材質與資源,截圖等輸出環節也按實際後端適配。
應用需要讓視點移動、模式切換和媒體更新分別接入對應後端。相同的內容可以有不同的繪製方法,具體效果也應與所選路徑的能力匹配。
從 npm 體驗 WebGPU 版本
開發者可以使用 npm 上的 Five WebGPU 開始構建空間瀏覽。核心 SDK 通過 alpha 通道發佈 WebGPU 版本;本文對應 1.0.0-alpha.11,與 three@0.183.2 配套。[12]
npm install --save-exact three@0.183.2 @realsee/five-webgpu@1.0.0-alpha.11
需要標籤、測量、導覽等空間插件時,可追加 Dnalogel 的 WebGPU 版本,本文使用 4.0.0-webgpu.6。插件與核心 SDK 使用同一份 Three.js。[13]
npm install --save-exact @realsee/dnalogel@4.0.0-webgpu.6
可以先在 Realsee Discover 探索餐廳、住宅、博物館和零售等類型的公開空間案例。[14]
開發者可以訪問 Realsee 開發者平臺,瞭解空間瀏覽能力並構建自己的應用。
參考資料
- [1] Realsee Developer Platform
- [2] WebGL — Khronos 規範
- [3] WebGL 2.0 — Khronos 規範
- [4] WebGPU Explainer — GPU for the Web Community Group
- [5] WebGPU — W3C
- [6] Overview of WebGPU — Chrome for Developers
- [7] HDR support with canvas tone mapping — Chrome for Developers
- [8] WebGPURenderer — Three.js 遷移指南
- [9] VideoTexture — Three.js 官方文檔
- [10] Color Management — Three.js 官方說明
- [11] WebGPURenderer — Three.js 官方文檔
- [12] Five WebGPU — npm 1.0.0-alpha.11
- [13] Dnalogel WebGPU — npm 4.0.0-webgpu.6
- [14] Realsee Discover — 公開空間案例集合

