1. bump map与normal map

昨天拿了crytek sponza(http://www.crytek.com/cryengine/cryengine3/downloads)场景测试,

一开始用的是这里的模型(http://graphics.cs.williams.edu/data/meshes.xml)发现里面用到了1通道的bumpmap, 但是blade的shader并不支持, 如果要支持的话又要加材质和shader了, 所以用了这种hack, 只为了跑一下这个场景.

bumpmap是单通道的灰度图, 实际上是一张高度图, 在shader里面可以根据高度差得到法线扰动. 而法线贴图是切空间的相量.

bump map是对法线的偏移和扰动, 而normal map则是对法线的完全的替换.

法线贴图可以有两种途径产生, 一是高模烘焙, 二是通过高度图生成.第二种方法nvidia的photoshop插件里面就有(https://developer.nvidia.com/nvidia-texture-tools-adobe-photoshop).

原理不多说了,这里有个链接:

凹凸贴图(Bump Map)实现原理以及与法线贴图(Normal Map)的区别

bump map到normal map转换的方法从上面链接中的shader里面可以看出来, 即用高度图中的的导数dx, dy来构造法线. 下面是一个参考(原帖是有错误的求助帖, 回复中有SOBEL filter的代码片段):

https://www.opengl.org/discussion_boards/showthread.php/168864-HeightMap-to-NormalMap

更多的参考在这里(GIMP的法线贴图插件, 各种各样的, nxn的filter啊):

https://code.google.com/p/gimp-normalmap/source/browse/trunk/normalmap.c

目前blade使用了3x3的SOBEL filter. 这个转换只有实时转换用到了, 但理论上后台工具也可以直接用.

下面是用blade的导出插件导出的cretek sponza场景, 并在model viewer里面查看的效果, 后面做场景渲染效果的时候可以暂时先拿它来测试:
 

这个场景比较复杂, 用它测试max导出插件, 也发现了在导出切空间时的某些bug, 比如计算切空间时, 三角形两个边的向量, 是带长度的向量, 不能单位化, 否则对于狭长的三角形, 计算错误会暴露出来.

另外,与话题无关的, 还有两个诡异的问题, 上面的两个模型(.obj)在max里都是这样: 一个材质sponza_bricks, 它的diffuse map和normal map是同一张diffuse贴图: spona_bricks_a_diff.tga, 但是明明有对应的法线贴图文件在啊, 而且用这个导出模型的话, 渲染结果明显不对, 害得又被坑了, 改成正确的贴图就好了.

而且贴图明明含有specular map, 但是材质里面又没有设置specular map, 这个我也暂时没管了.

2.通过上面的模型, 也测试出了几个material LOD的几个小bug:

a.虽然模型系统的材质是以单个子mesh为单位更新的,但是子mesh交给materialLOD updater的世界坐标, 是父model的坐标, 即所有的子mesh都使用的相同的坐标. 这样如果一个model太大, 位置的精度会有问题, 现已改为子mesh真正的世界坐标, 这样材质LOD的精度真正达到单个子mesh级别.

b.判断材质LOD的距离, 之前用的是相机和物体中心之间的距离.当物体非常大的时候, 相机已经在物体的内部了, 但是距离物体中心还很远, 导致LOD切换出了问题, 这个需要用距离减去物体半径(虽然接口已经定义了半径/AABB但是一直没有用).

c.有的submesh有多个部件, 而且相距很远(比如场景的两端),但是他们属于同一个submesh(共享同一个材质), 导致这个submesh非常大, 相机一直在其内部. 这样的材质LOD更新粒度太大, 导致材质LOD没有机会切换. 这个要改导出插件. 因为现在的导出方式是按材质划分submesh, 合并材质相同的object, 这个需要改为按material + object划分出submesh, 相同material的object分开导出而不合并. 只要material相同的object在导出时, 分开的多个submesh连续在一起, 同时在渲染时按顺序绘制. 这样与之前相比, 从一个材质对应一个drawcall, 变成一个材质对应多个连续drawcall, 结果将是多几个drawcall, 也没有多余的材质切换, 是可接受的折衷方案.

3.UV坐标系改用OGL坐标系.
因为blade使用的坐标系是右手系, 但是uv使用的是dx的坐标系(u向右v向下), 这导致"默认的"切空间是左手系, 有点不爽. 所以就改成OGL的坐标系, 即u向右v向上.

这样默认的切空间变成右手系, 不过在实际中切空间是使用左手系还是右手系, 同时要看normal map是哪一种了.windows下大多游戏的法线贴图都是左手系.

左手系和右手系的normalmap是不一样的,他们的G通道是相反的.记得在网上看过两张图片的对比,具体链接忘了.

所以也在导出插件里面添加了手相选项. 一般来说,对于一个项目, 这些参数(手相之类)都是预定好的规范, 然后根据规范制作对应的模型和贴图, 这个时候这个手相选项就是固定的, 没有太大用处.

但是对于想使用3方现有模型和贴图的时候(比如我目前在网络上下载的各种模型), 由于各种情况都有, 这个时候可能需要选择导出手相, 使切空间匹配法线贴图.

而对于上面的bump map 转的normal map, 因为是运行时生成, 所以导出时的切空间可以选择任意坐标系, 比如目前导出时选择右手系, bump转normal的时候也使用右手系就可以了.

另外,blade对于uv的处理, 之前的想法是这样的: 使用固定的uv坐标系, 如果使用的uv, 或者图像的内存布局(有的是从低向上, 有的是从上到下)跟渲染API期望的不一样, 就翻转纹理图像的内容, 这样对于不同的API, uv和shader都不用改了.
虽然这个想法理论上没有问题, 但是实际上非常二: 运行时翻转图像太耗时.. 现在已经改成加载时翻转模型的纹理坐标(v坐标)了, 这样最终效果也一样.

因为OGL的uv坐标系要求图像是倒着存放的(原点在左下角), 如果加载的纹理不是这种布局(原点在左上角), 那么就翻转纹理坐标的v值. 比如DDS图像格式,其原点在左上角而不是左下角.

在用MFC+GDI做编辑器的过程中, 学习到GDI的bitmap header, 或者通用的bitmap header可以根据图像高度biHeight的符号来动态区分其存放格式http://msdn.microsoft.com/en-us/library/aa930622.aspx),

而在使用FreeImage的过程中发现, FreeImage加载的位图都是垂直倒放的, 这对于OGL有着先天优势.

4.threading utility

因为C++11里面已经有简单的thread了, 但是blade是基于C++98/03写的, 没有使用任何新特性. 因为Blade内部已经使用了Intel TBB, 多线程这个功能因为一直没有直接用到(除了自己写的readwritelock用到了mutex lock), 所以没加.但是考虑到以后用户的可能需求, 所以先放上.

本来的思路是写成C++11兼容的接口, 这样用户可以在不支持C++11编译器上用blade自带的thread, 接口也能保持一致, 不用改代码.

但是发现thread的某些功能使用了C++11的语法新特性, 所以这种想法不可行, 于是就用blade当前的风格简单封装了condition variable, mutex, thread, 放在了foundation库里面.目前做了windows系列和*nix (pthread)两种实现.pthread对应的功能都有, 只是简单的封装, windows下新版本的crt也有, 但是为了兼容性, 是自己写的.

目前只做了简单的测试, 估计还有N多bug, 暂时先这样吧, 嗯.

5. IK预研

目前找到的参考有:

http://freespace.virgin.net/hugo.elias/models/m_ik.htm

http://freespace.virgin.net/hugo.elias/models/m_ik2.htm

http://billbaxter.com/courses/290/html/img0.htm

http://graphics.ucsd.edu/courses/cse169_w04/welman.pdf

http://graphics.ucsd.edu/courses/cse169_w05/CSE169_12.ppt

http://graphics.ucsd.edu/courses/cse169_w05/CSE169_13.ppt

循环坐标下降(CCD)算法中对骨骼动画中膝盖等关节的特殊处理 很高兴国内已经有人在做^^.

另外还有 DOOM3 source code, 里面有IK的代码.

据了解 IK常用的方案有: Jacobian Transpose, CCD( cyclic coordinate descent), 和Analytical Method.

前两者是迭代逼近的解法, 而其中CCD更简单易懂, 而且有效.

Jacobian Transpose: http://www.math.ucsd.edu/~sbuss/ResearchWeb/ikmethods/iksurvey.pdf

CCD: https://sites.google.com/site/auraliusproject/ccd-algorithm

Analytical Method: http://www.ryanjuckett.com/programming/analytic-two-bone-ik-in-2d/

最后一个是几何分析的方法, 适用于简单的情况. 目前从doom3的代码看, 它好像用的这种方式(貌似没看到迭代).

blade的计划支持腿部IK, 还有臂部IK, 必要时加上头发辫子等等, 这个类似doom3的IK_Walk和IK_Reach, 但是臂部IK应该要比doom3更复杂.

后面还是继续IK的研究, 工作很忙, 先抽空看看资料吧, 进度会很慢.

引擎设计跟踪(九.14.2c) 最近一些小的更新的更多相关文章

  1. 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复

    由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...

  2. 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善

    最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVert ...

  3. 引擎设计跟踪(九.14.2g) 将GNUMake集成到Visual Studio

    最近在做纹理压缩工具, 以及数据包的生成. shader编译已经在vs工程里面了, 使用custom build tool, build命令是调用BladeShaderComplier, 并且每个文件 ...

  4. 引擎设计跟踪(九.14.2f) 最近更新: OpenGL ES & tools

    之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...

  5. 引擎设计跟踪(九.14.2d) [翻译] shader的跨平台方案之2014

    Origin: http://aras-p.info/blog/2014/03/28/cross-platform-shaders-in-2014/ 简译 translation: 作者在2012年写 ...

  6. 引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏

    之前milestone2已经做完的工作, 现在趁有时间记下笔记. 1.设计 这里是指兼容3ds max导出/fbx格式转换等等一系列工作的设计. 最开始, Blade的3dsmax导出插件, 全部代码 ...

  7. 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现

    因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...

  8. 引擎设计跟踪(九.14.2j) TableView工具填坑以及多国语言

    Blade的UI都是预定义的接口, 然后由插件来负责实现, 目前只有MFC的插件. 最近加上了TableView的视图, 用于一些文件的查看和编辑, 比如前面在文件包的笔记中提到需写一个package ...

  9. 引擎设计跟踪(九.14.2b) 骨骼动画基本完成

    首先贴一个介绍max的sdk和骨骼动画的文章, 虽然很早的文章, 但是很有用, 感谢前辈们的贡献: 3Ds MAX骨骼动画导出插件编写 1.Dual Quaternion 关于Dual Quatern ...

随机推荐

  1. nginx php 安装

    .选定源码目录选定目录 /data/klj/ cd /data/klj/ 2.安装PCRE库cd /data/klj/wget ftp://ftp.csx.cam.ac.uk/pub/software ...

  2. php实现显示网站运行时间-秒转换年月日时分秒

    <?php // 设置时区 date_default_timezone_set('Asia/Shanghai'); /** * 秒转时间,格式 年 月 日 时 分 秒 * * @author w ...

  3. 在PyQt中直接使用ui文件并加载qrc资源文件

    1. 用Qt设计师创建一个包含qrc资源文件的ui文件 2.打开cmd使用以下命令把qrc资源文件转换成十六进制的py文件 pyrcc4 -o C:\res.py C:\res.qrc pyrcc4 ...

  4. AngularJs记录学习03

    AngularJs的路由是一个组件,需要自己额外添加,在目录/src/ngRoute中 三个文件route.js,routeParams.js,ngView.js <html> <h ...

  5. jquery异步上传文件,支持IE8

    http://code.taobao.org/p/upload2/src/ 已经托管至淘宝code 源码:http://code.taobao.org/p/upload2/src/jquery.upl ...

  6. 使用Android Studio开发J2SE项目方法

    0.前言 最近因为要为项目开发一个底层的Java应用,所以非常偶然的遇到了这样一个问题,过去Eclipse有Java Project而现在手头使用Android Studio并不能直接建立Java应用 ...

  7. Map,HashMap

    Map(映射),又称为字典(Dictionary),是由关键字(Key)及其对应的元素值(Value)所组成的元素单元(Element)的表单式集合. 通常,对于Map而言,使用给定的Key,可以迅速 ...

  8. [原创] PostgreSQL Plus Advanced Server在Windows中配置双机热备流复制

    一.系统环境 操作系统:Windows Server 2003/2008 两个节点分别为master与slave. 主节点master:172.27.19.28 备机点slave:172.27.19. ...

  9. hdu 4217 Data Structure?/treap

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4217 可用线段树写,效率要高点. 这道题以前用c语言写的treap水过了.. 现在接触了c++重写一遍 ...

  10. 记录:asp.net mvc 中 使用 jquery 实现html5 实现placeholder 密码框 提示兼容password IE6

    @{ViewBag.Title = "完美结合";} <script>var G_start_time = new Date;</script> <! ...