游戏要实现模型的突出显示,最好是边缘高亮的效果.刚听到这个东西时,第一个进入头脑中的就是:边缘检测.于是就写了一个:
Pass 0:
渲染模型到一个RenderTarget Model上,并把模型的形状写入Alpha通道.
Pass 1:
对上面得到的Alpha通道用拉普拉斯模板进行滤波,得到一个边缘,写入另一个RenderTarget Edge.
Pass 2:
把前面得到的两个RenderTarget进行合成,输出到屏幕. |
虽说效果还不错,但是用掉了两个RenderTarget,显然不合算.而且,用拉普拉斯在PixelShader中进行逐像素的处理,效率并不高.
阿来在GameDev上求得另一种方法:把模型画两遍,其中一次对模型进行一次放大,关闭Z-Write就出来这种效果了.不过有两个问题:
一是模型直接放缩是以模型坐标系的原点来的,而这个原点并不一定是在模型的中心.就算在中心,对于一些非凸多面体并不能得到很好的效果,有一些边缘会被模型遮住.
二是,关闭了深度检测,那这个模型怎么跟别的模型来进行遮挡处理呢?
后来在群里有人提醒说在3D游戏程序设计入门这本书上有,我才想起来有一个卡通渲染的例子.卡通渲染?那里面不也有轮廓生成吗?看了一下书上的实现方法,用的是三角形退化,有点复杂.于是google之,发现了一个跟GameDev上那个方法差不多思想的:
Pass0:
把模型按法线方向进行放大,然后渲染成单色模型,不过只渲染背面,避免遮住正常的模型.(把D3DRS_CULLMODE设成D3DCULL_CW就可以了)
Pass1:
正常渲染模型,不用做什么改变.不过不要忘了把D3DRS_CULLMODE改回来. |
Shader:
float4x4 matViewProjection;
struct VS_INPUT
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
Output.Position = float4(Input.Position.xyz + Input.Normal*0.4f,1);
Output.Position = mul( Output.Position, matViewProjection );
return( Output );
} |
sampler2D BaseMap;
float4 ps_main() : COLOR0
{
return float4(0, 1, 0, 1);
} |
下面是两种方法实现的效果对比:
差不多哈,区别就是用卡通渲染的那种方法出来的中间也有轮廓线.