nVIDIA SDK White Paper ----Vertex Texture Fetch Water

http://blog.csdn.net/soilwork/article/details/713842

nVIDIA SDK White Paper ----Vertex Texture Fetch Water

分类: GPU程序设计2006-05-09 04:48 3439人阅读 评论(2) 收藏 举报

shader网格fp数学计算算法blog

nVIDIA SDK White Paper

Vertex Texture Fetch Water

作者:Jeremy Zelsnack

本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。

由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。也欢迎大家和我多多交流。

翻译:clayman

Blog:http://blog.csdn.net/soilwork

[email protected]

 

水面模拟

水面模拟的目标是在合理的计算量下,创造视觉上真是可信的水面。其中可能的方法之一是基于流体力学中的Navier-Stokes方程求解。这种方法可以创建极度真是的水面,不幸的是,计算量太过沉重。一种较为简单,同时资源消耗较少的方法是在一张均匀网格上解2D波方程。牺牲一点点真实性换取实现的简洁和速度。本文描述了2D波方程技术。

上面的就是2D波方程。这个方程表示点将在Y方向上上下起伏。C表示波传播的速度。直观的说,这个方程表示点上下起伏的加速度,和表面起伏改变的快慢是成正比的。

看到这里,你可能会问,“如何来求解这样一个方程呢?”GPU并不知道偏导数是什么;只知道空间位置而已。如果我们把方程左边对t进行两次积分,就得到了y值。如果继续把计算出的y值与点x和z的值组合到一起,就得到了3D坐标,这就是GPU所能理解的了。

