【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 5312|回复: 12

[HLSL] 用RenderMonkey 进行shader开发

[复制链接]
发表于 2008-10-23 16:46:25 | 显示全部楼层 |阅读模式
Natalya Tatarchuk

3D Application Research Group

ATI Research



作者:董宝成

Email:dongxinzhiemail@163.com



介绍

目前3D图形应用程序开发人员面临的挑战主要集中于创建和使用可编程图形shaders。这些可编程的图形shaders是将来图形编程的核心竞争力。

有能力创建和使用这些可编程shaders的开发人员将能够享受所有硬件所提供的高级特性和创建颠覆传统实时图形艺术的应用程序。为可帮助开发者充分释放这些竞争力潜在优势,ATI开发了一组工具— RenderMonkey 工具集。

尽管写汇编或高级shader语言代码是开发过程的核心,但shaders远不止这么简单。压缩一个基于shader的效果是一个复杂的任务因为包括捕获所有包括这些渲染特效系统的状态。这就导致一个普遍存在于shader开发者之间的问题 — 交换和共性数据不是一件简单的事。另一个问题是在开发shader程序的工程中它必须与艺术家紧密的交流。由于没有适合艺术家使用的工具,就造成了开发过程中合作的困难。现在需要的是一个开发环境,他不仅仅适合程序员而且艺术家和游戏设计者也能够一起合作,从而创造出预想的效果。RenderMonkey就是被设计用来解决这些问题的。用这个工具,我们提供了一个创建shaders的强大的程序员开发环境,它能被作为一个标准的传输机制允许开发组之间共享基于shader的特效。我们也提供了一个灵活的,可扩展的框架他能够非常容易的将自定义的组件集成而且还为以后的工具开发提供了一个基本的固件集。RenderMonkey 能很容易定制和集成到任何开发者的工作流中。RenderMonkey集成开发环境的设计使得将当前的和以后的API结合在一起变得非常容易。这篇文章是关于1.0版本的,他能够支持DirectX9.0 shader 特效(用汇编和HLSL都行),也支持基于GL2编写的基于OpenGL的特效。

集成开发环境预览

RenderMonkey应用程序接口对那些曾经用过像Microsoft Visual Studio之类的集成开发环境的开发者而言将是非常直观的。图1是一个接口渲染一个云特效时的快照。



图1 — 主要应用程序界面

这个主要接口有以下几个组件组成:

l 一个编辑特效的工作区视图

l 一个用于显示编译结果和来自应用程序的文本信息的输出窗口

l 一个用于预览被编辑特效的预览窗口

l 另外的编辑模块还有用于编辑代码的编辑器和用于shader参数的GUI编辑器。Shader参数能被指定为“艺术家可编辑”标记然后它就能够用艺术家编辑器模块进行编辑。

创建一个基本的照明特效

在这节,我们将创建一个简单的照明特效在RenderMonkey 的预览窗口渲染一个明亮的材质。尽管这个简单计算光照强度的方法来自用于初学者图形学书籍,但是它作为学习用RenderMonkey 集成开发环境快速开发shader的指南非常好。它还充分展示了用微软的HLSL开发shader程序的的优雅,我们能用熟悉的光照公式而且用很少的几行代码就能够实现很好的视觉效果。

我们将用Phong光照模型来实现这个特效。如果我们仔细研究任何一本图形学的书籍都能找到计算该光照模型的公式,该公式如下:

I = Iambient + Idiffuse + Ispecular (1)

每个光照组件贡献的计算如下:

Iambient = Ka*Ia (2)

Idifuse = Kd*Id * (N dot L) (3)

Ispecular = Ks*Is * (V dot R)n (4)

Ka ,Kd ,Ks 分别环境,漫射和镜面光照的系数。根据我们表面的反射系数,这些参数被指定为范围在0到1的常量值。如果我们想要一个高反射率的表面,我们要设置Kd和Ks的值接近1。这将产生一个光亮的表面,在光直接照射的地方有一个高强度的高光 。为了模拟一个高吸光率的表面,我们设置反射率的值接近0。

Id是漫反射光照强度,Is是镜面反射强度,Ia是环境光强度。N,V,R分别为法向量,视向量和反射向量。 n是镜面反射系数,调整视向量和反射向量的之间的角度值。光泽的表面有一个狭窄的光照范围(这两个向量之间的夹角很小),一个以南的表面有宽的反射范围。因此一个非常光泽模型有一个大的n值(100左右),一个黯淡的表面有一个大概等于0.5的值。

我们在像素shader中用公式(2)——(4)来计算该光照模型的每个像素的最终颜色。但首先我们要建立应用程序和特效工作区。

运行时数据库预览

在RenderMonkey 中的每一组视觉特效都被压缩到一个单独的XML工作区中。除了纹理和材质存储在一个单独的文件中之外,所有这些信息对创建特效都非常关键。它使用户可读的,而且每一个游戏开发人员都能够创建自己的转换工具将RenderMonkey 的文件格式转换成他们各自的游戏引擎的脚本格式。我们有充分的理由选择用XML来存储特效工作区。最重要的,XML是工业标准且不失易用性(RenderMonkey 用微软的XML剖析器还有其他一些可选的理由)。他表示数据很容易而且是用户可扩展的。最酷的就是,任何人都能用IE直接打开RenderMonkey的XML文件进行阅读 — 它只是另一种ASCII文件格式。

要创建一个基于shader的特效,我们首先要启动一个应用程序,它将自动为你创建一个空的工组区。所有和特效有关的数据都会用RenderMonkey的运行时数据格式存储在该工作区中。每个特效工作区由下列一些元素组成:

l 变量节点

l 流映射

l 模型

l 纹理变量

l 特效组

一个特效组把一系列相关的特效组合在一起。比如,你可能想把所有用一个噪点函数渲染的混乱特效组合在一起,像云,火或等离子。

每一个特效组由一个或多个特效节点组成。每一个特效节点用来描述一个单独的视觉特效。你可能想用一个单独的过程特效,或用几个绘制掉用来产生你想要的结果。每个绘制调用可能有下列数据组成:

l 一个渲染状态块(可选)

l 一个顶点shader(必须)

l 一个像素shader(必须)

l 一个几何模型参考(必须)

