天天看點

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

擷取模組化得到的三維模型并解析

STL****檔案

STL (STereoLithography, 立體光刻)是由3D Systems軟體公司創立、原本用于立體光刻計算機輔助設計軟體的檔案格式。它有一些事後諸葛的字頭語如“标準三角語言(Standard Triangle Language)”、“标準曲面細分語言(Standard Tessellation Language)”、“立體光刻語言(STereolithography Language)”和“(立體光刻曲面細分語言)”。許多套裝軟體支援這種格式,它被廣泛用于快速成型、3D列印和計算機輔助制造(CAM)。STL檔案僅描述三維物體的表面幾何形狀,沒有顔色、材質貼圖或其它常見三維模型的屬性。

STL格式有文字和二進碼兩種型式。二進碼型式因較簡潔而較常見。

ASCII格式

ASCII碼格式的STL檔案逐行給出三角面片的幾何資訊,每一行以1個或2個關鍵字開頭。

在STL檔案中的三角面片的資訊單元 facet 是一個帶矢量方向的三角面片,STL三維模型就是由一系列這樣的三角面片構成。整個STL檔案的首行給出了檔案路徑及檔案名。在一個 STL檔案中,每一個facet由7 行資料組成,facet normal 是三角面片指向實體外部的法矢量坐标,outer loop 說明随後的3行資料分别是三角面片的3個頂點坐标,3頂點沿指向實體外部的法矢量方向逆時針排列。

ASCII格式的STL 檔案結構如下:

//字元段意義

solidfilenamestl//檔案路徑及檔案名

facetnormalxyz//三角面片法向量的3個分量值

outerloop

vertexxyz//三角面片第一個頂點坐标

vertexxyz//三角面片第二個頂點坐标

vertexxyz//三角面片第三個頂點坐标

endloop

endfacet//完成一個三角面片定義

…//其他facet

解析輸出為:

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

二進制格式

二進制STL檔案用固定的位元組數來給出三角面片的幾何資訊。

檔案起始的80個位元組是檔案頭,用于存貯檔案名;(如下所示)

solid Exported from Blender-2078 (sub 0)
           

緊接着用 4 個位元組的整數來描述模型的三角面片個數,如下所示,即為一個三角得資訊。

facet normal -0.000000 0.000000 -1.000000
outer loop
vertex 1.000000 1.000000 -1.000000
vertex 1.000000 -1.000000 -1.000000
vertex -1.000000 -1.000000 -1.000000
endloop
endfacet
           

後面逐個給出每個三角面片的幾何資訊。每個三角面片占用固定的50個位元組,依次是:

3個4位元組浮點數(角面片的法矢量)

3個4位元組浮點數(1個頂點的坐标)

3個4位元組浮點數(2個頂點的坐标)

3個4位元組浮點數(3個頂點的坐标)個

三角面片的最後2個位元組用來描述三角面片的屬性資訊。

一個完整二進制STL檔案的大小為三角形面片數乘以 50再加上84個位元組。

二進制格式的STL 檔案結構如下:

UINT8//Header//檔案頭

UINT32//Numberoftriangles//三角面片數量

//foreachtriangle(每個三角面片中)

REAL32[3]//Normalvector//法線矢量

REAL32[3]//Vertex1//頂點1坐标

REAL32[3]//Vertex2//頂點2坐标

REAL32[3]//Vertex3//頂點3坐标

UINT16//Attributebytecountend//檔案屬性統計

解析輸出為:

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

OBJ檔案

obj(或者.obj)是一種幾何定義檔案格式,第一次是 Wavefront Technologies在他們的可視化加強動畫包裡面使用的。檔案格式是公開的,并能很好的在其他的3D應用中被支援。

Obj檔案格式是一種簡單的單獨表示3D幾何圖元的檔案格式——也就是,頂點的坐标,每個頂點紋理的UV坐标,頂點法向量,以及組成多邊形的面的頂點坐标、以及紋理UV坐标序列。面的頂點預設為逆時針順序,法向量不是必須的。OBJ檔案并非歸一化的,但是可以在注釋中加入縮放資訊。

Obj檔案可以是ASCII的編碼(.obj)方式也可以是二進制格式(.mod)。但是二進制類型其作為專利未公開,是以這裡不作讨論。以ASCII格式存儲的obj檔案必須用.obj作為檔案拓展名。

檔案的開始,有以哈希字元(#)開始的一行表示注釋。

# this is a comment
           

對于obj來說,一個obj格式的檔案可能包含了頂點資料,自由形式的曲面/表面屬性,繪制索引序列,自由形式的曲面/表面内容聲明,關聯自由形式的表面,組和渲染屬性資訊。大多數常見的繪制索引表現為幾何頂點,紋理坐标,頂點法線以及多邊形的面:

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-gK3xEAGG-1590112131477)(https://raw.githubusercontent.com/adonispeace/adonispeace.github.io/master/dailyPic/20200401/clip_image012.jpg “Image_border+rounded”)]{:.border.rounded}

通常處理obj檔案的時候,會抛棄頂點法線資料,而通過頂點資訊來進行計算。有了以上的頂點坐标、法線、紋理坐标等資訊,就可以進行3D模型檔案的渲染了。

解析輸出為:

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

g “Image_border+rounded”)]{:.border.rounded}

3DS檔案

3ds檔案是3D Max的一種二進制存儲格式,它始終沒被官方公開,但是也基本被大家hack出來了大半。其“格式”總的來說非常簡單,這裡介紹一個概念:chunk。3ds檔案裡的資料都是按chunk一塊一塊隔離的。每個chunk都有兩個标記:2個位元組大小的chunkId,用來辨別這個chunk存的是什麼資料。接着是一個4個位元組大小的chunkLen,它根據chunkId不同,可能表示該chunk的大小,也可能表示下一個chunk的位置偏移。

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

