I don't know the exact terminology, but here it is..
I pulled it from old Mental Mill stuff, changed it a bit and converted it for FX Composer in OpenGL Mode..
You'll make more sense of it than I could but it does work (in Composer at least).
I found that anything working in Composer worked in my old Win 32 OpenGL programs.
Code: Select all
// - RELIEF MAP -
// Values for the light_type parameter of light shaders
#define LIGHT_POINT 0
#define LIGHT_SPOT 1
#define LIGHT_INFINITE 2
#define LIGHT_PLANAR 3
// The light iterator structure holds the return values resulting from
// evaluating a light.
struct Light_iterator
{float3 _point;
float4 contribution;
float4 raw_contribution;
float DotNLightDiffuse;
float DotNLightSpecular;
float3 direction;
float distance;
float4 shadow;
int count;
};
struct Ray {
float3 origin;
float3 direction;
};
void CreateBasis(const float3 n, const float3 u, const float3 v,
out float3 t, out float3 b)
{
b = normalize(cross(u,n));
t = cross(n,b);
if(dot(b,v) < 0.0) b = -b;
}
// float3 DividePerspective(float4 pt) { return pt.xyz/pt.w; }
//
// The state structure is used internally within the fragment shader to
// commonly used values.
//
struct State
{
float4 tex_coord[4];
float3 position;
float3 normal;
float3 direction;
float3x3 tangent_space[1];
float3 light_position;
float3 light_to_surface;
float light_distance;
float light_dotnl;
};
//
// The following are free parameters of the shader that should be set by the
// application at runtime.
//
float4 __light0_Light_point_1_color
<
string UIName = "Light0 Color";
string UIWidget = "Color";
> = float4(1.000000, 1.000000, 1.000000, 1.000000);
float __light0_Light_point_1_intensity
<
string UIName = "Light0 Intensity";
float UIMin = 0.000000;
float UIMax = 10.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 1.000000;
float __light0_Light_point_1_distance_falloff_exponent
<
string UIName = "Light0 Distance Falloff Exponent";
float UIMin = 0.000000;
float UIMax = 4.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 1.000000;
float __light0_Light_point_1_distance_falloff_start
<
string UIName = "Light0 Distance Falloff Start";
float UIMin = 0.000000;
float UIMax = 10.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 0.000000;
float __light0_Light_point_1_distance_falloff_limit
<
string UIName = "Light0 Distance Falloff Limit";
float UIMin = 0.000000;
float UIMax = 1000.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 1000.000000;
//-----------------------------------------------------------------------------
float __light0_Light_point_1_distance_scale
<
string UIName = "Light0 Distance Scale";
float UIMin = 0.001000;
float UIMax = 100.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 1.000000;
//-----------------------------------------------------------------------------
float3 __light0_position : Position
<
string Object = "PointLight0";
string Space = "World";
string UIName = "Light0 Light_position";
> = float3(0.000000, 1.000000, 0.000000);
//-----------------------------------------------------------------------------
texture __Normals_relief_map_1_color_tex <
string UIName = "Normals_relief_map_1_color_tex";
string ResourceName = "CliffRock.dds";
string ResourceType = "2D";
>;
//-----------------------------------------------------------------------------
sampler2D Normals_relief_map_1_color_tex = sampler_state {
Texture = <__Normals_relief_map_1_color_tex>;
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
};
//-----------------------------------------------------------------------------
texture __Normals_relief_map_1_height_tex <
string UIName = "Normals_relief_map_1_height_tex";
string ResourceName = "relief_map_1_height.dds";
string ResourceType = "2D";
>;
//-----------------------------------------------------------------------------
sampler2D Normals_relief_map_1_height_tex = sampler_state {
Texture = <__Normals_relief_map_1_height_tex>;
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
};
//-----------------------------------------------------------------------------
texture __Normals_relief_map_1_norm_tex <
string UIName = "Normals_relief_map_1_norm_tex";
string ResourceName = "relief_map_1_normal.dds";
string ResourceType = "2D";
>;
sampler2D Normals_relief_map_1_norm_tex = sampler_state {
Texture = <__Normals_relief_map_1_norm_tex>;
MinFilter = LinearMipMapLinear;
MagFilter = Linear;
};
//-----------------------------------------------------------------------------
float DiffuseMultiplier
<
string UIName = "DIFFUSE_MULTIPLIER";
float UIMin = 0.000000;
float UIMax = 2.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 1.0;
//-----------------------------------------------------------------------------
float Normals_relief_map_1_amount
<
string UIName = "Amount";
float UIMin = 0.000000;
float UIMax = 0.500000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 0.050000;
//-----------------------------------------------------------------------------
float4 SpecularColour
<
string UIName = "Specular Color";
float4 UIMin = float4(0.000000, 0.000000, 0.000000, 0.000000);
float4 UIMax = float4(1.000000, 1.000000, 1.000000, 1.000000);
float UIStep = 0.01;
string UIWidget = "color";
> = float4(1.000000, 1.000000, 1.000000, 1.000000);
//-----------------------------------------------------------------------------
float SpecularGloss
<
string UIName = "Specular Shininess";
float UIMin = 0.000000;
float UIMax = 300.000000;
float UIStep = 0.01;
string UIWidget = "slider";
> = 100.000000;
//-----------------------------------------------------------------------------
int Normals_relief_map_1_steps
<string UIName = "Steps";
int UIMin = 1;
int UIMax = 80;
float UIStep = 0.01;
string UIWidget = "slider";
> = 10;
//-----------------------------------------------------------------------------
// The following are parameters representing non-varying state variables
// referenced by the shader. These should be set by the application at runtime.
// Note that vector parameters should be provided in camera space.
float4x4 __object_to_ndc : WorldViewProjection <string UIWidget = "none";>;
float4x4 __world_to_object : WorldInverse <string UIWidget = "none";>;
float4x4 __object_to_world : World <string UIWidget = "none";>;
float4x4 __camera_to_world : ViewInverse <string UIWidget = "none";>;
#ifndef PhongShade__Vector2__Scalar__Scalar__Scalar
#define PhongShade__Vector2__Scalar__Scalar__Scalar 1
float2 PhongShade(float n_dot_l, float n_dot_h, float e)
{float2 res;
res.x = (saturate(n_dot_l));
// res.y = (((n_dot_l < 0) || (n_dot_h < 0)) ? 0 : (pow(n_dot_h, e))); // WRONG!! (As in example)
res.y = (((n_dot_l < 0) || (n_dot_h < 0)) ? 0 : (pow(n_dot_l, e))); // RIGHT!!
// AHA!! THIS WAS THE PROBLEM IN COMPOSER
// (WHY DOES EXAMPLE GIVE US THIS?)
return res;
}
#endif
//
// The App2vert structure defines the vertex attributes used by the vertex
// shader. The application should supply a vertex stream containing these
// elements.
//
struct App2vert
{
float3 position : POSITION;
float3 normal : NORMAL;
float4 texcoord0 : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
float3 tex_du : TANGENT;
float3 tex_dv : BINORMAL;
};
//
// The Vert2frag structure defines values used by the fragment shader and
// supplied by the vertex shader.
//
struct Vert2frag
{
float4 hpos : POSITION;
float4 tex_coord[4] : TEXCOORD0;
float3 tex_du : TEXCOORD4;
float3 tex_dv : TEXCOORD5;
float3 position : TEXCOORD6;
float3 normal : TEXCOORD7;
};
//
// This function is the main method of the vertex shader.
//
Vert2frag VertexProgram(
App2vert vs_in)
{
Vert2frag vs_out;
float4 position = float4(vs_in.position, 1);
vs_out.hpos = mul(__object_to_ndc, position);
vs_out.position = mul(__object_to_world, position).xyz;
vs_out.normal = mul(vs_in.normal, (float3x3)__world_to_object);
vs_out.tex_coord[0] = vs_in.texcoord0;
vs_out.tex_coord[1] = vs_in.texcoord1;
vs_out.tex_coord[2] = vs_in.texcoord2;
vs_out.tex_coord[3] = vs_in.texcoord3;
vs_out.tex_du = mul(vs_in.tex_du, (float3x3)__world_to_object);
vs_out.tex_dv = mul(vs_in.tex_dv, (float3x3)__world_to_object);
return vs_out;
}
//
// The following functions are generated from the MetaSL implementation of
// the shaders that are part of the compiled shader graph.
//
void Light_point_main(
float4 color,
float intensity,
float distance_falloff_exponent,
float distance_falloff_start,
float distance_falloff_limit,
float distance_scale,
State state,
out float4 result,
out float4 light_shadow)
{
{
float d = saturate((((state.light_distance) / (distance_scale - distance_falloff_start)) / (distance_falloff_limit - distance_falloff_start)));
float f = 1.0 / (1.0 + (pow(d, distance_falloff_exponent)));
result = ((color * intensity) * f);
light_shadow = (float4(1,1,1,1));
result *= 3.14159265358979323846f;
}
}
void LightCalculation(
float4 Light_point_1_color,
float Light_point_1_intensity,
float Light_point_1_distance_falloff_exponent,
float Light_point_1_distance_falloff_start,
float Light_point_1_distance_falloff_limit,
float Light_point_1_distance_scale,
float3 __light_position,
State state,
out Light_iterator __light)
{
{
float4 light_shadow = float4(0.000000, 0.000000, 0.000000, 0.000000);
float4 result = float4(0.000000, 0.000000, 0.000000, 0.000000);
__light.direction = (__light_position - (state.position));
__light.distance = (length(__light.direction));
__light.direction /= __light.distance;
__light.DotNLightDiffuse = (dot(__light.direction, (state.normal)));
__light.contribution = 0.0;
__light.raw_contribution = 0.0;
__light.count = 0.0;
__light.shadow = 0.0;
__light._point = 0.0;
(state.light_to_surface) = (-__light.direction);
(state.light_distance) = __light.distance;
(state.light_dotnl) = __light.DotNLightDiffuse;
(state.light_position) = __light_position;
Light_point_main(Light_point_1_color, Light_point_1_intensity, Light_point_1_distance_falloff_exponent, Light_point_1_distance_falloff_start, Light_point_1_distance_falloff_limit, Light_point_1_distance_scale, (state), result, light_shadow);
__light._point = __light_position;
__light.shadow = light_shadow;
__light.count = 0;
__light.raw_contribution = result;
__light.contribution = (result * light_shadow);
}
}
void ProcessRelief(
sampler2D color_tex,
sampler2D height_tex,
sampler2D norm_tex,
float amount,
float4 specular_color,
float specular_shininess,
int steps,
int texture_space,
State state,
out float4 result)
{
{
float3 vtan = mul((state.tangent_space)[0], (state.direction));
float step_size = 1.0 / steps;
float2 dt = ((-vtan.xy) * amount) / (steps * vtan.z);
float height = 1.0;
float2 t = (state.tex_coord)[texture_space].xy;
float h = (tex2D(height_tex, t)).x;
while (h < height)
{
height -= step_size;
t += dt;
h = (tex2D(height_tex, t)).x;
}
for (int i = 0; i < 8; i++)
{
if (h < height)
{
t += dt;
height -= step_size;
}
else
{
t -= dt;
height += step_size;
}
step_size *= 0.5;
dt *= 0.5;
h = (tex2D(height_tex, t)).y;
}
float3 n = ((tex2D(norm_tex, t)).xyz - 0.5) * 2.0;
(state.normal) = (normalize(n));
float4 color = tex2D(color_tex, t);
float4 diffuse = float4(0, 0, 0, 0);
float4 specular = float4(0, 0, 0, 0);
step_size = (1.0 / steps);
Light_iterator light;
{
{
LightCalculation(__light0_Light_point_1_color, __light0_Light_point_1_intensity, __light0_Light_point_1_distance_falloff_exponent, __light0_Light_point_1_distance_falloff_start, __light0_Light_point_1_distance_falloff_limit, __light0_Light_point_1_distance_scale, __light0_position, (state), light);
float3 TanByLightDir = mul((state.tangent_space)[0], light.direction);
float2 ti = t;
// float3 OrigNorm = state.normal;
// float TX = state.normal.x;
// float TY = state.normal.y;
// float TZ = state.normal.z;
// state.normal.y = TX;
float DotNLightDiffuse = dot(TanByLightDir, (state.normal));
float3 TempStateNrml;
//TempStateNrml.x = state.normal.x;
//TempStateNrml.y = state.normal.y;
//TempStateNrml.z = state.normal.z;
//float3 TanByLightDirTEMP ;
//TanByLightDirTEMP.x = TanByLightDir.x;
//TanByLightDirTEMP.y = TanByLightDir.y;
//TanByLightDirTEMP.z = TanByLightDir.z;
float DotNLightSpecular = dot(TanByLightDir, (state.normal));
// state.normal = OrigNorm;
if (DotNLightDiffuse > 0.0)
{ dt = ((TanByLightDir.xy * amount) / (steps * TanByLightDir.z));
h = (tex2D(height_tex, ti)).x;
height = (h + step_size);
ti += dt;
while ((h < height) && (height < 1))
{
height += step_size;
ti += dt;
h = (tex2D(height_tex, ti)).x;
}
if (h < height)
{
float3 vhalf = normalize((TanByLightDir - (state.direction)));
float2 illum = PhongShade(DotNLightDiffuse, (dot((state.normal), vhalf)), specular_shininess);
diffuse += (((illum.x * DotNLightDiffuse) * light.contribution) / 3.14159265358979323846f);
// ======
diffuse.xyz *= DiffuseMultiplier;
specular += ((((illum.y * DotNLightSpecular) * specular_color) * light.contribution) / 3.14159265358979323846f);
}
}
}
}
result = ((color * diffuse) + specular);
}
}
//
// The following method is the root function of the shader graph
//
float4 Evaluate(State state)
{float4 result;
ProcessRelief(Normals_relief_map_1_color_tex,
Normals_relief_map_1_height_tex,
Normals_relief_map_1_norm_tex,
Normals_relief_map_1_amount,
SpecularColour,
SpecularGloss,
Normals_relief_map_1_steps, 0, (state), result);
return result;
}
//
// This function is the main method of the fragment shader. It initializes the
// values in the state structure that are used by nodes in the shader graph
// and produces the final result of the shader.
//
float4 FragmentShader(
Vert2frag fs_in) : COLOR
{
State state;
state.position = fs_in.position;
state.normal = normalize(fs_in.normal);
state.tex_coord = fs_in.tex_coord;
float3 eye_to_pos = state.position - float3(__camera_to_world[0][3], __camera_to_world[1][3], __camera_to_world[2][3]);
state.direction = normalize(eye_to_pos);
float3 t_tex_tangent, t_tex_binormal;
CreateBasis(state.normal, fs_in.tex_du, fs_in.tex_dv, t_tex_tangent, t_tex_binormal);
state.tangent_space[0] = float3x3(
t_tex_tangent,
t_tex_binormal,
state.normal);
state.light_position = 0;
state.light_to_surface = 0;
state.light_distance = 0;
state.light_dotnl = 0;
return Evaluate(state);
}
// The following define the default technique and pass of the effect.
technique T0
{
pass P0
{
DepthTestEnable = true;
DepthMask = true;
CullFaceEnable = false;
VertexShader = compile vp40 VertexProgram();
PixelShader = compile fp40 FragmentShader();
}
}