昨天研究了下Node Based Material System, 虚幻3的材质系统是没戏了,还没用会呢. 不过Max的一个插件: ShaderFX倒是给我很大的启发,这东西就是结点型材质系统, 而且能生成真正的FX. 不像虚幻3那么不厚道,只是局部显示HLSL.
经过分析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;
}
感谢大野猪友情出演,正片开始:)