void CalculateEmissiveContribution(inout SurfaceProperties surfaceInfo)
{
#if EMISSIVE || EMISSIVE_ADDITIVE
surfaceInfo.surface_emissiveIntensity = emissiveMultiplier *
surfaceInfo.surface_diffuseColor.a *
gEmissiveScale;
#if EMISSIVE_NIGHTONLY
surfaceInfo.surface_emissiveIntensity *= gDayNightEffects;
#endif
#else
surfaceInfo.surface_emissiveIntensity = 0.0;
#endif
}
// ----------------------------------------------------------------------------------------------- //
#define MIN_NUM_OF_PXM_STEPS 8
#define MAX_NUM_OF_PXM_STEPS 30
SurfaceProperties GetSurfaceProperties( float4 IN_baseColor,
#if PALETTE_TINT
float4 IN_baseColorTint,
#endif
#if DIFFUSE_TEXTURE
float2 IN_diffuseTexCoord,
sampler2D IN_diffuseSampler,
#endif
#if DIFFUSE2 || DIFFUSE3 || OVERLAY_DIFFUSE2
float2 IN_diffuseTexCoord2,
sampler2D IN_diffuseSampler2,
#endif
#if OVERLAY_DIFFUSE2 && OVERLAY_DIFFUSE2_SEPARATE_ALPHA_SOURCE
float IN_diffuse2Alpha,
#endif
#if SPEC_MAP
float2 IN_specularTexCoord,
sampler2D IN_specularSampler,
#endif // SPEC_MAP
#if REFLECT
float3 IN_worldEyePos,
REFLECT_SAMPLER IN_environmentSampler,
#if REFLECT_MIRROR
float2 IN_mirrorTexCoord,
float4 IN_screenPos,
#endif // REFLECT_MIRROR
#endif // REFLECT
#if NORMAL_MAP
float2 IN_bumpTexCoord,
sampler2D IN_bumpSampler,
float3 IN_worldTangent,
float3 IN_worldBinormal,
#if PARALLAX || PARALLAX_MAP_V2
#if PARALLAX
float3 IN_tanEyePos,
#endif
#if PARALLAX_MAP_V2
float3 IN_worldEyePosPOM,
sampler2D IN_heightSampler,
#if EDGE_WEIGHT
float2 IN_edgeWeight,
#endif // EDGE_WEIGHT
#endif // PARALLAX_MAP_V2
#endif // PARALLAX || PARALLAX_MAP_V2
#endif // NORMAL_MAP
#if NORMAL_MAP2
float2 IN_bumpTexCoord2,
sampler2D IN_bumpSampler2,
float3 IN_worldTangent2,
float3 IN_worldBinormal2,
#endif // NORMAL_MAP2
#if DIRT_NORMALMAP
float3 IN_dirtBumpUV, // xy = UV, z = dirtLevel
sampler2D IN_dirtBumpSampler,
#endif//DIRT_NORMALMAP...
#if DETAIL_UV
float2 IN_detailUV,
#endif //DETAIL_UV...
float3 IN_worldNormal
)
{
SurfaceProperties OUT = (SurfaceProperties)0;
OUT.surface_baseColor = IN_baseColor;
#if PALETTE_TINT
OUT.surface_baseColorTint = IN_baseColorTint;
#endif
#if DIFFUSE2 || DIFFUSE3 || OVERLAY_DIFFUSE2
OUT.surface_overlayColor = tex2D(IN_diffuseSampler2, IN_diffuseTexCoord2);
#if OVERLAY_DIFFUSE2_SEPARATE_ALPHA_SOURCE
OUT.surface_overlayColor.a = IN_diffuse2Alpha;
#endif // OVERLAY_DIFFUSE2_SEPARATE_ALPHA_SOURCE
#endif // DIFFUSE2
#if PARALLAX
float2 outTexCoord;
float3 parallaxPackedNormalHeight = CalculateParallax(
IN_tanEyePos,
tex2D_NormalHeightMap(IN_bumpSampler, IN_bumpTexCoord.xy),
IN_diffuseTexCoord,
IN_bumpTexCoord,
IN_bumpSampler,
outTexCoord).xyz;
IN_diffuseTexCoord = outTexCoord;
#endif // NORMAL_MAP
#if PARALLAX_MAP_V2 && __SHADERMODEL >= 40
#if EDGE_WEIGHT
float edgeWeight = 1.0f - clamp(IN_edgeWeight.x, 0.0f, 1.0f);
float zLimit = clamp(1.0f - IN_edgeWeight.y, 0.1f, 1.0f);
#else
float edgeWeight = 1.0f;
float zLimit = 0.1f;
#endif
if(POMDisable == 0)
{
float3 tanEyePos;
tanEyePos.x = dot(IN_worldTangent.xyz, IN_worldEyePosPOM.xyz);
tanEyePos.y = dot(IN_worldBinormal.xyz, IN_worldEyePosPOM.xyz);
tanEyePos.z = dot(IN_worldNormal.xyz, IN_worldEyePosPOM.xyz);
tanEyePos = normalize(tanEyePos);
float clampedZ = max(zLimit, tanEyePos.z);
float VdotN = abs(dot(normalize(IN_worldEyePosPOM.xyz), normalize(IN_worldNormal.xyz)));
float numberOfSteps = lerp(POMMaxSteps, POMMinSteps, VdotN);
float globalScale = globalHeightScale * edgeWeight * saturate(numberOfSteps - 1.0f) * saturate(VdotN / POMVDotNBlendFactor);
float2 maxParallaxOffset = (-tanEyePos.xy / clampedZ) * heightScale * globalScale;
float2 heightBiasOffset = (tanEyePos.xy / clampedZ) * heightBias * globalScale;
float height = TraceHeight(IN_heightSampler, IN_diffuseTexCoord, maxParallaxOffset, heightBiasOffset, numberOfSteps).r;
float2 textCoordOffset = heightBiasOffset + (maxParallaxOffset * (1.0f - height));
IN_diffuseTexCoord += textCoordOffset;
IN_bumpTexCoord += textCoordOffset;
#if SPEC_MAP
IN_specularTexCoord += textCoordOffset;
#endif // SPEC_MAP
}
#endif // PARALLAX_MAP_V2 && __SHADERMODEL >= 40
#if DIFFUSE_TEXTURE
float4 diffuseColor = tex2D(IN_diffuseSampler, IN_diffuseTexCoord);
#else
float4 diffuseColor = float4(1.0, 1.0, 1.0, 1.0);
#endif
OUT.surface_diffuseColor = calculateDiffuseColor(diffuseColor);
#ifdef USE_DETAIL_MAP
float detailInten=1.f;
#if DETAIL_USE_SPEC_ALPHA_AS_CONTROL && SPECULAR && SPEC_MAP
detailInten = tex2D(IN_specularSampler, IN_specularTexCoord.xy).w;
#endif
#if DETAIL_UV
float2 detailUV = IN_detailUV.xy;
#elif DIRT_NORMALMAP
float2 detailUV = IN_dirtBumpUV.xy;
#else
float2 detailUV = IN_diffuseTexCoord.xy;
#endif
float3 detailBumpAndIntensity = GetDetailBumpAndIntensity( detailUV, detailInten);
OUT.surface_diffuseColor *= detailBumpAndIntensity.z;
#endif
#if WRINKLE_MAP
OUT.surface_worldNormal.xyz = CalculateWrinkleNormal(
IN_bumpSampler,
IN_bumpTexCoord.xy,
IN_worldTangent,
IN_worldBinormal,
IN_worldNormal);
#else
#if NORMAL_MAP
#if PARALLAX
float3 packedNormal = float3(0.0, 0.0, 0.0);
#else
float3 packedNormal = tex2D_NormalMap(IN_bumpSampler, IN_bumpTexCoord.xy).xyz;
#endif
float3 packedNormalHeight = CalculatePackedNormal(
packedNormal,
#if PARALLAX
parallaxPackedNormalHeight,
#endif
#if DIRT_NORMALMAP
IN_dirtBumpSampler,
IN_dirtBumpUV.xyz,
#endif
IN_bumpTexCoord.xy);
#ifdef USE_DETAIL_MAP
packedNormalHeight.xy += detailBumpAndIntensity.xy;
#endif
OUT.surface_worldNormal.xyz = CalculateWorldNormal(
packedNormalHeight.xy,
bumpiness,
IN_worldTangent,
IN_worldBinormal,
IN_worldNormal);
#else
//should be normalized as the normal is interpolated from vertex normals
OUT.surface_worldNormal.xyz = normalize(IN_worldNormal.xyz);
#endif
#endif
#ifdef DECAL_USE_NORMAL_MAP_ALPHA
OUT.surface_worldNormal.a = packedNormalHeight.z;
#endif
#if NORMAL_MAP2
float3 packedNormalHeight2 = tex2D_NormalMap(IN_bumpSampler2, IN_bumpTexCoord2.xy).xyz;
OUT.surface_worldNormal2.xyz = CalculateWorldNormal(packedNormalHeight2.xy, bumpiness, IN_worldTangent2, IN_worldBinormal2, IN_worldNormal);
#endif
#if SPECULAR
CalculateSpecularContribution(
OUT,
#if SPEC_MAP
IN_specularSampler,
IN_specularTexCoord.xy,
#endif
IN_baseColor,
OUT.surface_worldNormal);
#ifdef USE_DETAIL_MAP
OUT.surface_specularIntensity *=detailBumpAndIntensity.z;
#endif
#endif
#if REFLECT
float3 surfaceToEyeDir = normalize(IN_worldEyePos);
CalculateReflection(
OUT,
IN_environmentSampler,
#if REFLECT_MIRROR
IN_screenPos,
#endif
#if defined(USE_MIRROR_CRACK_MAP)
IN_mirrorTexCoord,
#endif
#if SPECULAR
OUT.surface_specularExponent,
#endif
surfaceToEyeDir,
OUT.surface_worldNormal);
#endif
#if PARALLAX
// parallax only: if BumpMap.xy is (0,0), then we want no lighting:
const float threshold = 0.002f; // 0.00001f
float parallaxLightMask = (dot(packedNormalHeight.xy, packedNormalHeight.xy) >= threshold);
OUT.surface_diffuseColor.rgb *= parallaxLightMask;
OUT.surface_baseColor.rgb *= parallaxLightMask;
OUT.surface_specularIntensity *= parallaxLightMask;
#endif //PARALLAX...
#ifdef COLORIZE
OUT.surface_diffuseColor.rgba*=colorize;
#endif
#if SELF_SHADOW
OUT.surface_selfShadow = 1.0f;
#endif
#if PARALLAX_MAP_V2 && __SHADERMODEL >= 40
float3 tanLightDirection;
tanLightDirection.x = dot(IN_worldTangent.xyz, gDirectionalLight.xyz);
tanLightDirection.y = dot(IN_worldBinormal.xyz, gDirectionalLight.xyz);
tanLightDirection.z = dot(IN_worldNormal.xyz, gDirectionalLight.xyz);
float shadowAmount = TraceSelfShadow(IN_diffuseTexCoord, IN_heightSampler, tanLightDirection, 1.0f - IN_edgeWeight, heightScale * globalHeightScale);
OUT.surface_selfShadow = (1.0f - shadowAmount * parallaxSelfShadowAmount);
#if EDGE_WEIGHT
if(POMEdgeVisualiser)
{
OUT.surface_diffuseColor.r = clamp(IN_edgeWeight.x, 0.0f, 1.0f);
OUT.surface_diffuseColor.g = 1.0f - clamp(IN_edgeWeight.y, 0.0f, 1.0f);
OUT.surface_diffuseColor.b = 0.0f;
}
#endif
#endif
#if USE_SLOPE
OUT.slope = CalcSlope(IN_worldNormal.z);
#endif
CalculateEmissiveContribution(OUT);
return OUT;
}