l 一个流映射参考(必须)

l 一个或多个有有效纹理参考的纹理对象(可选)

l 变量节点(可选)

所有在RenderMonkey特效工作区涉及到的单独项目都被指定为节点。
 楼主| 发表于 2008-10-23 16:53:39 | 显示全部楼层
工作区试图

特效工作区中的主要窗口就是工作区视图。他是一个可停靠的窗口,通常位于主界面的左侧,它包括一个用于显示特效数据库的高级视图的节点树。图2显示了工作区视图窗口:



图2.工作区视图

工作区视图能访问特效工作区中的所有元素。这样设计的目的是能根据每个单独特效之间的共同属性将他们组合在一起。

工作区视图中有两个标签:特效标签和艺术标签。特效标签用于显示全部的工作区——所有变量和过程。艺术视图只显示那些在工作区中被指定了艺术家可编辑标志的变量。程序员用特效标签开发了一种特效,然后把它交给艺术家,艺术家就能够简单的通过调节艺术标签中的艺术家可编辑变量来调出他们想要的效果。

好了,让我们开始实现我们的特效。如果你在工组区节点处单击右键,将探出一个菜单,然后选择 Add Effect Group 菜单项。该菜单如图3所示:



图3 用于添加新的特效组的上下文菜单

当你在工组区中添加一个新的特效组的时候,RenderMonkey将自动在你的工作区中添加一些节点。他自动添加一个含有一个过程的特效样本。该过程中包含一个顶点和像素shader的示例,和一个模型。如果你有一块ATI RADEON 8500或更好的图形芯片,你将能在预览窗口中看见一个红色的茶壶。如果没有,你需要把像素shader换成 PS_1_1(我将在后面的文章中教你怎么换)。RenderMonkey也增加一个叫做view_proj_matrix的矩阵变量和一个标准的流映射节点——standard mapping。还增加了一个模型节点。这是你能在功能完善的特效基础上创建比一个红色茶壶更好的视觉效果。

变量的创建和管理

你的任何一个基于shader的特效都要有一些用于当前渲染的参数。在RenderMonkey中这些参数都被指定为变量节点。你能够在节点树的任何级别增加你的变量。
 楼主| 发表于 2008-10-23 16:54:10 | 显示全部楼层
既然我们已经知道了要在我们的shader中需要一些输入变量,那么,现在就让我们加入它们吧。要想加入变量你需要在想要把变量增加到的节点上单击右键,再弹出的菜单中选择“Add Variable“菜单项。(见图4)



图4 增加变量

然后会弹出如图5所示的对话框



图5 增加变量对话框

你要为你的变量节点选择一个RenderMonkey支持的数据类型:

l 标量(一个简单的浮点变量)

l 向量(4D 浮点变量)

l 矩阵(4×4 浮点矩阵)

l 颜色(4D 浮点变量,分别用表示 RGBA)

l 纹理变量:

? 2D 纹理贴图

? 立方贴图

? 体积纹理

节点左边的图标可以帮你快速的确定节点的类型。例如,矩阵类型左边会有一个 图标,而颜色则为 。

默认情况下,新创建的标量,向量和矩阵变量没有被指定为艺术家可编辑,而颜色,纹理,立方贴图和体积纹理变量则被指定为了艺术家可编辑。你能够在变量创建时指定该变量是否为艺术家可编辑(在 Add Variable 对话框中指定Artist Editable)。这个标记将决定该变量是否在艺术标签中显示。如果你想指定一个以创建的变量为艺术家可编辑的,你可以右键单击该变量然后选择Artist Variable 菜单项。如果想移除艺术家可编辑属性,可再次右键单击该变量,然后再次选择Artist Variable 菜单项即可。一个黄色的小三角图标江指出该变量是否为艺术家可编辑,如果该变量是艺术家可编辑的则在该变量图标的左上角就会出现这个黄色的小三角: ,否则没有。

预定义的RenderMonkey 变量

你可能已经注意到了,当你在创建一个新的特效组的时候,RenderMonkey 自动为你增加了一个叫做 view_proj_matrix 的矩阵变量。这就是一个预定义变量的例子。与定义的变量是一些常量值,他们在程序运行时就已经被指定好了。而且你不能直接改变它们的值。RenderMonkey为了方便用户提供了一组预定义的变量:

? view_proj_matrix: 一个组合了摄像机和投影矩阵的矩阵类型

? view_matrix: 一个摄像机矩阵

? inv_view_matrix: 摄像机矩阵的你矩阵

? proj_matrix: 投影矩阵

? time: 这是一个向量类型的变量,它提供了当前的时间值,它的值能在RenderMonkey 的优先选择对话框中修改,其默认值为当前时间值与120调制的值。

? cos_time: 一个向量类型的变量,它是时间的余弦值

? sin_time: 一个向量类型的变量,它是时间的正弦值

? tan_time: 一个向量类型的变量,它是时间的正切值



最简单的添加预定义变量的方法是在 Add Variable 对话框中选择适当的
 楼主| 发表于 2008-10-23 16:54:43 | 显示全部楼层
量类型,然后 Name 下拉列表框中选择你想要添加的变量的名字。(如图6所示)注意,你选择的变量的名字必须与上面选择的类型一致,否则RenderMonkey将不能将其正确的初始化,因为RenderMonkey从变量的名字和类型两方面来判定预定义的变量。



图6 选择预定义的变量

与定义的变量在工作区中也很容易辨识,他将在变量类型图标的左下方有一个绿色的小图标,如图 。

流映射模块

另一个自动添加到特效工作组中的节点是流映射节点。流映射节点能在工作区的任何地方创建(直接在特效工作区中,直接在特效工作组中,或者在各个过程中)。该节点的作用是绑定数据流到输入寄存器中供shaders使用。RenderMonkey使用直接来自模型数据来自动产生这个流或者你通过用户接口来定义流通道,然后由应用程序计算该流。

流映射模块被用来给一个过程装配几何模型。要创建一个流映射节点,右键单击一个父节点(一个特效,一个特效工作区或一个特效组)再弹出的菜单中选择 Add Stream Mapping 菜单项。图7 是一个在特效工作区中创建一个空的流映射节点的例子。



