Custom Entities

Topics: Developer Forum, User Forum
Sep 18, 2007 at 11:58 AM
hr0nix,

This is a wonderfully designed library. Thank you so much for your (team's?) contribution to the community. I've been using Lutz Roeder's reflector to try and get a better feel for how the library works, and my first question is in relation to entities.

For our purposes, the supplied Billboard and Model entities are not sufficient to provide all of the graphical elements we are working to create in our game. Naturally, then, we wanted to create a custom entity that suited our needs. This seems straight-forward enough; I noticed that most of the actual geometry would be provided via the GetBatches method and either an indexed or non-indexed batch. However, I am having trouble figuring out how the effect is used. Some further investigation revealed that the RenderPass defines which techniques are expected, but it is difficult for me to see how this gets selected and used.

So my question is: in general, how should effect files be structured to get the most out of the library, particularly concerning the shadow pass? What techniques are expected, and what types of output should they provide?

Thanks again, and I am looking forward to further releases!

-Mark
Coordinator
Sep 20, 2007 at 1:38 PM
Thanks for your feedback.

If you want your batch to be rendered in some render pass, you should add a technique to your FX file which name equals to RenderPass.TechniqueName. Then your batch will be drawn during that render pass.

In the next release rendering pipeline will change a bit, and new amasing postprocessing technique will be introduced instead of existing one.
Sep 20, 2007 at 5:49 PM
Thanks for the reply!

I did notice that the TechniqueName defines the render pass I need to put in my FX file. What I wasn't sure about was exactly how the FX file itself should work. For example, if I have a shadow technique, what are the inputs provided to the FX file for each vertex? What is the aim for output from the pixel shader? I'm assuming it wouldn't be simply the diffuse output I might calculate during a more "normal" pass. I'm not even sure what general algorithm your shadow pass expects us to use.

Hope that helps to clarify my question.

-Mark
Coordinator
Sep 21, 2007 at 5:57 AM
Edited Sep 21, 2007 at 6:01 AM
Note that inputs for each vertex are always the same because of the same geometry being rendered. Uniform inputs (shader constants) for each pass are documented in pass algorithm provider's documentation.
Shader library provides default implementations for practically all the required techniques.

Here is the FX file from the demo, I hope it helps you (stupid codeplex engine formats it a bit, but you can find everything you need).

#include "../../../Engine/EngineContent/Shaders/CommonParameters.hlsl"
#include "../../../Engine/EngineContent/Shaders/CommonFunctions.hlsl"
#include "../../../Engine/EngineContent/Shaders/CommonVertexShaders.hlsl"
#include "../../../Engine/EngineContent/Shaders/CommonPixelShaders.hlsl"

#include "../../../Engine/EngineContent/Shaders/LightingParameters.hlsl"
#include "../../../Engine/EngineContent/Shaders/ShadowsParameters.hlsl"
#include "../../../Engine/EngineContent/Shaders/Parallax.hlsl"
#include "../../../Engine/EngineContent/Shaders/Lighting.hlsl"
#include "../../../Engine/EngineContent/Shaders/Shadows.hlsl"

#ifndef SHADOWKERNELSCALE
#define SHADOWKERNELSCALE 3.f
#endif

texture Texture;
sampler2D DiffuseSampler = sampler_state
{
Texture = ( Texture );

MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;

AddressU = Wrap;
AddressV = Wrap;
};

texture Bump0;
sampler2D NormalHeightSampler = sampler_state
{
Texture = ( Bump0 );

MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;

AddressU = Wrap;
AddressV = Wrap;
};

void LightingBase( in float2 texCoord, inout float3 toLight, inout float3 toViewer,
out float3 normal, out float4 diffuseColor, uniform bool UseShadows )
{
toLight = normalize( toLight );
toViewer = normalize( toViewer );

#ifdef PARALLAX_MAPPING
// Calculating parallax texcoord shift using predefined engine function
#ifdef PARALLAX_CHEAP
texCoord = CalculateParallaxTexCoordShift( NormalHeightSampler, texCoord, toViewer,
PARALLAXHEIGHTSCALE );
#else
float3 parallaxPos = FindHeightFieldIntersection( NormalHeightSampler, texCoord, toViewer,
PARALLAXHEIGHTSCALE, PARALLAXLSSTEPS, PARALLAXBSSTEPS );
texCoord = parallaxPos.xy;
#endif
#endif

normal = float3( 0.f, 0.f, 1.f );
#ifdef NORMAL_MAPPING
normal = normalize( 2.f * tex2D( NormalHeightSampler, texCoord ) - 1.f );
#endif

diffuseColor = tex2D( DiffuseSampler, texCoord );

#if defined(PARALLAXMAPPING) && defined(PARALLAXSELFSHADOWING) && !defined(PARALLAXCHEAP)
if ( UseShadows )
{
diffuseColor *= GetParallaxSelfShadowing( NormalHeightSampler, toLight, parallaxPos,
PARALLAXHEIGHTSCALE, PARALLAXLSSTEPS, PARALLAXBSSTEPS, 0.05f );
}
#endif
}

void SpotLight_PS(
in float2 inTexCoord : TEXCOORD0,
in float3 inToLightTS : TEXCOORD1,
in float3 inToViewerTS : TEXCOORD2,
in float3 inLightDirectionTS : TEXCOORD3,
in float4 inPositionLPS : TEXCOORD4,
in float3 inToLightWS : TEXCOORD5,

out float4 outColor : COLOR,

uniform bool UseShadows )
{
float3 toLight = inToLightTS;
float3 toViewer = inToViewerTS;
float3 normal;
float4 diffuseColor;

LightingBase( inTexCoord, toLight, toViewer, normal, diffuseColor, UseShadows );

float3 lightDirection = normalize( inLightDirectionTS );
float distToLight = length( inToLightWS );

// Calculating lighting amount using predefined engine function
float lightingAmount = CalculateSpotLightLightingAmount(
distToLight, toLight, toViewer, normal, lightDirection, SPECULARAMOUNT, SPECULARPOWER );

float shadowAmount = 1.f;
if ( UseShadows )
{
// Calculating shadow amount using predefined engine function
shadowAmount = Calculate2DShadowPCF3x3( inPositionLPS, SHADOWKERNELSCALE );
}

outColor = LightColor * diffuseColor * lightingAmount * shadowAmount;
}

void PointLight_PS(
in float2 inTexCoord : TEXCOORD0,
in float3 inToLightTS : TEXCOORD1,
in float3 inToViewerTS : TEXCOORD2,
in float3 inToLightWS : TEXCOORD3,

out float4 outColor : COLOR,

uniform bool UseShadows )
{
float3 toLight = inToLightTS;
float3 toViewer = inToViewerTS;
float3 normal;
float4 diffuseColor;

LightingBase( inTexCoord, toLight, toViewer, normal, diffuseColor, UseShadows );

float distToLight = length( inToLightWS );

// Calculating lighting amount using predefined engine function
float lightingAmount = CalculatePointLightLightingAmount(
distToLight, toLight, toViewer, normal, SPECULARAMOUNT, SPECULARPOWER );

float shadowAmount = 1.f;
if ( UseShadows )
{
// Calculating shadow amount using predefined engine function
shadowAmount = CalculateCubeShadow( inToLightWS );
}

outColor = LightColor * diffuseColor * lightingAmount * shadowAmount;
}

void DirectionalLight_PS(
in float2 inTexCoord : TEXCOORD0,
in float3 inToViewerTS : TEXCOORD1,
in float3 inToLightTS : TEXCOORD2,
in float4 inPositionLPS : TEXCOORD3,

out float4 outColor : COLOR,

uniform bool UseShadows )
{
float3 toLight = inToLightTS;
float3 toViewer = inToViewerTS;
float3 normal;
float4 diffuseColor;

LightingBase( inTexCoord, toLight, toViewer, normal, diffuseColor, UseShadows );

// Calculating lighting amount using predefined engine function
float lightingAmount = CalculateDirectionalLightLightingAmount(
toLight, toViewer, normal, SPECULARAMOUNT, SPECULARPOWER );

float shadowAmount = 1.f;
if ( UseShadows )
{
// Calculating shadow amount using predefined engine function
shadowAmount = Calculate2DShadowPCF2x2( inPositionLPS );
}

outColor = LightColor * diffuseColor * lightingAmount * shadowAmount;
}

technique GenerateDepth
{
pass SinglePass
{
VertexShader = compile vs11 Position_VS();
PixelShader = compile ps11 DoNotCare_PS();
}
}

technique ShadowSceneInfo
{
pass SinglePass
{
VertexShader = compile vs11 ShadowSceneInfoDefaultVS();
PixelShader = compile ps20 ShadowSceneInfoDefaultPS();
}
}

technique Ambient
{
pass SinglePass
{
#ifdef PARALLAX_MAPPING
VertexShader = compile vs11 PositionTex2DViewerTS_VS();
#ifdef PARALLAX_CHEAP
PixelShader = compile ps2b AmbientParallaxDefault_PS( DiffuseSampler, NormalHeightSampler,
PARALLAXHEIGHTSCALE );
#else
PixelShader = compile ps2b AmbientPOMDefault_PS( DiffuseSampler, NormalHeightSampler,
PARALLAXHEIGHTSCALE, PARALLAXLSSTEPS, PARALLAXBSSTEPS );
#endif
#else
VertexShader = compile vs11 PositionTex2D_VS();
PixelShader = compile ps20 AmbientDefaultPS( DiffuseSampler );
#endif
}
}

////////////////////////////////////////////////////////////////////////
//// Directional lights ////
////////////////////////////////////////////////////////////////////////

#if defined(PARALLAXMAPPING) && !defined(PARALLAXCHEAP)

technique DirectionalLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DDirectionalLight_VS();
PixelShader = compile ps2b DirectionalLight_PS( false );
}
}

