空間包圍檢測(cè)在計(jì)算機(jī)圖形學(xué)、虛擬仿真、工業(yè)生產(chǎn)等有著廣泛的應(yīng)用。
現(xiàn)代煤礦開采過程中,安全一直是最大的挑戰(zhàn)之一。地質(zhì)空間中存在諸多如瓦斯積聚、地質(zhì)構(gòu)造異常、水文條件不利等隱蔽致災(zāi)因素,一旦被觸發(fā),可能引發(fā)災(zāi)難性的后果。因此在安全生產(chǎn)過程中有效的管理和規(guī)避各隱蔽致災(zāi)因素,有著重要的意義。
通過對(duì)煤礦地質(zhì)空間中各地質(zhì)因素建模,建立空間數(shù)據(jù)庫,還原地下真實(shí)場(chǎng)景,使用計(jì)算機(jī)圖形學(xué)進(jìn)行空間計(jì)算,可以實(shí)時(shí)監(jiān)測(cè)各隱蔽致災(zāi)因素的位置和距離,指導(dǎo)安全生產(chǎn),并進(jìn)行可視化展示。
空間包圍檢測(cè)有多種方法,比如基于包圍盒的檢測(cè),三角面碰撞檢測(cè)等。本文提出了一種基于 GPU 渲染的高效計(jì)算方法。
假定待檢測(cè)球體范圍的半徑為r。兩種檢測(cè)方法如下:
方法 1:遍歷模型所有的點(diǎn),計(jì)算點(diǎn)和球心的距離。如果有距離小于 r,模型在球體范圍內(nèi)。
方法 2:以檢測(cè)區(qū)域的包圍盒為正交投影空間,渲染所有需要檢測(cè)的模型。渲染過程中計(jì)算每個(gè)渲染點(diǎn)到球心的距離,如果有距離小于r的渲染點(diǎn),模型在球體范圍內(nèi)。
模型和檢測(cè)區(qū)域有以下幾種位置關(guān)系:
圖 1:模型完全在球體范圍內(nèi):方法 1 可檢測(cè)
圖 2:模型部分點(diǎn)在球體范圍內(nèi):方法 1 可檢測(cè)
圖 3:模型點(diǎn)不在球體范圍內(nèi),部分三角面在球形范圍內(nèi):方法 2 可檢測(cè)
圖 4:模型不在球體范圍內(nèi):方法 1 + 2 可檢測(cè)
圖 5:模型完全包含球體范圍:模型如果是空心的,方法 1 + 2 可檢測(cè)模型不在球體范圍內(nèi)。如果需要計(jì)算結(jié)果是模型在球體范圍內(nèi),也就是模型是實(shí)心的,建模時(shí)需要在模型內(nèi)部加上額外的輔助計(jì)算的三角面,用于表達(dá)內(nèi)部信息。此時(shí)用方法 1 + 2 可檢測(cè)模型在球體范圍內(nèi)。
以上方法使用 WebGL 渲染到紋理(Render To Texture) 和 readPixels 功能。圖撲 HT for Web SDK 組件庫對(duì) WebGL 底層復(fù)雜操作做了封裝, 為用戶省掉了繁瑣的底層 WebGL 操作,可以方便快捷的實(shí)現(xiàn)正交透視、渲染到紋理和異步 readPixels 等高級(jí) WebGL 功能。
方法 1:點(diǎn)檢測(cè)法
準(zhǔn)備一張 N X N 紋理圖 texture1(HT RenderTarget),保證要檢測(cè)的模型的數(shù)量不大于 N X N。每一個(gè)模型在紋理上分配一個(gè)像素,像素的位置為 (x,y)。
創(chuàng)建點(diǎn)渲染模式著色器程序,實(shí)現(xiàn)以下功能:
頂點(diǎn)著色器:檢測(cè)每個(gè)點(diǎn)到球心的距離,將距離是否小于r的信息傳給片段著色器。指定的位置 (x,y) 賦給 gl_Position。
片段著色器:如果距離小于 r, 渲染紅色,否則不渲染顏色。
JavaScript 程序遍歷每一個(gè)待檢測(cè)模型,將模型的頂點(diǎn)和模型在紋理上的位置 (x,y) 通過 attribute 和 uniform 傳給頂點(diǎn)著色器。所有模型渲染結(jié)束后,使用異步 readPixels 將渲染結(jié)果讀出來。通過判斷讀取結(jié)果里每個(gè)像素點(diǎn)顏色值,獲得模型是否在球體內(nèi)部信息。
主要代碼:
// 創(chuàng)建渲染材質(zhì)1 const texture1 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 100, 100); // 循環(huán)渲染所有的模型,結(jié)果保存到texture1。 for (let i = 0; i < nodeCount; i++) { data = datas[i]; tModel = getDataMesh(data); // 獲取模型網(wǎng)格信息 // 準(zhǔn)備著色器數(shù)據(jù) tModel.mat = model4.mat; tModel.matDef[DEFAULT_MAT_NAME] = model4.mat; tModel.mat.modelMat = data.getMatrix4().toArray(); x = i % 100; y = Math.floor(i / 100); model4.mat.uPos = [x / 100 * 2 - 1 + 1 / 200, 2 * y / 100 - 1 + 1 / 200]; // 渲染到texture1 g3d.setViewport(gl, 0, 0, 100, 100); g3d.renderModel(texture1, model4, { clear: false }); } // 讀取檢測(cè)結(jié)果 texture1.readPixelsAsync(0, 0, 100, 100, null, (result) =?> { for (let y = 0; y < 100; y++) { for (let x = 0; x < 100; x++) { // 遍歷像素點(diǎn),檢測(cè)是否是紅色 // ...... } } });
方法 2:面檢測(cè)法
準(zhǔn)備兩張紋理貼圖 texture1 和 texture2。Texture1 的要求同方法 1。Texture2 默認(rèn)使用 1000 X 1000 的分辨率。
創(chuàng)建兩套著色器。第一套著色器使用三角面渲染:
頂點(diǎn)著色器:正常計(jì)算頂點(diǎn)投影信息
片段著色器:檢測(cè)每一個(gè)點(diǎn)到球心的距離,如果小于 r,渲染紅色
第二套著色器使用點(diǎn)渲染:
頂點(diǎn)著色器:根據(jù)輸入的 texture2 坐標(biāo)(attribute),使用 texture2D 獲取對(duì)應(yīng)位置的顏色值,如果是紅色,表示模型在球體內(nèi)部,將此信息傳給片段著色器。模型在 texture1 上的位置信息 (x,y) 賦給 gl_Position。
片段著色器:如果距離小于 r, 渲染紅色,否則不渲染顏色。
JavaScript 程序遍歷每一個(gè)模型,使用著色器 1 將結(jié)果渲染到 texture2。渲染過程使用正交透視矩陣,視錐是球體的包圍盒。JavaScript 將 texture2 (uniform sampler2D)、texture2 每個(gè)像素的 x, y位置信息 (attribute)、模型在 texture1 上的位置信息 (uniform) 傳給頂點(diǎn)著色器 2。片段著色器 2 將模型是否在球體內(nèi)的信息渲染到 texture1。所有模型渲染結(jié)束后,使用異步 readPixels 將渲染結(jié)果讀出來。通過判斷讀取結(jié)果里每個(gè)像素點(diǎn)顏色值,獲得模型是否在球體內(nèi)部信息。
主要代碼:
// 創(chuàng)建渲染材質(zhì)1,2 const texture1 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 100, 100); const texture2 = new ht.graph3d.RenderTarget(g3d, g3d.getGL(), 1000, 1000); // 循環(huán)渲染所有的模型到texture2。texture2信息渲染到texture1 for (let i = 0; i < nodeCount; i++) { data = datas[i]; tModel = getDataMesh(data); // 獲取模型網(wǎng)格信息 // 準(zhǔn)備著色器1數(shù)據(jù) tModel.mat = model2.mat; tModel.matDef[DEFAULT_MAT_NAME] = model2.mat; tModel.mat.modelMat = data.getMatrix4().toArray(); // 渲染到texture2 g3d.setViewport(gl, 0, 0, 1000, 1000); g3d.renderModel(texture2, tModel, { clear: true }); // 準(zhǔn)備著色器2數(shù)據(jù) model3.mat.uImage = texture2.texture; x = i % 100; y = Math.floor(i / 100); model3.mat.uPos = [x / 100 * 2 - 1 + 1 / 200, 2 * y / 100 - 1 + 1 / 200]; // 渲染到texture1 g3d.setViewport(gl, 0, 0, 100, 100); g3d.renderModel(texture1, model3, { clear: false }); }
方法 1 簡(jiǎn)單快速。但檢測(cè)結(jié)果不準(zhǔn)確。方法 2 檢測(cè)結(jié)果準(zhǔn)確,但計(jì)算過程復(fù)雜。實(shí)際使用中兩種方法結(jié)合使用。首先使用方法 1 檢測(cè)。對(duì)于不在球體范圍內(nèi)的模型,再使用方法 2 檢測(cè)。
如果需要檢測(cè)橢球體范圍或者長(zhǎng)方體的范圍,可以獲取橢球體或長(zhǎng)方的變換矩陣,計(jì)算獲得逆矩陣。將逆矩陣應(yīng)用于每一個(gè)待檢測(cè)模型的節(jié)點(diǎn)。此時(shí)只需要檢測(cè)變換后的模型是否在單位圓或單位立方體內(nèi)即可。HT SDK 3D 引擎庫提供了豐富的數(shù)學(xué)計(jì)算 API,可以非常直觀簡(jiǎn)潔的實(shí)現(xiàn)以上功能。
審核編輯 黃宇
-
gpu
+關(guān)注
關(guān)注
28文章
4743瀏覽量
128997 -
檢測(cè)
+關(guān)注
關(guān)注
5文章
4492瀏覽量
91521 -
渲染
+關(guān)注
關(guān)注
0文章
69瀏覽量
10931
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論