引擎设计跟踪(九.10) Max插件更新,地形问题备忘
最近没有大的更新. 最近本来要做max的骨骼/动画导出, 看导出插件代码的时候, 突然想起之前tagent space导出的疑问, 于是确认了一下.
http://www.cnblogs.com/crazii/archive/2013/04/03/2997601.html
同时在网上找到了一个很明显的带有镜像UV的模型, 进行了测试.
使用该模型顺便发现了float16 (IEEE 754-2008 16 bit floating point format)即半精度浮点数 (http://en.wikipedia.org/wiki/Half_precision), 我的实现方式的bug: 由于使用了简单的位运算,
没有处理overflow和underflow的情况, 导致float32 => float16转换过程中数值溢出.
遇到的情况是一个很小的数(比如1e-6)转到float16时underflow, 正确值应该转为0, 但是由于没有处理这种情况, 导致转换的结果为-300多.
本来导出的模型有部分顶点被拉伸错位, 当时没有想到是这个原因, 在导出插件里加了很多isnan()检测和AABB越界检查, 以及flaot16跟float32的转换后比较, 最后发现是以上的原因.
最后干脆使用OpenEXR的half (https://github.com/openexr/openexr/blob/master/IlmBase/Half/half.h),
问题解决. OpenEXR的half实现是用了内建表加速转换, 具体细节没怎么看, 只看到对于half=>single presicon使用了65536个表项的表(静态数组)做全值映射.
导出的tangent space使用quaternion保存,这个之前测过没有问题. 但镜像贴图仍然有缝, crytek的pdf说tangent space的mirror模式缝很难避免, 只能通过好的tangent space生成算法来尽量改进.
这个模型是Gear of War3里面的模型, 除了面部没有使用镜像UV, 其他地方都用了. 可以看到中间是有缝的, 脖子下面有个倒L行的裂缝最明显(镜像UV到面部非镜像的过渡), 这个裂缝在贴了base map以后还可以看到(这个在MAX 2013 shaded模式里面也能看到), 而其他地方的缝, 带上贴图的时候不是特别明显, 除了离的非常近才能看到一点. 试了crytek(ShaderX4中)的方法(http://www.shaderx4.com/TangentSpaceCalculation.h),效果还是没太大改进. 打算暂时先这样吧, 以后找时间专门研究下.
然后无意间在地形渲染里发现一个严重的问题(可能上次地形更新后没有测这些-_-!), 原因已经找到, 但是不太好改:
由于上次的地形更新(http://www.cnblogs.com/crazii/archive/2013/06/01/3085449.html),
使用了layermap带替代per vertex layer buffer, 这个时候blendmap要跟layermap的纹素精确的的匹配.
如果有3张贴图,分别为A(红色贴图),B(白色贴图),C(绿色贴图) 的时候, 索引为 0, 1, 2; (蓝色半透部分为画刷)
2张贴图A,C的时候 索引为0, 2;
blendmap的混合通道为: Red, Green, Blue. Red对应第一张图即底图.
内圆有三张贴图的部分, Green通道权重为0(不显示贴图B). Blue通道为1对应贴图C,
外圆有两张贴图的部分, Green通道权重为1(全显示),对应贴图C. 所以Green通道在边缘处对应的两张贴图不一样, 通过blend weight的线性差值后, 内圆边缘处Green通道本来应该不显示的贴图B的, 但差值后中间有一部分不是0,导致边缘有缝隙.
layermap使用pointer sampling, 因为layermap保存的是atlas贴图的索引, 不能做线性插值, 否则索引就坏掉了. 如果blendmap改用point过滤(layermap, blendmap的精确匹配), 可以解决这个问题, 但是混合效果太丑, 有马赛克, 无法接受.
想了一下, 上次更新之前没,还没有问题, 是因为per vertex layer buffer实际上是per block(chunk), 即一个block上所有的vertex的layer都一样(有点浪费), 只有block之间的接缝处才有这样的问题, 而且之前blendmap的uv是预先计算的顶点数据, 在block边缘做了半个像素的偏移, 避免采样到邻接block, 所以没有缝.
现在layermap不是per block了,而是精确到每一个纹理元素, 而且没有规律, 不能做像素偏移. 即便把layermap改成per-block的精度, 但现在blendmap的UV已经没有vertex buffer, 而是在shader里面根据位置计算算, 两个block衔接处的顶点位置是一样的, 不知道是哪个block的哪一边, 确定不了偏移方式.所以没有办法在shader里做半像素的uv偏移. 除非这部分退回以前的方式, 使用vertex uv buffer保存blend map uv.
这个问题很恶心, 主要是使用了atlas以后, 还想支持一个draw call的batch合并, 产生的各种问题, 为了渲染正确, 已经做了不少work around了, 现在感觉很难处理.
目前打算把layer map做成per block,跟以前一样, 这样缝的问题只出现在block边缘, 然后的处理方式就比较多. 一种方法跟以前一样, 处理blendmap uv的偏移, 需要占用额外的内存/现存. 另一个方法是像WOW一样, blendmap也是per block, 这样就采样不到邻接block, 但是改动可能有点大, 而且这样block就不能合并draw call了. 魔兽世界地形的chunk是可以(根据情况)合并的因为他没有用atlas, 我这里用了atlas图集, 并且要支持batch合并.
还有一个方法是把blendweight放到vertex buffer里面, 由于每个block之间没有共享顶点, 不会有blend weight插值. 但这样纹理混合的精度有所损失,而且没有之前那样,精度可控(只要调整blend map的大小即可).
需要先考虑清楚有没有更好的办法, 再动手改. 后面可能先做骨骼动画的导出(mile stone 2的key feature, 拖了一年了), 也有可能先把这个问题修好.
更新:
尝试在shader里面使用bilinear采样, 代替硬件采样, 这个时候可以做一些特殊处理, 但效果不是特别好, 仍然有不明显的缝存在.
突然想起来, 如果layermap是per block的话, 没必要对一个block按顶点来保存一大块一模一样的数据, 把这一样的数据块合成一个像素, 采样出来的效果一样, 这样起码没有浪费.
更新2: 目前使用shader里面手动bilinear采样, 代替硬件采样的方式, 通过调整一些参数, 勉强可以了. 但是pixel shader多了20条指令(目前-O3已经达到190条左右), 其中有五条tex2D纹理采样. 低材质LOD的直接用点采样吧, 虽然能看到马赛克, 但是已经有点远了, 应该不是特别需要处理, 如果需要的话也用这种方式.
经过简单对比, 感觉效率比以前低了,之前的debug版, 一个512x512的tile, 在380-400FPS左右, 现在大约300-340FPS, 降低了50-60FPS的样子.
如果退回跟以前类似的的方式, 顺便把layermap处理一下, 按最大的tile大小512, 按最小的block大小为16, 而一个block对应一个像素, 则layermap 最大为 64*64*16(R4G4B4A4) 字节, 比以前小很多.blendmap的uv要加vertex stream并且预处理边界, 或者不添加顶点数据, 在现有的顶点数据里存一个标记, 在shader里面处理. 但现在不是很想改, 主要是因为那样改动太大, 而现在的改法, 改动很小. 所以目前暂时先这样吧, 也许对速度的影响不是特别大, 这次先记录下来, 以后如果真的不行, 可以再改.
引擎设计跟踪(九.10) Max插件更新,地形问题备忘的更多相关文章
- 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复
由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...
- 引擎设计跟踪(九.14.2f) 最近更新: OpenGL ES & tools
之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...
- 引擎设计跟踪(九.9) 文件包系统(Game Package System)
很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...
- 引擎设计跟踪(九.14.2j) TableView工具填坑以及多国语言
Blade的UI都是预定义的接口, 然后由插件来负责实现, 目前只有MFC的插件. 最近加上了TableView的视图, 用于一些文件的查看和编辑, 比如前面在文件包的笔记中提到需写一个package ...
- 引擎设计跟踪(九.14.3.2) Deferred shading的后续实现和优化
最近完成了deferred shading和spot light的支持, 并作了一部分优化. 之前forward shading也只支持方向光, 现在也支持了点光源和探照光. 对于forward sh ...
- 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现
因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...
- 引擎设计跟踪(九.14.2g) 将GNUMake集成到Visual Studio
最近在做纹理压缩工具, 以及数据包的生成. shader编译已经在vs工程里面了, 使用custom build tool, build命令是调用BladeShaderComplier, 并且每个文件 ...
- 引擎设计跟踪(九.14.2c) 最近一些小的更新
1. bump map与normal map 昨天拿了crytek sponza(http://www.crytek.com/cryengine/cryengine3/downloads)场景测试, ...
- 引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏
之前milestone2已经做完的工作, 现在趁有时间记下笔记. 1.设计 这里是指兼容3ds max导出/fbx格式转换等等一系列工作的设计. 最开始, Blade的3dsmax导出插件, 全部代码 ...
随机推荐
- git merge 到 非当前 branch
1. Add a remote alias for your local repository, ex: git remote add self file:///path/to/your/reposi ...
- 转载:简单介绍Python中的try和finally和with方法
用 Python 做一件很平常的事情: 打开文件, 逐行读入, 最后关掉文件; 进一步的需求是, 这也许是程序中一个可选的功能, 如果有任何问题, 比如文件无法打开, 或是读取出错, 那么在函数内需要 ...
- highcharts实现统计图效果
highcharts实现统计图效果 ① 根据需求确定需要使用的案例图 把这个界面的html模板文件复制出来,放入./Application/Admin/View/User下改名为chart.html ...
- 《RHEL6硬盘的分区和swap分区管理》——硬盘分区的大总结
首先介绍下几个简单的命令: free查看当前系统内存的使用情况 查看分区的使用情况:T类型.H显示大小以G,M 查看系统所有硬盘的分区信息:分区的没分区的都显示出来了 开始分区:为什么要加cu 不加 ...
- LitJSON使用
地址:http://lbv.github.io/litjson/docs/quickstart.html LitJSON Quickstart Guide Introduction Quick Sta ...
- CentOS配置VSFTP服务器
[1] 安装VSFTP [root@localhost ~]# yum -y install vsftpd [2] 配置vsftpd.conf文件 [root@localhost ~]# vi /et ...
- php微信开发(1):缓存access_token的方法
语言:PHP access_token一直要用,但每天取的数量有限制.反正2小时才过期.就想缓存一下. File1: wx_access_token.php File2: file_cache.php ...
- 你必须知道的.NET
作者博客地址:http://www.cnblogs.com/anytao/archive/2008/04/09/anytao_insidenet_center.html 第1章 OO大智慧 1.1对象 ...
- mysql5.7.12安装过程中遇到的一些问题
在安装mysql-5.7.12-winx64中遇到的问题总结 1.该版本的mysql解压后的文件夹里没有data文件(切记自己添加data,自己添加的文件可能出现的问题是文件里的文件会缺失) 我在使用 ...
- linux 非缓冲io笔记
简介 在linux中,打开的的文件(可输入输出)标识就是一个int值,如下面的三个标准输入输出 STDIN_FILENO/STDOUT_FILENO/STDERR_FILENO这三个是标准输入输出,对 ...