technique DirectionalLight_Shadows
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DDirectionalLight_VS();
PixelShader = compile ps2b DirectionalLight_PS( true );
}
}

#else

technique DirectionalLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DDirectionalLight_VS();
PixelShader = compile ps20 DirectionalLight_PS( false );
}
}

technique DirectionalLight_Shadows
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DDirectionalLight_VS();
PixelShader = compile ps20 DirectionalLight_PS( true );
}
}

#endif

////////////////////////////////////////////////////////////////////////
//// Point lights ////
////////////////////////////////////////////////////////////////////////

#if defined(PARALLAXMAPPING) && !defined(PARALLAXCHEAP)

technique PointLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DPointLight_VS();
PixelShader = compile ps2b PointLight_PS( false );
}
}

technique PointLight_Shadows
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DPointLight_VS();
PixelShader = compile ps2b PointLight_PS( true );
}
}

#else

technique PointLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DPointLight_VS();
PixelShader = compile ps20 PointLight_PS( false );
}
}

technique PointLight_Shadows
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DPointLight_VS();
PixelShader = compile ps20 PointLight_PS( true );
}
}

#endif

technique PointLight_PrePass
{
pass SinglePass
{
VertexShader = compile vs11 PointOrSpotLightPrePassDefault_VS();
PixelShader = compile ps20 PointLightPrePassDefault_PS();
}
}

////////////////////////////////////////////////////////////////////////
//// Spot lights ////
////////////////////////////////////////////////////////////////////////

#if defined(PARALLAXMAPPING) && !defined(PARALLAXCHEAP)

technique SpotLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DSpotLight_VS();
PixelShader = compile ps2b SpotLight_PS( false );
}
}

#else

technique SpotLight
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DSpotLight_VS();
PixelShader = compile ps20 SpotLight_PS( false );
}
}

#endif

technique SpotLight_Shadows
{
pass SinglePass
{
VertexShader = compile vs11 PositionTex2DSpotLight_VS();
PixelShader = compile ps2b SpotLight_PS( true );
}
}

technique SpotLight_PrePass
{
pass SinglePass
{
VertexShader = compile vs11 PointOrSpotLightPrePassDefault_VS();
PixelShader = compile ps20 SpotLightPrePassDefault_PS();
}
}
Sep 21, 2007 at 11:36 AM
Thanks, hr0nix! That's exactly what I was looking for.

-Mark