由于Chrono的官方教程在一些細節方面解釋的并不清楚,自己做了一些嘗試,做學習總結。
上一篇文章中,自己【用sketchup重建了三維場景】,但導入chrono中顏色很不正確,幾乎都是白色的,但也不是完全白色。經過了一系列的測試,找到了問題。
說明:由于本人不專門搞三維重建,因此可能有表述用詞不嚴謹,本文僅供說明含義,沒有去究用詞。
1、obj格式文件的存儲
從Sketchup導出帶紋理信息的obj文件后,會生成三個文件:xxx.obj
, xxx.mtl
,和xxx文件夾
。
其中,xxx.obj是三維模型,不帶有任何貼圖,沒有顏色的。mtl文件為material的縮寫,表示模型的材質,xxx文件夾是具體的貼圖圖片。
進一步解釋,就是在(chrono/meshlab/cloudcompare)打開一個obj文件時,如果找到了obj文件對應的mtl文件,就會根據mtl文件中定義的每個mesh面的參數,加載貼圖。
一個典型的mtl
文件的內容如下:
## Alias OBJ Material File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limitednewmtl TGA2021_6_302
Ka 0.200000 0.000000 0.000000
Kd 0.349020 0.337255 0.313725
Ks 0.330000 0.330000 0.330000
map_Kd outdoor_simple/TGA2021_6_302.jpg# 下一個面的參數
其中Ka, Kd, Ks為三個參數,下面會講;最后的map_Kd就是貼圖,對應的貼圖在xxx文件夾當中。貼在TGA2021_6_302這個面上。
如果說找不到mtl文件,或者丟失了紋理文件夾,打開obj就是一個沒顏色的,如下圖。同時,meshlab或者cloudcompare都會警告你沒有找到對應的紋理:
2、mtl文件參數說明
直接貼chatgpt給出的說明:
Ka (Ambient Reflectivity, 環境反射率):
解釋:Ka 用于定義材質的環境光反射率,也就是材質在環境光(ambient light)下的顏色。
格式:Ka R G B,其中 R、G、B 是紅、綠、藍三種顏色的反射率值,范圍通常為 0.0 到 1.0。
作用:環境光是模擬從所有方向均勻照射到物體上的光,它的反射率決定了物體在環境光下的基本顏色。
示例:Ka 0.200000 0.200000 0.200000 表示材質在環境光下反射 20% 的紅、綠、藍光。
Kd (Diffuse Reflectivity, 漫反射率):
解釋:Kd 用于定義材質的漫反射光反射率,也就是材質在漫射光(diffuse light)下的顏色。
格式:Kd R G B,同樣 R、G、B 的范圍為 0.0 到 1.0。
作用:漫射光是從特定方向照射到物體上,并在表面均勻反射的光。它主要影響材質的顏色和亮度。
示例:Kd 1.000000 1.000000 1.000000 表示材質在漫射光下反射 100% 的紅、綠、藍光,即材質呈現白色。
Ks (Specular Reflectivity, 鏡面反射率):
解釋:Ks 用于定義材質的鏡面反射光反射率,也就是材質在鏡面光(specular light)下的顏色。
格式:Ks R G B,同樣 R、G、B 的范圍為 0.0 到 1.0。
作用:鏡面光是模擬光線在表面反射產生的高光(specular highlights),它的反射率決定了材質的光澤度和反射光的顏色。
示例:Ks 0.330000 0.330000 0.330000 表示材質在鏡面光下反射 33% 的紅、綠、藍光。
也就是說,Ka是對“環境光/ambient light”的“顯示”,Kd和Ks是對主動光的“顯示”。
- 環境光:模擬從所有方向均勻照射到物體上的光,它的反射率決定了物體在環境光下的基本顏色。
- 特定光/主動光:不同于環境光的光線,物體受到主動光后,會“漫反射”和“鏡面反射”
3、問題分析
從sketchup導出的文件可以看出,所有物體的Ka都是0,僅存在Kd和Ks。所以,這個帖圖受環境光影響,只受主動光照的影響。
那么,既然場景中都是白色,是不是因為太亮了?
代碼中的實現如下:
vis->AddLight(ChVector<>(-50, -50, 200), 300, ChColor(0.7f, 0.7f, 0.7f))
vis->AddLight(ChVector<>(+50, +50, 200), 300, ChColor(0.7f, 0.7f, 0.7f));
vis->AddLight(ChVector<>(-50, +50, 200), 300, ChColor(0.7f, 0.7f, 0.7f));
vis->AddLight(ChVector<>(+50, -50, 200), 300, ChColor(0.7f, 0.7f, 0.7f));
可以看出,之前照抄的這段代碼,打了4束主動光,強度都是0.7。那么再綜合Kd這個漫反射參數,可以發現,4個0.7作用下,乘以漫反射系數,仍然超過了1,因此顯示出了白色。所以,如果把0.7改小,是不是會有所好轉?
改成0.2f后,確實山的顏色正常了,但問題是陰影區域顏色太暗了,看不清。
那么再回到Ka參數,既然都是0,那么修改Ka是不是能解決?于是將Ka的0全部修改為1試了下,沒有任何效果。
什么原因呢?那就是環境中并沒有“環境光”,chrono中AddLight添加的是主動光,而不是環境光。于是搜了半天,果然chrono中可以添加環境光,代碼如下(添加“滿”環境光,即255):
vis->GetSceneManager()->setAmbientLight(irr::video::SColor(0, 255, 255, 255));
注意:這個函數在chrono不同版本中的定義不同,請自行查找自己版本的代碼對應的定義。四個參數可能是alpha, r, g, b,也可能是r,g,b,alpha;可能是u32類型,也可能是float類型。
這樣,就可以看到物體“本身”的顏色了。只不過這樣主動光再一疊加,主動光直射部分還是容易泛白,因此我們可以把主動光全部關掉,只留環境光。
但是此時又發現了一個問題,那就是“純色”區域顯示的是灰色的,例如右側的山峰。這是因為純色區域在mtl文件中并沒有“貼圖”,只是通過Kd和Ks參數控制了顏色,因此主動光是0時環境光的Ka參數都是1,所以就會是灰色的。比如,下面這個xtl
中stone1是貼圖,而Vegetatin_Blur7是純色(沒有貼圖文件):
因此,再把純色區域的Ka不要設置成全1,而是用Kd參數即可。下圖中“山”的顏色正常了。但改起來比較麻煩,可以寫個腳本自動實現。
4、總結
啰嗦半天,更多的展示了試湊過程。總結如下:
- obj文件的顏色來自
mtl
文件定義,有兩種顏色:貼圖或者是純色 - obj中的每個面有三個參數決定顏色,Ka,Kd和Ks;Ka是“環境光”的“響應”,Kd是“主動光”的散射,Ks是“主動光”的反射,大概是一個:“顏色=(環境光 x Ka) + (主動光 x Kd) + (主動光 x 觀看角度 x Ks)” 這么一個關系(不是嚴格表達式,僅供理解)
- chrono的光照有兩種,主動光由代碼
AddLight
添加,或者環境光由setAmbientLight
添加; - chrono中最終顯示的mesh顏色,由主動光和Kd/Ks參數作用,加上環境光和Ka作用最終實現。區域白色說明主動光+環境光過高了,黑色區域為主動光少/遮擋/環境光太暗,對應上述公式調整;
- 調整思路,就是直接改變主動光或環境光,如果物體本身的材質差距比較大,再去編輯
mtl
文件修改對應參數
遺留問題/Issue
那么,有一個問題:如果修改了Kd/Ks,激光雷達在仿真時,intensity的數值是否會發生改變?換句話說,在chrono中由于光照“看起來”顏色不一樣的物體,會影響lidar的采集數據么?
答:簡單測了下,好像沒有區別。Kd/Ks設置為0,lidar的采集intensity看起來還是一樣的。