chunk Id 2 Byte

chunk Len  4 Byte

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

想要讀取3ds檔案,chunk Id是比較重要的部分,下面是hack出來的常用Id:

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

0x4D4D // Main Chunk

├─ 0x3D3D // 3D Editor Chunk

│ ├─ 0x4000 // Object Block

│ │ ├─ 0x4100 // Triangular Mesh

│ │ │ ├─ 0x4110 // Vertices List

│ │ │ ├─ 0x4120 // Faces Description

│ │ │ │ └─ 0x4130 // Faces Material

│ │ │ ├─ 0x4140 // Mapping Coordinates List

│ │ │ │ └─ 0x4150 // Smoothing Group List

│ │ │ └─ 0x4160 // Local Coordinates System

│ │ ├─ 0x4600 // Light

│ │ │ └─ 0x4610 // Spotlight

│ │ └─ 0x4700 // Camera

│ └─ 0xAFFF // Material Block

│ ├─ 0xA000 // Material Name

│ ├─ 0xA010 // Ambient Color

│ ├─ 0xA020 // Diffuse Color

│ ├─ 0xA030 // Specular Color

│ ├─ 0xA200 // Texture Map 1

│ ├─ 0xA230 // Bump Map

│ └─ 0xA220 // Reflection Map

│ │

│ ├─ 0xA300 // Mapping Filename

│ └─ 0xA351 // Mapping Parameters

└─ 0xB000 // Keyframer Chunk

├─ 0xB002 // Mesh Information Block

├─ 0xB007 // Spot Light Information Block

└─ 0xB008 // Frames (Start and End)

├─ 0xB010 // Object Name

├─ 0xB013 // Object Pivot Point

├─ 0xB020 // Position Track

├─ 0xB021 // Rotation Track

├─ 0xB022 // Scale Track

└─ 0xB030 // Hierarchy Position

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

一般來說,一個chunk可能還包含子chunk,比如0x4100表示Mesh的chunk裡就包含了0x4110,0x4120等chunk,同時,0x4100這個chunk的長度辨別,是把這些子chunk的長度也計算在内的。一般來說,我們讀取3ds檔案,隻要解析主要chunk,遇到不識别的chunk,跳過即可。因為3ds裡的資料,大多數并不是程式員需要的。我們隻要頂點和uv這些就夠了。

讀取資料并載入:

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

配置環境

本人使用的VS2019,在配置環境時,希望能夠講庫進行集中管理,是以在E盤單獨建立檔案夾,将include和lib項放入,并在項目中引入,雖然在後期建立項目中需要重複引入,但是保證了相關檔案的整理便捷性。

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

同時添加依賴項:

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

繪制三維模型

對于三種檔案格式來說,有很多的選擇來進行重繪,在這裡我選擇使用glut的庫來完成操作。

上邊已經顯示出資料的解析,并且得到繪制的圖形。可以先使用如下函數進行繪制,設視窗的大小以及形式等資訊。

glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA | GLUT_MULTISAMPLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(GL_WIN_WIDTH, GL_WIN_HEIGHT);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // | GLUT_STENCIL
glutInit(argc, argv);
GLUTwindow = glutCreateWindow("powerful_reader~");
glutReshapeFunc(glutResize);
           

最後的選擇如上圖所示。

Arcball實作控制

由于螢幕是二維的,無法直接表示旋轉,可以通過輔助幾何體來完成。想象在螢幕後面有一個球體,球體正好與這個螢幕相切,如下圖的俯視圖所示

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

我們在求旋轉軸之前需要将二維坐标轉化為三維向量OP,如下圖,T為螢幕上的二維坐标,P為T向螢幕後方發出射線與球體相交的點。這裡做作OM水準面平行于螢幕,P到水準線的深度z需要先行求得。

為了運算處理友善,我們需要将T坐标限定在[-1,1]之間,設定這個球體的半徑為1。

x = 2*x / 螢幕寬度 - 1

y = -(2*y / 螢幕高度 - 1)

由勾股定理可知,z = sqrt(1-xx-yy)。

當xx+yy大于1時,P不在球體上,那就在OM上找一點P,且滿足P在球體上,PT垂直于平面OM,即xx+yy大小限定在1這個值,z = 0.

具體流程如下:

x,y,z的值可以唯一确定OP向量,接下來,給定輸入的兩個坐标T1,T2,我們做出如下處理:

\1. 分别求出T1和T2對應的三維向量OP1和OP2

\2. s = OP1 · OP2,即先求兩個向量的内積

\3. v = OP1 × OP2,即求兩個向量的外積

\4. 記四元數q = [s, v],将其機關化,此時q為旋轉四元數。

\5. 旋轉角α = 2arccos(q.s) ,旋轉軸V = ( q.v / sqrt(1-q.s*q.s) )

結果展示

如下所示,stl格式的ascii、binary存儲格式的讀取和繪制以及控制,以及obj和3DS格式,運作過程存儲為gif****格式,可另行儲存觀看。

或者在百度雲下載下傳:

連結:https://pan.baidu.com/s/1mH9cy1nC9WNrOfa7HDqa9g

提取碼:xv8t

STL_binary

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

STL_ASCII

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

OBJ

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

3DS

C++方式實作stl、obj、3DS三種3D模型加載,并實作Arcball方法控制旋轉縮放平移(采用glut庫等檔案,具體可在項目檔案中實作),開發軟體為VS2019擷取模組化得到的三維模型并解析

繼續閱讀