剑孤寒的小站

人生的价值不是用时间,而是用深度去衡量的!
posts - 75, comments - 290, trackbacks - 0, articles - 0

在现在的3D游戏中有很多非常漂亮的Shader特效,比如爆炸产生的气浪,水流过玻璃使后面的景物变得扭曲等。这些特效并不是3D游戏的专利,有很多特效其实也是可以用在2D游戏里的,今天这一节我们就来学习一下如何在Galaxy2D游戏引擎中使用PixelShader制作爆炸气浪效果。

首先要判断显卡是否支持PixelShader,在OnInitiate()函数中添加:

if (System_GetState(GGE_PSVERSION) < PS_2_0) return false;

然后创建ShaderRenderTarget

m_shaderFx = Shader_Load("shader.fx""ShaderFx", PS_2_0);
m_fxTarget 
= Texture_Create(640480true);
m_targetTex 
= Texture_Create(640480true);

Shader_Load()函数用于载入Shader文件,第一个参数是Shader文件名,第二个参数指定Shader入口函数,第三个参数指定使用的Shader 版本,这里使用的是PS2.0

RenderTarget就像一个临时的画布,我们可以将贴图画在某个RenderTarget上而不影响后台缓存或其它的RenderTarget,常常用来做一些特殊效果,在这里m_fxTarget用于绘制NormalMap贴图,m_targetTex用于绘制正常图像,以便最后进行Shader合成。为了使用Shader还必须将m_shaderFx绑定到一个ggeSprite上:m_targetSpr->SetShader(m_shaderFx);

接下来在OnUpdate(float dt)里添加如下代码:

if (Input_IsKeyDown(GGEK_SPACE))
{
       m_alpha.a 
= 1;       //气浪强度
       m_posX = Random_Int(256384);//气浪中心点位置
       m_posY = Random_Int(176304); //气浪中心点位置
       m_scale = 1.0f;//气浪大小
}

Input_IsKeyDown()函数用于判断是否有键按下,后面的GGEK_SPACE是空格键的虚拟键值,其他的键值可在文档里找到。在Galaxy2D引擎里提供了一系列Input_*函数,用于键盘鼠标输入判断。

最后在OnRender()添加如下代码:

 

//如果alpha值大于0才进行Shader合成
        if (m_alpha.a > 0)
        
{
            
//开始在m_fxTarget上画东西
            Graph_BeginScene(m_fxTarget);
            Graph_Clear();
            m_fxSpr
->SetColor(m_alpha.GetColor());
            m_fxSpr
->SetPositionEx(m_posX, m_posY, 0, m_scale);
            m_fxSpr
->Render();
            Graph_EndScene();
        }


        
//开始画正常图像
        Graph_BeginScene(m_targetTex);
        Graph_Clear(
0);
        m_bgSpr
->Render();
        Graph_EndScene();

        Graph_BeginScene();
        
if (m_alpha.a > 0)
        
{
            
//绑定Shader要使用的纹理
            Graph_SetCurrentShader(m_shaderFx);
            m_shaderFx
->SetTexture("FxTex", m_targetTex, true, TEXADDRESS_BORDER, 0);
            m_shaderFx
->SetTexture("NormalMapTex", m_fxTarget);
        }

        
else
        
{
            Graph_SetCurrentShader(
0);
        }


        m_targetSpr
->Render();
        Graph_SetCurrentShader(
0);
        Graph_EndScene();

 好了,现在将下面的Shader代码复制到shader.fx文件中就大功告成了:

sampler2D FxTex:register(s0);
sampler2D NormalMapTex:register(s1);

float4 ShaderFx(float2 texCoord:TEXCOORD0):COLOR0
{
    float3 normal 
= tex2D(NormalMapTex, texCoord);
    texCoord 
+= dot(normal, float3(000.1));
    float4 tex 
= tex2D(FxTex, texCoord);

    
return tex;
}


 

最后上一张最终效果图,由于gif只有256色所以不大清楚,不过大致的效果还是可以看出来的,自己觉得还是比较华丽的^_^,当然Shader能做的不仅如此,只要大家发挥想象力一定能作出更Cool更华丽的特效。

Feedback

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2010-01-17 18:05 by Davy.xu
问下,怎样让RenderTarget的纹理绘制带alpha通道?

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2010-01-17 19:23 by 剑孤寒
如果显卡支持,
Galaxy2D在创建RenderTarget时优先创建带Alpha通道的纹理,
可用Graph_Clear(0)将RenderTarget的Alpha通道清0并在上面绘制带Alpha通道的纹理,
但正如前面所说这项功能是依赖显卡的,
所以并不推荐使用。

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2012-03-03 23:49 by ljb
实现原理还是改变坐标纹理

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效[未登录]  回复  更多评论   

2015-10-07 00:57 by shepherd
由于种种原因,我准备自己封装资源格式。但是这样文件是直接读入到内存的,音频、纹理这些G2D是支持内存流直接读取的;但是ini和xml有什么办法直接读取内存流吗?要是自己写语法分析器,就太累了

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2015-10-07 14:40 by 剑孤寒
@shepherd
xml可以用ggeXmlDocument::Parse()函数直接读取内存中的数据,至于ini么,我不知道有了xml,还有啥用ini的理由,至少我已经5、6年没用过这玩意了

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效[未登录]  回复  更多评论   

2015-10-08 01:20 by shepherd
这是我根据提示修改的代码。采用读xml文件的LoadFile方法工作正常。采用加载到内存的Parse方法则失败。是不是我用的不对啊?
char buffer[256];
long size = 0;
FILE *fp = fopen(resource_name, "rb");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(buffer, size, 1, fp);
fclose(fp);

ggeXmlDocument *doc = Xml_Create();
//打开xml文件
doc->Parse(buffer);
//doc->LoadFile(resource_name);
//获取根节点
ggeXmlNode root = doc->GetRootNode();

ggeXmlNode music = root.GetFirstChild("music");
strcpy_s(name, 100, music.GetName());
ggeXmlNode item = music.GetFirstChild("volume");
hot_volume = atoi(item.GetFirstChild().GetName()); //得到volume
item = music.GetFirstChild("count");
int count = atoi(item.GetFirstChild().GetName()); //得到count

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2015-10-08 10:01 by 剑孤寒
@shepherd
呃,不知道你为啥不用Resource_Load()函数载入xml文件到内存,如果你非要用fopen的话,需要先把buffer清零,如果还不行的话,把xml文件内容贴一下我看看

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效[未登录]  回复  更多评论   

2015-10-08 12:49 by shepherd
fopen那段就是测试用的,目的是把文件读取到内存,用来测试内存读取xml的效果。真正使用的时候,fopen那段时没有的,函数直接接受一个void *buffer的指针,其内容来自自己的资源读取函数。
xml及相关代码,发你邮箱吧。

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效  回复  更多评论   

2015-10-09 09:59 by 剑孤寒
@shepherd
你那个buffer要清零啊

char buffer[256];
memset(buffer, 0, 256);<------加这个清零
long size = 0;
FILE *fp = fopen(resource_name, "rb");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(buffer, size, 1, fp);
fclose(fp);

# re: Galaxy2D游戏引擎教程4 - 用PixelShader制作华丽的2D特效[未登录]  回复  更多评论   

2015-10-09 17:21 by shepherd
根据提示,已经OK。正是这个原因,多谢!

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理