接下来的难题就是如何对方程的右边进行积分。有许多种积分的技术可以使用,每种都有其优点和缺点。对我的程序来说,需要的是稳定性和速度。稳定性是相当重要的,因为公正的说,这个方程太过于呆板。方程右边的C2将使左边的值迅速增大。因此,不能使用类似欧拉的简单积分方法――它们不太稳定。Runge-Kutta方法也是不行的,因为它需要计算中间值,同时,还对储存速率有很高要求。这对于我们的程序来说太复杂,太耗费资源。Verlet积分计算量很轻,同时也很稳定,对储存速率也没有要求。不幸的是我忘记了Verlet方程(-_-# 汗~~),并且在30秒内都没有找到任何关于Verlet方程的参考资料(=。=)。因此,我重新发明了一种类似于Vertet的方法。

如果我们知道了点在t=0时刻的位置P(t0),以及t=1时刻的位置P(t1),加速度a(t1),那么使用方程3,只需要一些高中的物理知识,就可以求解t=2时刻的位置P(t2)。这里的推导假设采样步长是常数,因此,t1-t0 = t2 – t1 = t(n+1) – tn。当然,也可以步长值也可以为非常量,但这就需要更多的数学计算。

方程3和真正的Verlet积分(方程4)相当类似。唯一的不同,就是在加速度系数上有区别。

好了,方程3描述了一种计算积分的方法。但是有一个问题,它并不像看起来那么稳定,而是抖动的(jittery)。我们需要做一些额外的处理,来消耗由于不精确的积分而带来的额外能量。可以添加一个常量因子来减小通过推测而得来的速率。

好了,现在我们有了积分的技术,几乎可以对2D波方程的右边进行积分了。现在来看看如何计算方程右边的偏导数。方法之一,就是找一个和我们所要模拟的顶点相称的表面。有了这个表面,我们就能分析推测偏导数的计算公式。

那么什么样的表面才和要模拟的网格类似呢?我们需要一个快速,简单同时能在一定程度上保持精确的模型。3次样条曲线集合正好能满足我们的要求。可以对问题进行简化,变为对两个2D三次样条曲线的问题。这样就推导出了公式6。对一个三次方程来说,需要指定4个常数。其中,3个显而易见的常数就是当前以及邻近顶点的坐标。第四个常量则是当前顶点位置下的导数。图一描述了这种情况。假设切线和邻近的顶点是平行的,同时,网格也是均匀的,则可以得到一个2阶偏导数方程(公式7)。使用偏导数,右边的2D波公式就变为了方程8。


好了,现在我们简单分析了计算方程右边的算法,以及积分方法,可以实际计算网格中顶点的y值了。由于我们假设网格中的所有顶点之间的距离都为1个单位(在世界坐标中不一定合适),因此需要调整波的速度,让他看起来正常。

好了,现在可以使用简单的迭带来求解波形方程,我们让GPU来完成这个任务吧。我们把均匀网格的高度保存为一张纹理。同时,还需要追踪上一张高度图的值。这样就可以计算下一张高度图的值了。下面是使用HLSL求解波形方程的代码:

顶点纹理将保存为16bit的浮点纹理。使用8bit的整数是不可行的,16bit的整数虽然可以满足精度的要求,但无论如何浮点数都是最好以及最方便的选择。示例的程序中,我们把高度和法线混合起来,保存为一张D3DFMT_A16B16G16R16的纹理。这样做,可以减少vertex shader中纹理拾取的次数。

好了,现在有一张用来模拟水面的高度图了,如何来使用它呢?Shader Model 3.0 支持在vertex shader中进行纹理拾取(在VS 3.0中)。为了渲染水面,我们把包含了有效顶点位置的网格mesh传入到vertex shader中。顶点纹理拾取能有效的帮助我们把纹理转换为几何体。更多信息请参考(ftp://download.nvidia.com/developer/Papers/2004/Vertex_Textures/Vertex_Textures.pdf)

需要注意的是,GeForce 6系列的硬件在vertex shader中并不支持D3DFMT_A16B16G16R16的格式。这就需要把fp16的波形方程结果转换为fp32格式。你可能会问,问什么开始不直接把波形方程的结果保存为fp32格式呢?答案是fp2的纹理渲染起来很慢,此外,fp32的渲染目标不支持混合或者纹理过滤。由于fp32缺乏混合机制,将导致水面控制更加复杂。而缺乏过滤,则会降低渲染质量。

好了,有了模拟水面的方法,接下来看看如何控制它。幸运的是,使用Verlet积分对此进行控制。Verlet积分本身就表示了高度偏移的速率。在GeForce 6系列的硬件上,高度偏移值将直接渲染为fp16格式的高度纹理。这是最自然也是最高效的方法。但是在Geforce 6系列之前的硬件上,这却是不可行的,应为缺乏对fp16 alpha混合的支持。没有混合,就不得不把高度偏移值渲染为额外的非fp16渲染目标中,之后,再把这张偏移值纹理渲染到高度图之上。这是很麻烦的方法,同时精度也不高。

再进一步来看看这个方法的性能如何,水面模拟到底有多快。虽然看起来有很多操作。幸运的是,这对GPU来说并算不了什么。你基本上只是在一个简单的pixel shader中渲染了一张小渲染目标(比如128x128)。凭感觉来说,这对现代GPU算不了什么。作为一个稍微“科学”的基准来看,在GeForce 6800GT的显卡上,关闭了水面模拟之后,帧速率从263fps变为了268fps。这表示我们的模拟只需要0.07毫秒,这并不算长。与实际的模型相比,顶点纹理拾取的性能才是瓶颈。

~~~~~~~~~~~~~~~~~~~·未完待续·~~~~~~~~~~~~~~~~~~~~~~~~

这篇文章是SDK里Vertex Texture Fetch Water的白皮书,今天头晕晕的,好多地方翻的不恰当,要看的同志还是对照原文一起来-_-#。 又快天亮了,偶睡觉去鸟~~~~

水面渲染

分类: GPU程序设计2006-05-19 06:34 5367人阅读 评论(5) 收藏 举报

shaderfloatfftc++网格文档

看了那么多文章,终于动手自己写水面渲染的程序了。选择了使用顶点纹理来实现(FFT。。。看了2遍信号与系统,还是没有明白怎么变换求解-_-#)。弄了3天,总算把水面的初步动画实现了,画面效果还没进行优化,纹理也没贴,不过效果还不错,CPU占用率出乎意料的低,网格大小为256x256,并且没有任何裁减的情况下,6600GT可以跑到70帧左右。本来打算用MDX2.0的,结果写了一点点,就出了一大堆问题,没有文档实在是麻烦的事情,还是回到了1.0。对顶点纹理进行采样的sampler参数设置差点让我崩溃了,查了无数资料,都没有关于如何在MDX里进行设置的例子。最后,模仿nVIDIA SDK里一个C++程序的例子写了一个,居然成功了~~。VS2003里不能调试shader实在是痛苦啊,但是拼写错误就害死人啊T_T。

记下一些容易犯的低级错误 ,以免再错-_-:
1.  顶点索引的顺序是很重要的, 切记需要按顺时针顺序来定义;
2.  矩阵相乘的顺序是有讲究的;
3.  拜托,写demo的时候先画个草图,设计好物体,观察点的位置,不要弄了半天发现物体根本不在视线内~_~;
4.  顶点纹理一定要是32bit的float point格式,否则就算程序可以运行,也不会有结果 +_+;
5.  注意tex2Dlod这个函数接收的纹理坐标参数为float4,而不是普通的float2  =.=;
6.  顶点纹理sampler的参数和pixar shader是不一样的,需要用特殊的标识符 @[email protected];
7. 拼写~~!!一定要注意拼写的正确性啊~~ 0_0;

nVIDIA SDK White Paper ----Vertex Texture Fetch Water

时间: 2024-10-12 16:28:04

nVIDIA SDK White Paper ----Vertex Texture Fetch Water的相关文章

类的扩展--类目--ios

person+money.h  这是类目类 #import "Person.h" //这是扩展person类的接口类,独立一个文件 @interface Person (Money) -(void) haveMoney; @end person+money.m 这是类目类 #import "Person+Money.h" //这是扩展person类的实现类,独立一个文件 @implementation Person (Money) -(void) haveMoney

IOS开发-OC学习-常用功能代码片段整理

IOS开发-OC学习-常用功能代码片段整理 IOS开发中会频繁用到一些代码段,用来实现一些固定的功能.比如在文本框中输入完后要让键盘收回,这个需要用一个简单的让文本框失去第一响应者的身份来完成.或者是在做与URL有关的功能时,需要在Info.plist中添加一段代码进而实现让网址完成从Http到Https的转换,以及其他的一些功能. 在从一个新手到逐渐学会各种功能.代码.控件.方法如何使用的过程中,也在逐渐积累一些知识,但是一次总不会把这些东西都深刻记住并完全理解.所以在这儿记录下这些东西,用来

mac下修改mysql-root密码-各种权限问题解决

官方资料:http://dev.mysql.com/doc/refman/5.0/en/resetting-permissions.html#resetting-permissions-unix 还有一个值得参考的mysql安装,与python-mysql安装博客http://hearrain.com/2011/01/498 据官方文档说, For example, if you run the server using the mysql login account, you should l

IOS开发-UI学习-sqlite数据库的操作

IOS开发-UI学习-sqlite数据库的操作 sqlite是一个轻量级的数据库,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了,而且它的处理速度比Mysql.PostgreSQL这两款著名的数据库都还快,在ios和安卓app中常用来完成对数据进行离线缓存的处理,如新闻数据的离线缓存. 它的基本操作步骤是: 1.先加入sqlite开发库libsqlite3.dylib, 2.新建或打开数据库, 3.创建数据表, 4.插入数据, 5.查询数据并打印, 6.关闭数据库, 具体操作步

OC--单例--NSDate--归档--json--plist--协议

-------单例-------- 定义:一个类只允许创建一个对象,在任何地方调用对象方法或属性的时候,只能通过这个对象.注意:一般在单例类里面只创建有限的类方法. 作用:1.一个类只能有一个对象的时候,并且从一个大家都熟知的访问点访问它 2.保存值 //1.将本类的对象设置静态的,这样就能保证对象的唯一性. //manage是全局的 static  SetUpManage *manage  = nil; +(SetUpManage *)sharedManage{ @synchronized(s

SPRING源码解析-SPRING 核心-IOC

IoC 和 AOP是Spring的核心, 是Spring系统中其他组件模块和应用开发的基础.透过这两个模块的设计和实现可以了解Spring倡导的对企业应用开发所应秉承的思路: 易用性. POJO开发企业应用, 直接依赖于Java语言,而不是容器和框架. 提升程序的可测试性,提高软件质量. 提供一致性编程模型,面向接口的编程 降低应用的负载和框架的侵入性.IoC和AOP实现. 不作为现有解决方案的替代,而是集成现有. IoC和AOP这两个核心组件,特别是IoC容器,使用户在使用Spring完成PO

初识_IOS-简易计算器-问题总结

作为一个新手,只好拿所有开发者都写的不想写又没有太大难度的计算器来下手咯.比较细一点,耐心哟. 我们都知道,计算器首要任务就是计算,那我们就直接看成A+B=C,来进行分析了.对A,B,C三个对象进行分析. 我们来想象一下真实计算器的操作,首先进行的就是输入了,那我们就先来解决输入问题: ----------键盘的输入: 输入时我们得知道此次输入的值是A还是B,因为如果分不清是左值还是右值那就无法进行正确的赋值,那可想而之我们的计算器得成什么样. 但是用其他方法来实现这一辨别很显然很麻烦,这时候我

Kafka源码分析-序列4 -Producer -network层核心原理

在上一篇我们分析了Java NIO的原理和使用方式,本篇将进一步分析Kafka client是如何基于NIO构建自己的network层. network层的分层架构 下图展示了从最上层的KafkaProducer到最底层的Java NIO的构建层次关系: 图中淡紫色的方框表示接口或者抽象类,白色方框是具体实现. 整个架构图也体现了"面向接口编程"的思想:最底层Java NIO往上层全部以接口形式暴露,上面的3层,也都定义了相应的接口,逐层往上暴露. 接口的实例化(包括KafkaClie

6月10日-IOS应用-日记本

嗯,经过这几天的学习,我的第一个IOS应用,日记本算是学习完毕了,下面写一篇日记,记录所学到的知识和需要继续学习的地方. 1,首先是ViewController,必须添加两个协议UITableViewDataSource和 UITableViewDelegate,必须实现这两个协议的两个方法,tableView numberOfRowsInSection和tableView cellForRowAtIndexPath,前者返回行数后者设置行内容. 2,搜索框,搜索框需要加载协议UISearchB