图7 增加流映射节点

一旦你创建了一流映射节点,你就能够双击或右键单击选择 Edit 调出流映射节点编辑器来编辑该节点,见图8


图8 流映射节点编辑器

我们知道要正确地计算光照,需要顶点的法线和定点的位置。让我们把它们添加到我们的工作区中。双击流映射节点调出流编辑器。我们单击 Add Channel 按钮增加一个新的通道。然后选择想要的输入寄存器,然后使用法,索引和类型。如果你想删除一个通道,单击该通道后面的 X 按钮。图9 中我已经增加了一顶点的法线通道,不要忘了把法线通道的类型设置成 FLOAT3。



图9 增加一个法线通道

要真正的要流映射起作用,你需要在你的过程中增加一个流映射参考。要增加一个流映射参考,你要确保已经在工作区树的某个地方创建了一个流映射节点。然后在你想放置该参考的过程节点上单击右键,再弹出的菜单中选择 Add Stream Mapping Reference菜单项(如图10 )



图10 在过程中增加一个流映射参考

一个新的流映射参考被创建。初始情况下这个参考是没有连接任何流映射节点的。图标上红色的斜杠()表示该参考节点没有被正确的连接。要正确地连接,右键单击过程中的流映射节点,再弹出的菜单中选者Reference Node 菜单项,然后选择你要连接的节点名称(如图11)。你也可以双击流映射参考节点然后将其重命名为流映射节点来直接连接它。
 楼主| 发表于 2008-10-23 16:56:40 | 显示全部楼层




图11 连接一个流映射参考到一个流映射节点

为了确定一个过程中流映射的范围,RenderMonkey 首先要检查该过程中是否有一个流映射实例。如果在过程中既没有找到流映射的实例也没有找到流映射参考,应用程序将到整个工作区中去查找第一个流映射节点或参考。所以你必须考虑放置流映射节点或参考的位置,因为错误的使用流映射节点将导致渲染结果的错误。

如果一个流映射节点被找到且被判定是正确的,将出现一个流映射参考节点的图标:。注意,图标中的小箭头说明这只是一个参考而不是一个真正的流映射节点。在RenderMonkey 中所有的参考节点的图标上都有一个小箭头,所以通过它们你可以很容易的找到工作区中的参考节点。

模型管理

一个特效要通过一个几何模型才能过表现出来。RenderMonkey用模型和模型参考节点来允许用户指定哪个模型被渲染。正如你所看到的,再主工作区节点下包含一个模型节点,在过程节点中包含一个模型参考节点。通过一个红色的小茶壶图标你能很容易的找到模型节点,和参考模型节点(茶壶下有一个小箭头,前文已经提到过每个参考节点图标的左下角都有一个这样的小箭头)。要在模型节点中增加一个新的模型,双击模型节点再弹出的对话框中原则一个你要添加的模型文件。为了绑定数据流到shaders,RenderMonkey将在一个工程中成对的增加一个模型参考节点和一个流映射参考节点以保证必要的数据在运行时就存在且能即时地将其绑定到流源。

管理特效

尽管我们在这次练习中不使用任何额外的特效,我们也暂时讨论一下关于RenderMonkey中的特效管理。工作区中的每个特效都被用来绘制一单独的,连续的视觉特效。他有一个或更多的绘制调用组成。要创建一个新的特效,在特效工作组节点上单击右键,再弹出的菜单中选择Add Effect(见图12)。



图12 在工作区中增加一个新的特效

你能很容易地将一个特效重命名。默认的,RenderMonkey在增加一个新的特效的同时会增加一带有HLSL顶点和像素shaders的一个单独的工程节点。要想看到新增的特效节点的效果,你要将该节点设置成活动的。要激活该节点,在该节点上单击右键然后再弹出的菜单中选择Set as Active Effect。你能很容易的辨认出一个激活的特效节点,因为它将粗体显示。

现在我们已经接近了可编程流水线的核心——shaders自身。RenderMonkey同时支持汇编和高级着色语言shaders。为了增加新的像素或顶点shaders,在你想要将其添加到的特效节点上单击右键,选择Add Vertex Shader 或Add Pixel Shader。(见图13)



图13 增加Shaders

现在,你要选择你想要添加的shader的类型。在如图14的对话框中选择一种你想要的shader类型(汇编或HLSL)。



图14 增加一个新的Shader

单击OK按钮增加一个新的shader。通过图标你能很容易的辨认出Shaders的类型:DirectX汇编语言的顶点shaders的图标为 ,汇编的像素shaders的图标为 ;DirectX HLSL的顶点shaders的图标为 ,像素shaders的图标为 。

RenderMonkey将根据语言自动地选择合适的shader编辑器。注意,每个过程中只能有一组顶点和像素shaders。如果你想改变一个shader的类型,你需要删除旧的shader然后增加一个新的。

编辑shaders

现在我们已经有了一个包含一对shaders的过程,那么现在就让我们看看实际的代码吧。要编辑一个shader,双击该shader节点,然后RenderMonkey将打开一个适当的shader编辑器。一个单独的特效中的所有过程都共享一个shader编辑器窗口。图15显示了一个shader编辑器用户界面的快照。


 楼主| 发表于 2008-10-23 16:58:54 | 显示全部楼层
图15 shader 编辑器窗口(HLSL shader)

在上面的图形用户界面中,shader编辑器有两个标签叶;一个用于顶点shader另一个用于像素shader。这个用户界面根据你选择的shader类型的变化而变化。图16 是一个汇编语言shader编辑器用户界面的快照。



图16 汇编语言shader编辑器窗口

要编辑不同过程的shaders,你只需要简单得选中你想要编辑的过程。顶点和像素shader标签将被更新为新过程的顶点和像素shader标签叶。你能用Ctrl和Tab键的组合来快速的在顶点和像素shader标签叶之间切换。

顶点shader设置和编辑

让我们在我们地一个过程的顶点shader中增加一些代码。下表显示了我们将要增加的代码。(表1):

float4x4 view_matrix;

float4x4 view_proj_matrix;

float4 lightDir;



struct VS_OUTPUT

{

float4 Pos : POSITION;

float3 Norm : TEXCOORD0;

float3 View : TEXCOORD1;

float3 Light : TEXCOORD2;

};



