战魂小筑

讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  257 随笔 :: 0 文章 :: 506 评论 :: 0 Trackbacks

最近使用材质节点生成HLSL代码并开始编译,也顺手开始搭建一个正规的Shader包含及编译流程,所以用到了D3DXCompileShader及ID3DXInclude

ID3DXInclude的使用方法在OGRE 1.65(或者类似的版本)的OgreD3D9HLSLProgram.cpp中有源代码可供参考

        STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType,
            LPCSTR pFileName,
            LPCVOID pParentData,
            LPCVOID *ppData,
            UINT *pByteLen
            )

此函数发生在代码中有#include XXX时, FileName就是XXX

ppData需要由用户提供FileName对应的源码内容,ANSI格式

pByteLen是代码长度

STDMETHOD(Close)(LPCVOID pData)

此函数的pData既是Open中提供的ppData, 用户可以用于自行释放内存等操作

 

本来按照正常流程, HLSL代码应该可以正常编译,我的HLSL功能大概描述:

Material.hlsl 提供基础光照模型函数

Material_Generated.hlsl 由材质节点生成的代码,包含Main入口, #include "Material.hlsl"

结果D3DXCompileShader报了一个莫名其妙的错误,找不到Main入口. 找了很久都没发现代码有什么问题. 于是开始回看OGRE代码,发现了大侠们的一句救命留言:

// copy into separate c-string
// Note - must NOT copy the null terminator, otherwise this will terminate
// the entire program string!
马上查阅我的代码,为LoadFileToString函数添加一个参数,是否添加终结符0
    bool LoadFileToString( const char* FileName, AString& Content, bool TerminateString )
    {
        wchar Buffer[MAX_PATH];
        FileStream TFile;
        if ( !TFile.Open(StringConverter::AnsiToUnicode( Buffer, MAX_PATH, FileName), FAM_Read ) )
        {
            return false;
        }
 
        dword FileSize = TFile.GetSize();
 
        Content.resize( FileSize + (TerminateString ? 1: 0) );
        TFile.ReadBuffer( (void*)Content.data(), FileSize * sizeof( char ) );
 
        if ( TerminateString )
            Content[FileSize] = 0;
 
        return true;
    }

D3DXCompileShader的Source 是需要终结的源码, 但是在ID3DXInclude的实现类Open函数中,返回给ppData的,坚决不能有终止符0.

 

总结:

   HLSL的代码编译过程是依赖#include将不同的文件碎片组合到一起后才开始解析,因此用户提供的字符串尾部带有终结符, 编译器是没有理由为你检查数据的正确性的.去掉包含终结符才是正确的做法

posted on 2010-06-18 17:01 战魂小筑 阅读(1615) 评论(0)  编辑 收藏 引用 所属分类: 渲染 Shader 引擎

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理