D3D载入法线贴图的问题 众位大哥,小弟想载入法线贴图很久了,但是老是失败,代码也比较凌乱,就不打算贴太多了,直接上图片。我不是太懂为什么一个正方体读入其中会变成这样,我用相同的模型读取一个场景盒是可以的,API和Shader都可以轻松用这个方块做出来,就只有法线贴图不行。同一个模型,读出不同样式!好头痛,有哪位大哥大姐有知道的吗?先在这里谢谢了。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 对了,忘记说了,我的图形库是D3D的,觉得这个应该是顶点着色器的问题。struct VS_INPUT { float4 Position : POSITION0; float2 TexCorrd : TEXCOORD0; float3 Normal : NORMAL0; float3 Binormal : BINORMAL0; float3 Tangent : TANGENT0; };struct VS_OUTPUT { float4 Position : POSITION0; float2 TexCoord : TEXCOORD0; float3 Eye : TEXCOORD1; float3 Light : TEXCOORD2; };VS_OUTPUT vs_main( VS_INPUT Input ){ VS_OUTPUT Output; float4 OffsetPos = mul(Input.Position,matWorld); Output.Position = mul( OffsetPos, matViewProjection ); Output.TexCoord = Input.TexCorrd * 0.5f; float3 world = mul(Input.Position,matWorld); float3 eye = vViewPosition - world; Output.Eye.x = dot(Input.Tangent, eye); Output.Eye.y = dot(Input.Binormal, eye); Output.Eye.z = dot(Input.Normal, eye); Output.Light.x = dot(Input.Tangent, vLight); Output.Light.y = dot(Input.Binormal, vLight); Output.Light.z = dot(Input.Normal, vLight); return( Output ); }这里是顶点着色器的代码,如果有懂的前辈能帮忙指点下错误吗?真是谢谢了 T_T 难道这个问题很复杂吗?据说法线贴图的算法是比较基础的Shader算法,可能我还连基础的基础都没有掌握吗?%>_<%求指点,谢谢了! Output.TexCoord = Input.TexCorrd * 0.5f;为什么标准的纹理坐标要乘以一个0.5? float3 eye = vViewPosition - world; Output.Eye.x = dot(Input.Tangent, eye); Output.Eye.y = dot(Input.Binormal, eye); Output.Eye.z = dot(Input.Normal, eye);还有这儿你的eye向量没有normalize。 不知道你的TBN是不是在世界坐标空间下通常我们会把模型空间下的TBN变换到世界坐标系中,然后将TBN传给pixel shader。而不是在vs中做。 输入进来的纹理*0.5只是用于测试的,贴图是一个石板,上面石头比较小,这样的方式,可以放大一点。这个东西在RenderMonkey里面是可以运行的额。。至于eye和light都没有标准化,我是在pixel Shader里面标准化的,可能有些习惯不太好。float4 ps_main( PS_INPUT Input ) : COLOR0{ //贴图颜色,环境光和漫反射光照亮这个颜色 float4 baseColor = tex2D(TextureMap, Input.TexCoord); float3 light = normalize(Input.Light); float3 eye = normalize(Input.Eye); float3 normal = normalize(tex2D(NormalMap, Input.TexCoord).xyz * 2.0f - 1.0f); “通常我们会把模型空间下的TBN变换到世界坐标系中,然后将TBN传给pixel shader。而不是在vs中做。”意思是,把模型的TNB弄成一个float3x3的矩阵,然后乘以世界矩阵?然后一起传给像素着色器来处理? float3x3 objToTangentSpace; objToTangentSpace[0]=T; objToTangentSpace[1]=cross(T, N); objToTangentSpace[2]=N; newMat = objToTangentSpace * world;这样?总觉得怪怪的,这位大哥可以再说得仔细一些吗?我是新手,学习Shader都是自己打拼,没人带,基础有些差。谢谢你了。 我贴一段代码给你吧,都是基础,最好你去找找一些最基本的文档来看。关于normal map的,建议你去看microsoft DX8 文档中有一篇很著名的文档,叫per-pixel lighting。是现在很多图形算法的基础。vs:struct VS_INPUT{ float3 Position : POSITION; float3 Normal : NORMAL; float3 Tangent : TANGENT0; float3 Binormal : BINORMAL0; float2 tOffset : TEXCOORD0;};struct VS_OUTPUT{ float4 Position : POSITION; // 最终位置(投影空间) float2 tOffset : TEXCOORD0; // 纹理坐标 float3 f3WorldP : TEXCOORD1; // 位置 (世界空间) float3 f3WorldN : TEXCOORD2; // 法线 (世界空间) float3 f3WorldB : TEXCOORD3; // 副法线(世界空间) float3 f3WorldT : TEXCOORD4; // 切线 (世界空间)};VS_OUTPUT VS_Entry( VS_INPUT In ){ // 顶点经过世界变换,视角变换,投影变换 float4 f4Locate = mul( float4( In.Position, 1.0 ), m4World ); float4 f4Viewer = mul( f4Locate, m4View ); // 写入数据 VS_OUTPUT Out = (VS_OUTPUT)0; Out.Position = mul( f4Viewer, m4Proj ); Out.tOffset = In.tOffset; // 计算世界坐标空间的位置,法线,副法线,切线; Out.f3WorldP = f4Locate; Out.f3WorldN = normalize( mul( In.Normal, (float3x3)m4World ) ); Out.f3WorldB = normalize( mul( In.Binormal, (float3x3)m4World ) ); Out.f3WorldT = normalize( mul( In.Tangent, (float3x3)m4World ) ); // 返回; return Out;}ps:float4 PS_Entry( VS_OUTPUT In ) : COLOR{ // 计算视线(世界空间,未单位化); float3 f3View = f4EyePosition.xyz - In.f3WorldP; // 准备切线空间到世界空间的矩阵; float3x3 f3x3TBN = float3x3(In.f3WorldT, In.f3WorldB, In.f3WorldN); // 计算像素法线(切线空间); float3 f3Normal = CalculateNormal(normalMap, In.tOffset); // 计算像素法线(世界空间);通过TBN的逆矩阵将切线空间内的法线变换到世界空间; f3Normal = normalize( mul( f3Normal, transpose(f3x3TBN) ) ); // 计算环境光; float4 f4AmbColor = f4MaterialAmbient * f4AmbientLight; // 计算光的反方向; float3 lgtDir, eyeDir; lgtDir = normalize( -f4DirLightWorldDirection.xyz ); // 计算漫反射强度; float fDiffuseScale = saturate( dot(f3Normal, lgtDir) ); // 计算漫反射; float4 f4DifColor = ( f4MaterialAmbient * f4DirLightAmbient + fDiffuseScale * f4MaterialDiffuse * f4DirLightDiffuse ); // 计算高光向量 eyeDir = normalize( f3View ); lgtDir = normalize( In.f3WorldP - f4DirLightWorldPosition.xyz ); float3 fReflect = normalize( reflect(lgtDir, f3Normal) ); // 计算高光的最终值 float4 f4SpcColor = f4DirLightSpecular * f4MaterialSpecular * ( pow( saturate( dot(fReflect, eyeDir) ), fSpecularPower ) ) * fDiffuseScale; // 最终的光颜色 float4 f4Final = f4MaterialEmissive + f4AmbColor + f4DifColor + f4SpcColor; // 计算最终的光照; In.Color = f4Final * float4( co.rgb, 1.0f );}以上代码是从项目中提取出来的,你要测试的话,需要自己该一些东西。这些代码就是最基本的per-pixel lighting的光源模型。 哎呀呀,真是太感谢你了!其实我写了一小段时间的Shader,但是,只会写一些平面整体渲染类型的,一遇到矩阵之类的就非常头痛。谢谢你的指点!加你好友了,谢谢,虽然我技术很薄弱,但有什么能帮上忙的就说,我尽力! 9L的代码有问题额。// 计算像素法线(世界空间);通过TBN的逆矩阵将切线空间内的法线变换到世界空间;f3Normal = normalize( mul( f3Normal, transpose(f3x3TBN) ) );这里的TBN矩阵就是将切线空间法线变换到世界空间(T,B,N三个基都是处于世界空间),逆矩阵是将世界空间法线变换到切空间。。 URL里带IP,有些地方无法访问 托盘气球提示出不来。。 有人对Active Accessibility了解吗,请教个问题? 在一个程序启动时如何判断它是否开机自动启动的 华为今天气死我了? 【VS6】安装问题!@! 如何简单获知显卡是否支持双显示器 跪求visual studio 6.0 英文企业版的下载地址 Windows操作系统下的程序界面是系统绘制的还是程序自己的代码绘制的? 这个暑假干什么? 弱弱的问问,MFC RIBBON 中如何为控件添加变量 为什么就算我的程序退出了,dll也还一直被其他程序使用?
struct VS_INPUT
{
float4 Position : POSITION0;
float2 TexCorrd : TEXCOORD0;
float3 Normal : NORMAL0;
float3 Binormal : BINORMAL0;
float3 Tangent : TANGENT0;
};struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float3 Eye : TEXCOORD1;
float3 Light : TEXCOORD2;
};VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
float4 OffsetPos = mul(Input.Position,matWorld); Output.Position = mul( OffsetPos, matViewProjection );
Output.TexCoord = Input.TexCorrd * 0.5f;
float3 world = mul(Input.Position,matWorld);
float3 eye = vViewPosition - world;
Output.Eye.x = dot(Input.Tangent, eye);
Output.Eye.y = dot(Input.Binormal, eye);
Output.Eye.z = dot(Input.Normal, eye);
Output.Light.x = dot(Input.Tangent, vLight);
Output.Light.y = dot(Input.Binormal, vLight);
Output.Light.z = dot(Input.Normal, vLight);
return( Output );
}
这里是顶点着色器的代码,如果有懂的前辈能帮忙指点下错误吗?
真是谢谢了 T_T
%>_<%求指点,谢谢了!
Output.Eye.x = dot(Input.Tangent, eye);
Output.Eye.y = dot(Input.Binormal, eye);
Output.Eye.z = dot(Input.Normal, eye);还有这儿你的eye向量没有normalize。
{
//贴图颜色,环境光和漫反射光照亮这个颜色
float4 baseColor = tex2D(TextureMap, Input.TexCoord);
float3 light = normalize(Input.Light);
float3 eye = normalize(Input.Eye);
float3 normal = normalize(tex2D(NormalMap, Input.TexCoord).xyz * 2.0f - 1.0f);
objToTangentSpace[0]=T;
objToTangentSpace[1]=cross(T, N);
objToTangentSpace[2]=N;
newMat = objToTangentSpace * world;
这样?
总觉得怪怪的,这位大哥可以再说得仔细一些吗?我是新手,学习Shader都是自己打拼,没人带,基础有些差。谢谢你了。
{
float3 Position : POSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT0;
float3 Binormal : BINORMAL0;
float2 tOffset : TEXCOORD0;
};struct VS_OUTPUT
{
float4 Position : POSITION; // 最终位置(投影空间)
float2 tOffset : TEXCOORD0; // 纹理坐标 float3 f3WorldP : TEXCOORD1; // 位置 (世界空间)
float3 f3WorldN : TEXCOORD2; // 法线 (世界空间)
float3 f3WorldB : TEXCOORD3; // 副法线(世界空间)
float3 f3WorldT : TEXCOORD4; // 切线 (世界空间)
};
VS_OUTPUT VS_Entry( VS_INPUT In )
{
// 顶点经过世界变换,视角变换,投影变换
float4 f4Locate = mul( float4( In.Position, 1.0 ), m4World );
float4 f4Viewer = mul( f4Locate, m4View );
// 写入数据
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Position = mul( f4Viewer, m4Proj );
Out.tOffset = In.tOffset;
// 计算世界坐标空间的位置,法线,副法线,切线;
Out.f3WorldP = f4Locate;
Out.f3WorldN = normalize( mul( In.Normal, (float3x3)m4World ) );
Out.f3WorldB = normalize( mul( In.Binormal, (float3x3)m4World ) );
Out.f3WorldT = normalize( mul( In.Tangent, (float3x3)m4World ) ); // 返回;
return Out;
}
ps:float4 PS_Entry( VS_OUTPUT In ) : COLOR
{
// 计算视线(世界空间,未单位化);
float3 f3View = f4EyePosition.xyz - In.f3WorldP;
// 准备切线空间到世界空间的矩阵;
float3x3 f3x3TBN = float3x3(In.f3WorldT, In.f3WorldB, In.f3WorldN);
// 计算像素法线(切线空间);
float3 f3Normal = CalculateNormal(normalMap, In.tOffset);
// 计算像素法线(世界空间);通过TBN的逆矩阵将切线空间内的法线变换到世界空间;
f3Normal = normalize( mul( f3Normal, transpose(f3x3TBN) ) );
// 计算环境光;
float4 f4AmbColor = f4MaterialAmbient * f4AmbientLight;
// 计算光的反方向;
float3 lgtDir, eyeDir;
lgtDir = normalize( -f4DirLightWorldDirection.xyz );
// 计算漫反射强度;
float fDiffuseScale = saturate( dot(f3Normal, lgtDir) );
// 计算漫反射;
float4 f4DifColor = ( f4MaterialAmbient * f4DirLightAmbient + fDiffuseScale * f4MaterialDiffuse * f4DirLightDiffuse );
// 计算高光向量
eyeDir = normalize( f3View );
lgtDir = normalize( In.f3WorldP - f4DirLightWorldPosition.xyz );
float3 fReflect = normalize( reflect(lgtDir, f3Normal) );
// 计算高光的最终值
float4 f4SpcColor = f4DirLightSpecular * f4MaterialSpecular * ( pow( saturate( dot(fReflect, eyeDir) ), fSpecularPower ) ) * fDiffuseScale;
// 最终的光颜色
float4 f4Final = f4MaterialEmissive + f4AmbColor + f4DifColor + f4SpcColor;
// 计算最终的光照;
In.Color = f4Final * float4( co.rgb, 1.0f );
}以上代码是从项目中提取出来的,你要测试的话,需要自己该一些东西。这些代码就是最基本的per-pixel lighting的光源模型。
f3Normal = normalize( mul( f3Normal, transpose(f3x3TBN) ) );这里的TBN矩阵就是将切线空间法线变换到世界空间(T,B,N三个基都是处于世界空间),逆矩阵是将世界空间法线变换到切空间。。