VS_OUTPUT main(

float4 inPos : POSITION,

float3 inNorm : NORMAL )

{

VS_OUTPUT Out = (VS_OUTPUT) 0;



// Output transformed position:

Out.Pos = mul( view_proj_matrix, inPos );



// Output light vector:

Out.Light = -lightDir;



// Compute position in view space:

float3 Pview = mul( view_matrix, inPos );



// Transform the input normal to view space:

Out.Norm = normalize( mul( view_matrix, inNorm ) );



// Compute the view direction in view space:

Out.View = - normalize( Pview );



return Out;

}

表1于计算Phong光照的顶点shader

顶点shader变换顶点位置,然后将其输出。然后她用一个名字为lightDir的shader变量计算了光向量(我们将在我们的创建完成我们的shaders后增加shader昌亮)。他还用RenderMonkey的一个预定义变量——view_matrix计算了顶点,视向量和法向量在视空间的位置,然后将视向量和法向量输出到像素shader中。

在我们实际增加这些代码之前,让我们仔细看看RenderMonkey用于编辑HLSL shaders的用户界面。

高级着色语言(HLSL)编辑器包括三部分。在编辑器顶部有一个用于管理shader参数的小装置。中间的文本编辑器用于显示HLSL shader的参数声明。该部分是不可编辑的,他仅被上部管理shader参数的小装置控制。这样能有效的保证RenderMonkey的变量节点和纹理对象正确的映射到HLSL参数。底部的窗口用于编辑实际的shader文本(见图15)。注意,一旦完成了常量和采样器的映射,你就能将常量编辑器块最小化取消其前面的钩选。

要映射一个变量节点(向量,颜色,矩阵,或标量)单击变量名标签后的箭头按钮:再弹出的一个包含了在被编辑的shader范围内的所有变量节点的菜单中选择一个你想映射的节点。(图17)




图17增加变量到HLSLshaders

这是,“name”标签栏将会变成你选择的节点的名字。接下来你要点击“Add ”按钮将新增加的变量节点加入到声明块,且将其映射为一个shader常量。然后,你将在实际的文本声明中看到该声明的变量。

现在让我们增加一个光向量,将其映射为我们写的顶点shader中的一个常量。在特效工作区节点上单击右键然后选择Add Variable。然后选择vector变量类型,将其命名为lightDir。若果你愿意也可以不选Artist Editable。单击OK按钮将在你的工作区中增加一个新的光向量,你将看到一个像这样的节点。转到我们已经打开的顶点shader编辑器,一步一步地将这个光向量映射为一个顶点shader的常量。当你点击Add按钮后,声明块中将增加一个像这样的文本——float4 lightDir;我们已将在我们的shader中增加了对一个常量!

接下来该shader需要的一个变量是视矩阵。应为它是RenderMonkey的一个预定义变量,所以,你不能直接改变它的值。好了,让我们在工作区中增加该变量。右击特效工作区节点选择Add Variable。选择Matrix变量类型。你将看到名称编辑框变成组合框。展开这个组合框,在出现的变量列表中选择view_matrix。然后单击OK搞定。

你将在工作区中看到这样一个节点。左下角绿色的小”p”表示它是一个RenderMonkey的预定义变量。根据上述步骤增加这个变量到顶点shader的声明区。下表列出了声明块中的全部变量(顺序并不重要):



Float4×4 view_proj_matrix: register(c0);

Float4 lightDir;

Float4×4 view_matrix;
现在你能简单的书写余下的shader代码(顶点shader输出结构声明和主函数)到shader的文本编辑器窗口。

用户应该已经注意到了,RenderMonkey中将要被映射到高级着色语言中的参数的节点必须有一个合法的名称。请参考HLSL语言的用户手册来了解更多的关于命名规则的信息。

默认情况下,一个HLSL shader 的入口函数名为main,(顶点和像素shader中都适用)。如果你想改变入口函数名,在入口点编辑区改变一个你想要的名字即可:.

因为每个shader都需要一个编译目标。所以,我们也需要为它指定一个。默认的,RenderMonkey的 HLSL shaders 提供了vs_1_1和ps_1_4。要改变目标的版本,从目标组合框中的列表中选择一个你想要的目标。你要为顶点和像素shader分别指定目标。请参考HLSL文档来了解每个目标。

底部的区域用于编辑shader的文本。该文本中至少要包含一个用于指明shader编译的入口点的函数。这个文本编辑器有HLSL风格的语法颜色。
 楼主| 发表于 2008-10-23 17:13:37 | 显示全部楼层
编译你的shaders

现在我们已经输入了我们的顶点shader,对每一个shader开发人员来说,接下来要做的事情就是编译它以确定它是否正确。要编译它,点击主工具栏中的提交改变按钮(图标为:)。你也可以用快捷键(F7)来开始编译。这将编译所有工作区中经过修正的shaders,然后将编译结果输出到输出窗口。

输出窗口

输出窗口是一个可停靠的窗口,它通常位于主用户界面底部(见图18)。该窗口用于输出shader的编译结果和不同应用程序的一些文本信息。输出窗口与shader编辑器链接用于高亮显示编译错误。




图18 输出窗口

一旦你点击了提交改变按钮,如果shader中有错误,他们将被显示在输出窗口。点击提交改变按钮不仅编译当前的shader,它还将存储shader代码的改变。还有就是,提交改变将应用到所有别改变的打开的shaders。在输出窗口中双击一个错误将打开一个纠正窗口并且高亮显示有错误的行(见图19)。如果你改变了shader的文本然后没有提交就想关闭窗口,RenderMonkey将询问在关闭窗口之前是否提交改变。


图19 HLSL shader 中的编译错误
编辑汇编

尽管我们这个练习中没有用到汇编sahders,还是让我们认识一下怎样编辑汇编shaders。汇编shader编辑器窗口有两个窗格扣组成——上面的窗格用于绑定RenderMonkey的变量节点到shader的常量寄存器中,下面的窗格用于编辑汇编shader文本。下面是汇编shader编辑器窗口的快照(如图20)



图12 汇编语言编辑器

