Ogre引擎渲染系列之Normal Specular Mapping
比较流行的开发引擎无非就是Unity3D引擎和UE4虚幻4,但是作为开源的Ogre引擎还是被一部分玩家所喜欢,由于其开源的,而且是针对图形处理的。所以对于学习3D游戏开发者来说,学习Ogre的GPU渲染是一条捷径,各个引擎的渲染Shader编写其实是类似的,它们的区别是在细节方面,虚幻做的最好,其他就是Unity和Ogre了。下面把Ogre的处理方式给大家介绍一下:
高光,法线,环境映射对于Shader来说必须要掌握的,其中Ogre中的渲染需要几个文件一是cg文件还有material文件,先给读者展示cg文件,代码如下所示:copy
- struct VIn
- {
- float4 p : POSITION;
- float3 n : NORMAL;
- float3 t : TANGENT;
- float2 uv : TEXCOORD0;
- };
- struct VOut
- {
- float4 p : POSITION;
- float2 uv : TEXCOORD0;
- float4 wp : TEXCOORD1;
- float3 n : TEXCOORD2;
- float3 t : TEXCOORD3;
- float3 b : TEXCOORD4;
- float4 lp : TEXCOORD5;
- float3 sdir : TEXCOORD6;
- };
- struct PIn
- {
- float2 uv : TEXCOORD0;
- float4 wp : TEXCOORD1;
- float3 n : TEXCOORD2;
- float3 t : TEXCOORD3;
- float3 b : TEXCOORD4;
- float4 lp : TEXCOORD5;
- float3 sdir : TEXCOORD6;
- };
- void ambient_vs(VIn IN,
- uniform float4x4 wvpMat,
- out float4 oPos : POSITION,
- out float2 oUV : TEXCOORD0)
- {
- oPos = mul(wvpMat, IN.p);
- oUV = IN.uv;
- }
- float4 ambient_ps(in float2 uv : TEXCOORD0,
- uniform float3 ambient,
- uniform float4 matDif,
- uniform sampler2D dMap,
- uniform sampler2D aoMap): COLOR0
- {
- return tex2D(dMap, uv) * tex2D(aoMap, uv) *
- float4(ambient, 1) * float4(matDif.rgb, 1);
- }
- VOut diffuse_vs(VIn IN,
- uniform float4x4 wMat,
- uniform float4x4 wvpMat,
- uniform float4x4 tvpMat,
- uniform float4 spotlightDir)
- {
- VOut OUT;
- OUT.wp = mul(wMat, IN.p);
- OUT.p = mul(wvpMat, IN.p);
- OUT.uv = IN.uv;
- OUT.n = IN.n;
- OUT.t = IN.t;
- OUT.b = cross(IN.t, IN.n);
- OUT.sdir = mul(wMat, spotlightDir).xyz; // spotlight dir in world space
- OUT.lp = mul(tvpMat, OUT.wp);
- return OUT;
- }
- float4 diffuse_ps(
- PIn IN,
- uniform float3 lightDif0,
- uniform float4 lightPos0,
- uniform float4 lightAtt0,
- uniform float3 lightSpec0,
- uniform float4 matDif,
- uniform float4 matSpec,
- uniform float matShininess,
- uniform float3 camPos,
- uniform float4 invSMSize,
- uniform float4 spotlightParams,
- uniform float4x4 iTWMat,
- uniform sampler2D diffuseMap : TEXUNIT0,
- uniform sampler2D specMap : TEXUNIT1,
- uniform sampler2D normalMap : TEXUNIT2): COLOR0
- {
- // direction
- float3 ld0 = normalize(lightPos0.xyz - (lightPos0.w * IN.wp.xyz));
- half lightDist = length(lightPos0.xyz - IN.wp.xyz) / lightAtt0.r;
- // attenuation
- half ila = lightDist * lightDist; // quadratic falloff
- half la = 1.0 - ila;
- float4 normalTex = tex2D(normalMap, IN.uv);
- float3x3 tbn = float3x3(IN.t, IN.b, IN.n);
- float3 normal = mul(transpose(tbn), normalTex.xyz * 2 - 1); // to object space
- normal = normalize(mul((float3x3)iTWMat, normal));
- float3 diffuse = max(dot(ld0, normal), 0);
- // calculate the spotlight effect
- float spot = (spotlightParams.x == 1 &&
- spotlightParams.y == 0 &&
- spotlightParams.z == 0 &&
- spotlightParams.w == 1 ? 1 : // if so, then it's not a spot light
- saturate(
- (dot(ld0, normalize(-IN.sdir)) - spotlightParams.y) /
- (spotlightParams.x - spotlightParams.y)));
- float3 camDir = normalize(camPos - IN.wp.xyz);
- float3 halfVec = normalize(ld0 camDir);
- float3 specular = pow(max(dot(normal, halfVec), 0), matShininess);
- float4 diffuseTex = tex2D(diffuseMap, IN.uv);
- float4 specTex = tex2D(specMap, IN.uv);
- float3 diffuseContrib = (diffuse * lightDif0 * diffuseTex.rgb * matDif.rgb);
- float3 specularContrib = (specular * lightSpec0 * specTex.rgb * matSpec.rgb);
- float3 light0C = (diffuseContrib specularContrib) * la * spot;
- return float4(light0C, diffuseTex.a);
- }
其中VIn表示的是顶点输入的结构体,VOut表示的是顶点输出的结构体,PIn表示的是片段着色器的输入结构体,在下面的函数实现中首先实现的是ambient occlusion mapping也包括顶点和片段处理。最后是diffuse的顶点和片段处理也就是高光specluar和法线normal的处理,这样整个Shader就完成了。
下面实现的是material的编写,代码如下所示: copy
该文件实现了一个基材质 base_material其它材质可以继承,这个对于开发者来说非常灵活。另外还需要一个program程序文件用于shader和图片的配置,代码如下所示:
以上就完成了高光,法线以及ambient Shader的实现,当然学习Shader编程不能仅限于功能实现,还需要举一反三,比如我们上面封装的base_material。还是可以继续去扩展的,代码如下所示: copy
关于变动的代码都加了注释,对比源代码既可以看明白,到此结束。
- material base_material
- {
- set $diffuseCol "1 1 1 1"
- set $specularCol "1 1 1"
- set $shininess "32"
- technique
- {
- pass
- {
- illumination_stage ambient
- ambient 1 1 1 1
- diffuse $diffuseCol
- specular 0 0 0 0
- emissive 0 0 0 0
- vertex_program_ref ambient_vs
- {
- }
- fragment_program_ref ambient_ps
- {
- }
- texture_unit diffuseMap
- {
- texture white.png
- }
- texture_unit aoMap
- {
- texture white.png
- }
- }
- pass
- {
- illumination_stage per_light
- scene_blend add
- // iteration once_per_light not needed while illumination_stage per_light is used
- vertex_program_ref diffuse_vs
- {
- }
- fragment_program_ref diffuse_ps
- {
- }
- diffuse $diffuseCol
- specular $specularCol $shininess
- ambient 0 0 0 0
- texture_unit diffuseMap
- {
- texture white.png
- }
- texture_unit specMap
- {
- texture white.png
- }
- texture_unit normalMap
- {
- texture flat_n.png
- }
- }
- }
- }
- // examples (require the appropriate [[textures]], all found in the Ogre samples)
- material rockwall : base_material
- {
- set_texture_alias diffuseMap rockwall.tga
- set_texture_alias specMap rockwall.tga
- set_texture_alias normalMap rockwall_NH.tga
- }
- material metal : base_material
- {
- set_texture_alias diffuseMap RustedMetal.jpg
- set_texture_alias specMap RustedMetal.jpg
- }
- material ogre : base_material
- {
- set_texture_alias diffuseMap GreenSkin.jpg
- set_texture_alias specMap GreenSkin.jpg
- set_texture_alias normalMap NMHollyBumps.png
- }
- vertex_program diffuse_vs cg
- {
- source general.cg
- profiles vs_1_1 arbvp1
- entry_point diffuse_vs
- default_params
- {
- param_named_auto wMat world_matrix
- param_named_auto wvpMat worldviewproj_matrix
- param_named_auto tvpMat texture_viewproj_matrix 0
- param_named_auto spotlightDir light_direction_object_space 0
- }
- }
- vertex_program ambient_vs cg
- {
- source general.cg
- profiles vs_1_1 arbvp1
- entry_point ambient_vs
- default_params
- {
- param_named_auto wvpMat worldviewproj_matrix
- }
- }
- fragment_program ambient_ps cg
- {
- source general.cg
- profiles ps_2_0 arbfp1
- entry_point ambient_ps
- default_params
- {
- param_named_auto ambient ambient_light_colour
- param_named_auto matDif surface_diffuse_colour
- }
- }
- fragment_program diffuse_ps cg
- {
- source general.cg
- profiles ps_2_x arbfp1
- entry_point diffuse_ps
- default_params
- {
- param_named_auto lightDif0 light_diffuse_colour 0
- param_named_auto lightSpec0 light_specular_colour 0
- param_named_auto camPos camera_position
- param_named_auto matShininess surface_shininess
- param_named_auto matDif surface_diffuse_colour
- param_named_auto matSpec surface_specular_colour
- param_named_auto lightPos0 light_position 0
- param_named_auto lightAtt0 light_attenuation 0
- param_named_auto iTWMat inverse_transpose_world_matrix
- param_named_auto spotlightParams spotlight_params 0
- }
- }
以上就完成了高光,法线以及ambient Shader的实现,当然学习Shader编程不能仅限于功能实现,还需要举一反三,比如我们上面封装的base_material。还是可以继续去扩展的,代码如下所示: copy
- material some_material : base_material
- {
- // any of these maps can be left out if you don't have one
- set_texture_alias diffuseMap some_dif.png
- set_texture_alias specMap some_spec.png
- set_texture_alias normalMap some_norm.png
- set_texture_alias aoMap some_ao.png
- // diffuse colour multiplier (for example, green-ish)
- set $diffuseCol "0.1 1 0.1"
- // specular colour multiplier (for example, red-ish)
- set $specularCol "1 0.1 0.1"
- // specular power (shininess) (the higher, the sharper the highlights)
- set $shininess "128"
- // once again, you can leave any of these configurables out if you don't need them
- }
我们还可以在此Shader的基础上实现UV镜像处理,修改代码如下所示:
一、首先将VIn输入结构体修改如下所示:
- struct VIn
- {
- float4 p : POSITION;
- float3 n : NORMAL;
- float4 t : TANGENT; // <- this was changed
- float2 uv : TEXCOORD0;
- };
二、修改Vout输出结构体代码如下:
- struct VOut
- {
- float4 p : POSITION;
- float2 uv : TEXCOORD0;
- float4 wp : TEXCOORD1;
- float3 n : TEXCOORD2;
- float4 t : TEXCOORD3; //<- this was changed
- float3 b : TEXCOORD4;
- float4 lp : TEXCOORD5;
- float3 sdir : TEXCOORD6;
- };
三、修改diffuse_vs函数代码修改如下所示:
- VOut diffuse_vs(VIn IN,
- uniform float4x4 wMat,
- uniform float4x4 wvpMat,
- uniform float4x4 tvpMat,
- uniform float4 spotlightDir)
- {
- VOut OUT;
- OUT.wp = mul(wMat, IN.p);
- OUT.p = mul(wvpMat, IN.p);
- OUT.uv = IN.uv;
- OUT.n = IN.n;
- OUT.t = IN.t;
- OUT.b = cross(IN.t.xyz, IN.n) * IN.t.w; //<-this was changed
- OUT.sdir = mul(wMat, spotlightDir).xyz; // spotlight dir in world space
- OUT.lp = mul(tvpMat, OUT.wp);
- return OUT;
- }