由于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看起来还是一样的。