常量储存编辑器为一个三列的视图列表。每行代表一个特定的寄存器的值。第一列(Constant)用于指定常量寄存器的索引。第二列(Name)显示连接到寄存器的节点的名字或“…”(如果没有变量链接到寄存器)。第三列显示的是连接到寄存器的变量节点的初始值。

绑定一个RenderMonkey变量节点到一个常量储存寄存器意味着软件将直接将节点的内部值绑定到寄存器值。在RenderMonkey中,向量和颜色节点表示为4个浮点值,标量被映射为四个相同的浮点值,矩阵用16个浮点值表示。

要绑定一个节点到寄存器,在你想要绑定的常量行的“Name”列上单击右键在弹出的菜单中选择一个变量节点(见图21)。该菜单包含了所有在被编辑的shader范围内的变量。一旦你选择了一个节点,他的名字将出现在“Name”列,它的初始值将显示在“Initial Value”列。



图21 映射一个节点到汇编shader常量寄存器

要清空一个常量寄存器,在上述的菜单中选择 Clear。以前与节点连接的变量名将被“…”替代,它的初始值也将被清空。

注意,如果你绑定一个矩阵到一个特殊的常量,该常量将占四个常量行。

编辑器支持像素和顶点汇编代码的自定义语法颜色。而且还能完全支持剪贴板操作。

像素shader编辑和设置

现在,我们应经对顶点shader有了一个完整的了解,接下来让我们看看像素shader。要编辑像素shader,要在shader编辑器窗口中选中Pixel Shader标签页。在开始编辑文本之前,然我们先回顾一下光照公式以确定要用到那些参数。参照公式(2)—(4)我们能确定要用到以下参数:

? Ka,Kd,Ks — 分别为环境,漫射和光照系数。

? Ia — 环境光强度。

? Id — 漫反射光照强度。

? Is — 镜面反射光强度。

? Ns — 镜面反射系数。

以上参数我们要将其作为常量添加到像素sahder中。Ka,Kd,Ks,ns将作为标量添加到工作区中,Ia,Id和Is能被作为颜色节点添加。根据下表将变量节的添加到工作区节点中:

1. Ka:名字为Ka的标量变量

2. Kd:名字为Kd的标量变量

3. Ks:名字为Ks的标量变量

4. ns:名字为Ns的标量变量

5. Ia:名字为Ia的颜色变量

6. Id:名字为Id的颜色变量

7. Is:名字为Is的颜色变量
 楼主| 发表于 2008-10-23 18:39:12 | 显示全部楼层
下图为你定义完成后工作区树视图的快照:



好啦,让我们将这些参数添加到像素shader的声明块中。用我们在顶点shader一节中讲解的方法将他们添加到像素shader的声明中。如果你已经添加完成了最后一个节点,你应该能看到下面的声明块:

Float Ka;

Float Kd;

Float Ks;

Float Ns;

Float4 Ia;

Float4 Id;

Float4 Is;



现在,我们已经准备好要开始写我们的像素shader的代码了。这里我们将真正感受到用高级着色语言编写sahders程序的简单和优雅。如果你尝试过用汇编语言写shader程序,那么你肯定会喜欢这种改变。本例中完整的像素shader程序如下(不包含声明部分):

float4 main( float4 Diff : COLOR0,

float3 Normal : TEXCOORD0,

float3 View : TEXCOORD1,

float3 Light : TEXCOORD2 ) : COLOR



{

// Compute the reflection vector:

float3 vReflect = normalize( 2 * dot( Normal, Light) * Normal -Light );



// Compute ambient term:

float4 AmbientColor = Ia * Ka;



// Compute diffuse term:

float4 DiffuseColor = Id * Kd * max( 0, dot( Normal, Light ));



// Compute specular term:

float4 SpecularColor = Is * Ks * pow( max( 0, dot(vReflect, View)), Ns );



float4 FinalColor = AmbientColor + DiffuseColor + SpecularColor;



return FinalColor;



}



你只需要简单的将这些代码写到像素shader的文本编辑器中然后点击提交改变按钮。记住,我们用了Pow指令,所以要将我们的目标设置成ps_2_0或更高版本。
预览窗口

现在,我们已经完成了shaders的编辑工作,但是要想看到我们编辑的代码的效果,还需要一个能用于查看结果的窗口。在RendeMinkey中,预览窗口就是用来交互的预览我们编辑的结果的窗口。所有shader中的变化或参数的更新都将适时地被渲染出来,一次他是真正的交互式shader开发。图23显示了一个海洋特效的预览窗口。



图23 预览窗口

在RenderMondey的标准预览模块中提供了简单的导航系统:

l 在窗口中平移用上下左右键,

l 向前或向后移动摄像机用“Z”和“X”键,

l 用鼠标旋转屏幕

注意,预览窗口中的模型将绕着Z轴旋转。

点击“P”键将根据渲染过程的个数显示为一个视口阵列,用于预览每一个渲染过程。(如图24):



图24 预览窗口中的多重视口

你也能选择一组预定义的视图来观看你的模型。在预览窗口中单击右键,再弹出的菜单中选择一个你想要的视图。在该菜单中选择“Properties”将允许你改变预览窗口的属性。再弹出的对话框中将允许你:

l 改变预览窗口的背景色,

l 改变过程阵列视图的背景色

l 改变视域

l 改变远近剪切面值

编辑变量

现在,我们的预览窗口中将出现一个白色茶壶。茶壶的外表取决于变量的值。我们要将我们shaders中的所有参数都设定一个有意义的值。不过,在这之前,先让我们讨论一下怎样编辑变量。编辑变量有两种方法,一种是双击该变量节点,一种是右击该节点再弹出的菜单中选择“Edit”。RenderMonkey将自动选择一个与被编辑变量相匹配的编辑框。

常量变量

 楼主| 发表于 2008-10-23 18:39:49 | 显示全部楼层
每个标量都可以通过下图所示的标量编辑模块编辑。注意,你可以用任何方法改变标量的值,如果你最后想反悔,可以单击“Cancel”。不过论你最后怎样,预览窗口都会交互地显示你的改变。


图25 标量编辑器

要编辑一个标量,你可以直接指定一个值,也可以通过滑动条交互的改变它的值。让我们将我们工作区中的标量设置成以下值:

1. Ka = 0.8

2. Kd = 0.8

