(如果您阅读了我这篇文章,觉得很好,请转载链接,不要直接复制内容,因为我还有大量的图和代码没有贴上去)

对于高手来说,没有什么东西是难的,这也就造成了精通一件事情的人总是写不出好的教程。——程飞

我学(cao)Blender纯属是个意外,我们实验室的叙利亚大哥(比我大好多岁的师弟)做他的研究的时候,需要获得深度图(Depth Map,如果你知道什么是Depth Map,说明你很适合继续看下去,否则请自行百度一下),他是从一篇paper上看到别人用Blender生产了一些粗糙的CG图和非常精准的深度图,但是paper嘛,你懂的,很多时候并不告诉你该怎么干,只告诉你他很牛逼的干成了。于是叙利亚大哥就跑过来问我,我当时其实也不会,但是觉得这玩意儿有何难,就答应他试试看,一尝试就傻逼了……中文搜索Blender+深度图之类的关键字,只有搜到一篇有用的东西,然后给我摆出一系列我当时完全看不懂的东西,根本没办法入门,但是好歹我知道了只要能捣鼓出他所给出来的图景,我就能搞定啦。

blender

这个图景就是上面这张图所示的样子,说实话,一个纯新手是崩溃的,尤其是我,我并不想从事CG这个行业,只是拿来渲染几个破图做做实验而已,我不可能一步步的从头学的。所以我决定写这篇文章来让一个纯新手如何完成获得深度图的工作。

首先,最最基础的Blender使用方法是要会的,一些想象力是需要的,然后请参考我的心路历程:

  1. 去百度搜索如何把Blender变成中文的;
  2. 知道怎么创建一些物体,这个也能百度到,不想百度的话,就自己试试,按下中键是旋转的,Shift+中键是移动,这两个都是对整个场景进行操作的,对特定物体要右击,然后拖动,自己体会怎么玩。实在不行就百度找教程,非常多的人讲这方面。另外值得一提的是物体所有参数全部都在场景3D视图那个画面的右上角的一个小加号里;
  3. 稍微了解一些Blender的界面哲学,确实很蛋疼。你会发现每一个板块的右上方都有三道斜线组成的小三角,那个就是整个Blender界面哲学的精髓(难以理解)。按着那个拖动,就能拖出另一个一模一样的板块,按着Shift拖动,就能让那个板块独立出来,我很喜欢这个功能,然后板块的左上角,有时候也在左下角,是可以改变这个板块是什么功能的,里面就包含我们最需要的功能——节点编辑器;
  4. 所谓节点编辑器,在我眼里就是像图形编程一样的东西,操作和输出数据。打开节点编辑器之后,可以看到最下面是菜单,真尼玛反人类,正常软件的菜单都是在上面。然而我们并不需要操作菜单,我们需要关注菜单后侧的三个小按钮,选择中间哪一个,然后屏幕左侧就出现了可以拖出来的各种模块了,也就能看到上面那个图的图景了;
  5. 图样图森破的我以为就快要大功告成了,然后参照我之前提到的那个文章就去弄了一下,之前那个文章就只是用了“规格化”这一个模块(规格化其实就是归一化,把数据映射到0到1的范围内),然后反向一下,就输出到“合成器”;
  6. 然后在渲染,还真是那么回事儿,输出来的东西特别特别“像”深度图;
  7. 然后我就兴高采烈的把生成出来的图给了叙利亚大哥,并且附上了详细的相机参数(这个也能百度到),并且感觉为了世界和平做出了一点点贡献;
  8. 十几天后,当我自己拿Blender的深度数据去做我的实验的时候,我整个人都不好了,首先是被“规格化”这个模块给害死了,规格化把最近点量化为0,最远点量化为1,但是最近点的实际距离和最远点的实际距离根本没有啊!
  9. 当然我也不是吃素的,我自己在摄像机的前面很近的距离放置一个非常小的块,这样我就知道最近点的距离是多少了,然后最远点我弄一面墙,始终垂直于相机,我也是知道那个点的距离的,看起来问题解决了!
  10. 我依然是图样图森破了,使用那么弄出来的Depth Map让我的实验结果错的一塌糊涂,当时真的非常崩溃;
  11. 当然,不可否认的是,我确实挺聪明的;
  12. 我依稀感觉到了一股神秘的力量,把我脑海里那个线性变化的深度给掰弯了,这股力量我记得叫gamma。这个我是学过的,但是公式实在不想推,我就采用查找表映射的办法暴力解决这个问题,但是问题是怎么得到一个确定的线性变化的图案呢,我就想到了让相机去看一个斜45度的平面,输出出来的深度图必然是线性渐变了,然而我又错了,需要把摄像机的成像原理从透视改成正交,才能得到线性渐变深度。我尝试了几个不同的角度,结果得到一样的规格化后的深度,印证了我的猜想是正确的;
  13. 然后问题就变得简单了,得到那个我确认是线性渐变的图,然后在Matlab里Plot一下,就看到了熟悉的Gamma曲线了,然后也不去拟合啥的了,直接插值一下得到了映射表,也就是之后再得到什么亮度,那直接查找一下,真实的归一化的值是多少就行啦;
  14. 当然为了提高精度,我很变态的把那个用来做查找表的图生产了1x65535px的尺寸,并且使用TIFF的16bit灰度图来存储,这样就能保证非常高的精度了,起码量化到8bit肯定是非常准确的了;
  15. 就这样,我完成了几个实验,但还是不甘心,应该还有更好的办法,毕竟gamma那里损失了很多精度;
  16. 我又去节点编辑器里去找,真的有gamma,那就用,但是gamma的值是多少,并不知道,我就一遍一遍的尝试,最终确定2.2是最合适的值,但依然不够完美的线性,依然需要用查找表校正到最线性;
  17. 我赶紧把这个消息告诉了叙利亚大哥,他经过一番挣扎终于理解我的思路了;
  18. 然而,还有一个结没有打开,就是我需要人为设定最远最近点,这个非常不人性化,肯定存在更合理的办法来解决,因为如果我需要让相机做复杂的运动,就没办法始终得到最远最近点了;
  19. 然而,我确实是挺聪明的;
  20. 我隐约感觉到那个Z值就是可以直接输出的,只是量化方法不对;
  21. 我尝试找到了“运算”模块,因为我知道归一化是把数据映射到0到1之间,那么那个Z值很可能是太大了,我的场景里,Z的最大范围在15米左右,那我就让整个Z值的图除以50,然后再经过Gamma,然后输出到合成器,结果真的出现了非常像深度图的东西;
  22. 到底是不是呢,我放到Matlab里去测试了一下,校准之后,然后把16bit的数据除以65535之后,乘以50,终于得到了非常非常精准的深度图啦!
  23. 到此,窃以为终于终极解决了在Blender里生成深度图的问题了!

我中间两次提到我挺聪明的,哈哈。其实我知道我的方法并不是最好的,但再没有专家帮助的情况下,如果我从头开始学习Blender,不知道要学到什么时候才能找到深度图这一内容,大部分用Blender的人都是艺术家,不在乎准确的深度图的,他们用Z值只要是做虚化的。

我是随性而写的这篇文章,主要描述了我的思维流,并且写了一些搜索引擎和官方资料都没有详细给出的细节,以及我是怎么想的。如果有人看到这里,想对我说些什么的话,请写邮件到fc@oooole.net交流,谢谢。

If you cannot understand Chinese, please try Google translation. I have no time to write an English edition. If you have any question, please feel free to send me email: fc@oooole.net.