战魂小筑

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

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

昨天研究了下Node Based Material System, 虚幻3的材质系统是没戏了,还没用会呢. 不过Max的一个插件: ShaderFX倒是给我很大的启发,这东西就是结点型材质系统, 而且能生成真正的FX. 不像虚幻3那么不厚道,只是局部显示HLSL.

image

经过分析ShaderFX导出的Shader文件, 发现其标准材质系统使用的就是逐像素光照模型, 而不同的Materials对应的就是一种Shader处理管线, 分别可以处理各种光照,甚至达到Compositor的混合效果. 而Shader Code Generation这个环节,也远没有虚幻3那样复杂(虚幻是神,咱们不评论神到底如何),只是将光照需要的各种分量,例如Emissive, Ambient, Diffuse, Specular等根据各分量提供的计算因子直接嵌入到Pixel Shader主函数体即可.

逐顶点光照在前面的文章已经有介绍,代码相对简单, 因此以后在材质系统中准备直接上逐像素光照. 因此,需要在我的模型插件中加入Tangent及Binormal支持.

这里是一篇很不错的讲解Tangent Space Vector的文章. 文中有贴过OGRE的Tangent计算代码,不过查阅OGRE 1.65代码后发现,OGRE现在根本就不用这个函数计算Tangent,而是更为复杂的一个类.

最终,我还是使用了大野猪的ev3d的max插件代码, 如果需要的话,可以去他博客找svn下载

 

bool CMaxMesh::__cacl_tbn(sFace_t& face,bool isSkin)
{
    Point3  normal[3];
    Point3  Tangent; 
    Point3  p[3];
 
    assign(normal[0],m_MeshData.m_VertexData.m_Normals[face.vert[0]]);
    assign(normal[1],m_MeshData.m_VertexData.m_Normals[face.vert[1]]);
    assign(normal[2],m_MeshData.m_VertexData.m_Normals[face.vert[2]]);
 
    if(isSkin == false)
    {
        assign(p[0],m_MeshData.m_VertexData.m_Positons[face.vert[0]]);
        assign(p[1],m_MeshData.m_VertexData.m_Positons[face.vert[1]]);
        assign(p[2],m_MeshData.m_VertexData.m_Positons[face.vert[2]]);
    }
    else
    {
        assign(p[0],m_MeshData.m_VertexData.m_VertexWeights[face.vert[0]].m_InitPos);
        assign(p[1],m_MeshData.m_VertexData.m_VertexWeights[face.vert[1]].m_InitPos);
        assign(p[2],m_MeshData.m_VertexData.m_VertexWeights[face.vert[2]].m_InitPos);
    }
 
 
    sUVCoord_t uv[3];
    uv[0] = m_MeshData.m_VertexData.m_UVChannels[0][face.vert[0]];
    uv[1] = m_MeshData.m_VertexData.m_UVChannels[0][face.vert[1]];
    uv[2] = m_MeshData.m_VertexData.m_UVChannels[0][face.vert[2]];
 
    Point3  e1 = p[1] - p[0];
    Point3  e2 = p[2] - p[0];
    sUVCoord_t u1 = { uv[1].u - uv[0].u , uv[1].v - uv[0].v};
    sUVCoord_t u2 = { uv[2].u - uv[0].u , uv[2].v - uv[0].v};
 
    float det =  ( u1.u * u2.v - u2.u * u1.v);
    if(det == 0.0f)
    {
        Tangent = e1;
    }
    else
    {
        Tangent = u2.v * e1 - u1.v * e2;
    }
 
    //从Normal 和 Tangent里重新计算出Tangent,因为面的Tangent和顶点的Normal可能不垂直
    Point3 final_tangent;
    for(int i = 0 ;i < 3 ; ++i)
    {
        Point3 binormal  = CrossProd(normal[i],Tangent);
        final_tangent = CrossProd(binormal,normal[i]);
        final_tangent.Normalize();
        m_MeshData.m_VertexData.m_Tangents[face.vert[i]].x += final_tangent.x;
        m_MeshData.m_VertexData.m_Tangents[face.vert[i]].y += final_tangent.y;
        m_MeshData.m_VertexData.m_Tangents[face.vert[i]].z += final_tangent.z;
 
    }
    return true;
}

 

感谢大野猪友情出演,正片开始:)

image

posted on 2010-06-02 15:55 战魂小筑 阅读(2033) 评论(2)  编辑 收藏 引用 所属分类: 渲染 Shader 引擎

评论

# re: 晒下材质系统进度: 导出Tangent Space Vector 2010-06-03 11:22 小熙
可以看看游戏编程精粹5上的Shader重组,另外,GPU Gems 1 书上33章上的材质树,使用cg实现,材质类用到了Interface和函数重载  回复  更多评论
  

# re: 晒下材质系统进度: 导出Tangent Space Vector 2010-06-03 18:01 战魂小筑
@小熙
呵呵,这2个都看了. Gem5那个太简单, Cg暂时不考虑
ShaderFX的模型很好,再结合下虚幻的,那就齐了
  回复  更多评论
  


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