3. Ks = 1.0

4. Ns = 100.0



正确的指定值后,你将在预览窗口中看到一个白色的茶壶。我们已经开启了光照!

向量变量

每个向量能通过向量编辑模块进行编辑:




图26 向量编辑器

每一个向量组件也向标量一样能直接指定值,也能通过滑动条来改变。用户也可以钩选“Keep normalized”选项以保持向量始终是归一化的。若果你对结果不满意,也可以单击Cancel按钮。

好了,现在我们来设定光向量的值。双击lightDir变量然后输入下列值:

X = -0.4; Y = 0.3; Z = 0.8; W = 0.0;

矩阵变量

尽管在本例中我们没有修改任何矩阵变量,也让我们了解一下怎样用怎样用矩阵编辑模块来编辑矩阵变量:



图27 矩阵编辑器

通过以上两例,相信读者已经知道怎样编辑矩阵变量了。矩阵变量值是多了几个值而已。这有一个选项用来将矩阵恢复为单位矩阵(Set to Identity Matrix)。
颜色变量

每个颜色变量都能通过颜色编辑模块编辑:



图28 颜色编辑器

用户能通过RGB和HSV两种模式来编辑颜色。可以直接输入颜色值,也可以通过颜色各个组建后的滑动条,还可以在颜色盘上直接选择一种颜色。窗口最右边的滑动条用来调节颜色的亮度。你调节的颜色时时地显示在左上角的小方框中。Float Point 选项只对RGB模式有效,它将其各个组件值限制在-1.0和1.0范围之内。负的颜色值能用来减少颜色。同样你也可以在不满意时点击Cancel按钮。

如果我们将Ia值设置为R = 0, G = 112, B = 0, A = 255,我们将看到如图29所示的茶壶。



图29 Phong 光照特效

渲染状态块管理

尽管我们已经完成了我们的第一个视觉特效。我们还是要探索一下怎样修改每一个绘制调用的渲染状态。每个过程都可能有若干个渲染状态,它可能是从一个更高级的过程继承而来也坑能就是他自己的。如果想创建一个渲染状态节点,在你想将其放置到的过程节点上单击右键,再弹出的菜单中选择“Add Render State Block”如图30:



图30 在过程中增加渲染状态块
 楼主| 发表于 2008-10-23 18:40:24 | 显示全部楼层
如果一个过程中没有定义渲染状态块,应用程序将搜索整个工作区树,然后将其找到的第一个渲染状态块节点作为该过程渲染状态块的父节点。当你在一个过程中创建一个渲染状态块节点时,它将继承在工作区中找到的第一个高级别渲染状态块的值。如果以前没有创建过渲染状态块,那么它将不继承任何值。改变新创建的渲染状态块的值将覆盖其继承的值。注意,在搜索过程中应用程序只查找当前和默认特效中的各个过程。也就是说每个特效中渲染状态块的值不能被其他特效访问。要编辑渲染状态,双击渲染状态节点或在该节点上单击右键再弹出的菜单中选择“Edit”。渲染状态编辑窗口如图31所示:



图31 渲染状态编辑器

要编辑一个特定的渲染状态,在你要编辑的渲染状态行的Value列单击左键,如果该状态由于定义的值,你可以在它们中选择一个,如果没有你可以直接指定一个值。

让我们将我们的茶壶改为线框显示。要做到这点其实相当容易。在渲染状态编辑器中找到Fillmode渲染状态将其值设为WIREFRAME。你将立即在预览窗口中看到一个县矿石的茶壶:



图32 线框显示

当今的游戏中使用个工各样的纹理贴图来生成视觉特效。现在,就让我们来学一学怎样在RenderMonkey中使用纹理贴图。就像你以前学习的一样,RenderMonkey中有专门用于2D纹理,立方贴图和体积纹理的变量类型。那么现在就让我们在工作区中增加一个2D纹理贴图变量。在我们的特效工作区节点上单击右键选择Add Variable。选择Texture类型然后将其命名为baseMap。一个纹理变量将出现在你的工作区中(默认的,纹理变量都被指定为艺术家可编辑的)。

接下来,为了将纹理应用到我们的特效中,需要在顶点shader中增加一个纹理坐标流。双击名字为standard mapping的流映射节点燃后增加一个新的通道用于纹理坐标:Reg = v2, Usage = TexCoord, UsageIndex = 0, Type = Float2。这样就在我们的顶点shader中增加了一个新的流通道。

下面的步骤是在我们的顶点shader程序中增加纹理坐标。打开顶点shader的文本编辑器然后输入以下代码(下面列出了代码)。粗体显示的行和被注释的行是不同于上面例子的部分:

float4x4 view_matrix;

float4x4 view_proj_matrix;

float4 lightDir;



struct VS_OUTPUT

{

float4 Pos : POSITION;

float3 Norm : TEXCOORD0;

float3 View : TEXCOORD1;

float3 Light : TEXCOORD2;

float2 Tex : TEXCOORD3; // NEW

};



VS_OUTPUT main(

float4 inPos : POSITION,

float3 inNorm : NORMAL

float2 inTex : TEXCOORD0 ) // NEW

{

VS_OUTPUT Out = (VS_OUTPUT) 0;



// Output transformed position:

Out.Pos = mul( view_proj_matrix, inPos );



// Output light vector:

Out.Light = -lightDir;



// Compute position in view space:

float3 Pview = mul( view_matrix, inPos );



// Transform the input normal to view space:

Out.Norm = normalize( mul( view_matrix, inNorm ) );



// Compute the view direction in view space:

Out.View = - normalize( Pview );



// Propagate texture coordinate to the pixel shader:

Out.Tex = inTex; // NEW



return Out;

}



新增的三行代码将顶点shader从输入的顶点流中获取的纹理坐标输出给像素shader,但是,要想真正的在像素shader中对纹理进行采样,我们还需要将我们的纹理变量绑定到一个纹理对象中。
纹理对象

要使用纹理变量,你首先要创建一个纹理变量(在你的工作区中用增加变量对话框创建纹理变量)。一旦一个纹理变量被创建,你需要选择一个从中加载纹理的文件。要在一个过程中实际的使用一个纹理,你要在该过程中增加一个纹理对象(在过程节点上单击右键,选择Add Texture Object,如图33)。图33 在过程中增加纹理对象

这将创建一个空的纹理对象。一个纹理对象如果没有一个有效的纹理引用,它的图标上将用一个红色的叉线:

。纹理对象映射到你shaders中的纹理阶段,他们还用于存储纹理和采样器状态。要使用一个纹理对象,还需要增加一个纹理引用。要增加一个引用,在纹理对象节点上单击右键,在弹出的菜单中选择Add Texture Reference菜单项(如图34)。



图34 为纹理对象增加一个引用
 楼主| 发表于 2008-10-23 18:40:58 | 显示全部楼层
这将创建一个空的纹理引用。要实际绑定一个引用到一个纹理变量,用户还需要指定要引用的变量的名字。如果一个有效的纹理变量被找到,纹理引用上的红叉线将消失。如果红线没有消失,那就说明纹理变量没有被成功的引用。默认情况下,如果工作区有一个baseMap纹理变量,RenderMonkey会将纹理引用绑定到该变量,所以我们不需要做任何事。

如果我们想为我们想为我们的纹理贴图指定一些采样状态,我们为一个特定的纹理引用节点用纹理编辑器指定这些状态值,双击纹理引用节点即可打开纹理编辑器。(如图35)



图35 纹理编辑器

纹理编辑器为每个特效中的每个过程多分配了一个标签页。纹理编辑器的顶部包含一个纹理应用的列表。点击纹理图标,能选择观看该纹理或设置纹理状态。要设置一个特定的状态,在状态行和Value 列单击,如果该状态有预定值则选择其中一个,如果没有直接指定一个值。注意,纹理编辑器为每个有有效文件关联的纹理变量都增加显示一个小的缩略图,你将在该图的左下角看到一个小图标,这个小图标显示了纹理的类型。

注意,仅当纹理对象又有效的纹理引用的时候会出现小图标
或显示为一个缩略图。如果纹理对象的纹理引用没用被正确的连接,它将显示为一个叉图标。纹理编辑器为所有的纹理变量都创建缩略图,可是,对立方贴图或体积纹理它只显示一个面或一个片断。

在HLSL Shaders中使用纹理

要在我们的像素shader中使用纹理贴图,我们首先要增加一个采样器。添加一个采样器非常简单和添加一个常量的步骤一样。你必须有一个有效的有引用的纹理对象用来添加一个采样器。单击Sampler标签后的箭头()这将打开一个能映射到HLSL 采样器对象的纹理对象变量的列表。纹理引用的名字将被用于采样器。用上述的方法你可以添加也可以删除采样器对象。

如果你想绑定一个参数到一个特定的寄存器,你要在寄存器组合框的下拉列表中选择一个寄存器。变量和采样器映射的寄存器设置是各自独立的。

然我们将我们的纹理对象映射到一个采样器。点击后面的小箭头在下拉列表中选择baseMap ,然后点击Add。你将在生命窗口中看到如下代码:

float4 Ia;

float Ka;

float4 Is;

float Kd;

float4 Id;

float Ns;

float Ks;



sampler baseMap;



在下面已经更新了的像素shader的代码(粗体显示的行为相对以前更新的代码):

float4 main( float4 Diff : COLOR0,

float3 Normal : TEXCOORD0,

float3 View : TEXCOORD1,

float3 Light : TEXCOORD2

float2 Tex : TEXCOORD3 ) : COLOR



{

// Compute the reflection vector:

float3 vReflect = normalize( 2 * dot( Normal, Light) * Normal - Light );



// Compute ambient term:

float4 AmbientColor = Ia * Ka;



// Compute diffuse term:

float4 DiffuseColor = Id * Kd * max( 0, dot( Normal, Light ));



// Compute specular term:

float4 SpecularColor = Is * Ks * pow( max( 0, dot(vReflect, View)), Ns );



float4 FinalColor =

(AmbientColor + DiffuseColor) * tex2D( baseMap, Tex ) + SpecularColor;



return FinalColor;



}
如果你现在编译它,你将在预览窗口中看到一个精细的带纹理的茶壶:



图25 带纹理的茶壶特效

渲染到纹理

让我们将我们的特效变得稍微复杂一点。我们要将我们第一个过程的输出(我们刚才创建的),作文我们第二个过程的输入。这一技术叫渲染到纹理,使用它能创建各种各样有趣的特效。

渲染过程

要创建一个最简单的渲染到纹理特效,我们至少需要两个过程。让我们在工作区中增加一个新的过程。要增加一个新的过程,在特效节点上单击右键在弹出的菜单中选择Add Pass 。默认的,每个新创建的过程都将包含顶点和像素shader节点,一个模型节点和一个流映射参考节点(当然,他们允许修改)。一旦你创建了一个新的过程,你将发现在预览窗口中又出现了一个红色的茶壶。这是因为,一个特效里的过程都是按顺序别调用的。要向前或向后移动一个过程,在该过程节点上单击右键,然后选择“Move Up”或“Move Down”(如图36)。你也能用“Ctrl加Up”组合键来实现一个过程的上下移动。现在我们有两个过程,如果你将过程2移动到过程1上,你将再次看到那个带纹理的茶壶,然后你再把它移回来,又将出现红色的茶壶。



图36 改变过程顺序

为了方便调试shader程序,你也能将一个过程禁用。要禁用一个过程,在该过程节点上单击右键选择“Enable/Disable Pass”。一个禁用的过程的图标上将出现一个红叉线

表示他已经被禁用了。要激活一个过程,重复上述步骤即可。

工作区试图中有一个禁用的过程的例子:



如果你已经重新排列了过程的顺序,在继续学习之前,请将其恢复到原来的顺序(过程1在过程2之前)。

可渲染的纹理支持
 楼主| 发表于 2008-10-23 18:41:39 | 显示全部楼层
RenderMonkey 支持将任何一个给定的过程渲染输出成一个纹理供另一个后来的过程进行采样。要在你的工作区中增加该功能,下面给出了步骤:

1. 在工作区中的任何地方创建一个可渲染的纹理。注意,一次只能将一个过程的渲染输出到该纹理。要增加一个可渲染的纹理,在任何你想将该纹理添加到的节点上击右键选择“Add Renderable Texture”:



图37 增加可渲染的纹理

2. 你将看到一个新的节点,其图标为:。这就是可渲染纹理节点,一会儿我们要将其连接到一个渲染目标和一个纹理对象以便对其进行采样。

3. 接下来,你要在你的过程中增加一个渲染目标用来输出可渲染的纹理。在过程节点上单击右键选择“Add Render Target”增加一个宣告染目标(该节点的图标为):




图38 在过程中增加一个渲染目标

4. 下面,你要将渲染目标节点连接到你刚创建的可渲染的纹理。你可以通过直接将渲染目标节点的名字改为可渲染纹理节点的名字来连接它,也可以右击渲染目标节点选择一个参考节点,如下图:


图39 连接渲染目标节点到一个可渲染纹理变量

5. 现在,过程的输出有了一个绘制可渲染纹理的渲染目标节点。
6. 然后,我们要将该可渲染的纹理连接到一个过程以便对其进行采样。不过在这之前,你首先要在该过程中创建一个纹理对象和一个纹理参考。一旦你有了一个纹理参考,你必须将其连接到可渲染的纹理(或通过充命名的方式或单击右键的方式,上面已经介绍过)。



图40 连接纹理对象到一个可渲染的纹理变量

7. 现在,你就能像正常的纹理一样使用该纹理对象了。

让我们在我们的工作区中增加一个可渲染的纹理。在特效工作区节点上单击右键,选择Add Renderable Texture。然后再过程1中增加一个渲染目标(在过程1节点上单击右键选择Add Render Target)。连接渲染目标到可渲染的纹理(方法不再累述)。现在,过程1的输出已经转向了可渲染纹理变量。

下面,我们要在过程2中增加对可渲染纹理的采样能力。首先,我么要保证定点shader正确的传递了纹理坐标。将下面代码下到定点shader中:

struct VS_OUTPUT

{

float4 Pos: POSITION;

float2 Tex: TEXCOORD0;

};

VS_OUTPUT main( float4 Pos: POSITION, float2 Tex: TEXCOORD0 )

{

VS_OUTPUT Out = (VS_OUTPUT) 0;

Out.Pos = mul( view_proj_matrix, Pos );

Out.Tex = Tex;

return Out;

}



这将保证我们将插值的纹理传递给了像素shader。接下来,我们在过程2中增加一个有纹理引用的纹理对象(步骤上面都已经讲过)。但这次我们不是将其连接到纹理变量,而是连接到可渲染的纹理变量。这将直接把过程1的输出传递给过程2。打开过程2的像素shader,增加一个采样器。输入以下代码:

float4 main( float4 Diff : COLOR0,

float2 Tex : TEXCOORD0 ) : COLOR

{

return tex2D( renderTexture, Tex );

}



现在,预览窗口中出现了一个带纹理的茶壶,其纹理为我们在过程1中渲染的茶壶(见图41)。设置两个过程的纹理对象的采样器状态来获得更好的渲染效果:Minfilter = LINEAR Magfilter = LINEAR。



图41 渲染到纹理特效

编辑可渲染的纹理

要编辑一个可渲染纹理节点,双击该节点将弹出可渲染纹理编辑框(见图42)。



图42 可渲染纹理编辑器
在编辑器中,你能改变可编辑纹理的尺寸。要改变宽度或高度直接在编辑框中输入你想改变的大小,然后按回车确认。选中“Use viewport dimensions”将会把纹理的大小邦定为视口的大小。要改变纹理的格式下拉列表中选择一个与定义的格式。

编辑一个渲染目标

要编辑渲染目标节点,用户要双击该节点打开渲染目标编辑器窗口:



图43 渲染目标编辑器

通过该编辑器,用户能通过“Enable color clear”按钮是否对一个可渲染的纹理使用一个透明色。如果用户选择用透明色,编辑器还提供了一个用于指定透明色的按钮,点击它然后回弹出颜色选择对话框,在对话框中选择一共颜色。用户也能通过“Enable depth clear”复选框来制定是否使用深度清除。如果允许,用户也能指定一个清除值。

艺术家编辑器

shaders开发者面临的一个问题是怎样将其开发的特效提交给艺术家,然后通过艺术家对其进行加工来达到更好的效果。RenderMonkey 的解决方案是提供了一个艺术家编辑模块。

Shader开发人员能有选择的指定一个变量是否为艺术家可编辑。在你想要指定的变量节点上单击右键,再弹出的菜单中选择Artist Editable项,该变量节点图标的左上角将出现一个黄色的小箭头。然后你就能将你开发的特效提供给与你一起工作的艺术家了。艺术家能通过艺术标签来对艺术家可编辑变量进行编辑。当前,支持的艺术家可编辑的变量类型有向量,标量和颜色,但是,任何变量都能被指定为艺术家可编辑然后通过艺术标签进行访问。

要打开艺术家编辑器,你能通过点击应用程序工具栏中的

图标,也能在主菜单的视图菜单中选择“Artist Editor”项。


图44艺术家编辑器界面

艺术家编辑器是一个可停靠窗口,它包含了特效工作区,特效组,特效和过程标签页,只要他们中包含了艺术家可编辑的变量。如果节点中没有包含艺术家可编辑变量,那么,该节点的标签页将不会出现。
 楼主| 发表于 2008-10-23 18:42:02 | 显示全部楼层
艺术家可编辑变量将按他们的类型分组(颜色,向量和标量)。每个组都能通过点击按钮将其展开或合并。



图45 艺术家编辑器界面

在艺术家编辑模块编辑变量

颜色

每个颜色变量有三个相关的控制项——颜色样本按钮用于打开颜色拾取器,一个色调滑动条和一个强度滑动条:



图46 颜色拾取器

向量

每个向量有五个可用的控制项——一个标签按钮用于显示向量编辑器的全貌,四个带有滑动条的组件编辑框,用于编辑向量的每一个组件:


图47 艺术家编辑器中的向量编辑器


图48 展开的向量编辑框

标量

每个标量有两个相关的控制想:一个由于展开标量编辑器的标签按钮和一个用于编辑标量值得编辑框。



图49 标量编辑框



图50 展开的标量编辑器
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 07:03

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表