Woops sorry, I've gotten so deep into this thing I'm just assuming the whole world knows what I mean by [font=courier new,courier,monospace]p_omega_out[/font]
. I appreciate the help and even general advice is very useful. Here is another screen from the paper which should be looked at with the image from the first post.
When I say [font=courier new,courier,monospace]p_omega_out[/font], I mean the vector from the pixel P to the viewer.
Here is the fx composer file I have at the moment, it's rather large and based off of the algorithms in the paper which you would probably need to read in full to make sense of so I won't ask you to do that! I am applying
this map as the subsurface texture map.
[source lang="java"]/*****************************************************************/
/*** HOST APPLICATION IDENTIFIERS ********************************/
/*** Potentially predefined by varying host environments *********/
/*****************************************************************/
// #define _XSI_ /* predefined when running in XSI */
// #define TORQUE /* predefined in TGEA 1.7 and up */
// #define _3DSMAX_ /* predefined in 3DS Max */
#ifdef _3DSMAX_
int ParamID = 0x0003; /* Used by Max to select the correct parser */
#endif /* _3DSMAX_ */
#ifdef _XSI_
#define Main Static /* Technique name used for export to XNA */
#endif /* _XSI_ */
#ifndef FXCOMPOSER_VERSION /* for very old versions */
#define FXCOMPOSER_VERSION 180
#endif /* FXCOMPOSER_VERSION */
#ifndef DIRECT3D_VERSION
#define DIRECT3D_VERSION 0x900
#endif /* DIRECT3D_VERSION */
#define FLIP_TEXTURE_Y /* Different in OpenGL & DirectX */
/*****************************************************************/
/*** EFFECT-SPECIFIC CODE BEGINS HERE ****************************/
/*****************************************************************/
/******* Lighting Macros *******/
/** To use "Object-Space" lighting definitions, change these two macros: **/
#define LIGHT_COORDS "World"
// #define OBJECT_SPACE_LIGHTS /* Define if LIGHT_COORDS is "Object" */
/**** UNTWEAKABLES: Hidden & Automatically-Tracked Parameters **********/
// transform object vertices to world-space:
float4x4 gWorldXf : World < string UIWidget="None"; >;
// transform object vertices to view space and project them in perspective:
float4x4 gWvpXf : WorldViewProjection < string UIWidget="None"; >;
// Ambient Light
float4 ambient : AMBIENT <
string UIName = "Ambient Light Color";
string UIWidget = "Color";
> = {0.7f,0.7f,0.7f,1.0f};
// surface color
float4 diffuse : DIFFUSE <
string UIName = "Diffuse Color";
string UIWidget = "Color";
> = {0.9f,0.9f,0.9f,1.0f};
float4 specular <
string UIName = "Specular Color";
string UIWidget = "color";
> = {0.75,0.75,0.75,1};
float specularPower <
string UIName = "Phong Exponent";
string UIWidget = "slider";
float UIMin = 1.0f;
float UIStep = 4;
float UIMax = 256.0f;
> = 8.0;
/*********** TEXTURES ***************/
texture gColorTexture : DIFFUSE <
string ResourceName = "grey.jpg";
string UIName = "Color Texture";
string ResourceType = "2D";
>;
sampler2D cm = sampler_state {
Texture = <gColorTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Wrap;
AddressV = Wrap;
};
texture gReliefTexture <
string ResourceName = "SSTM.png";
string UIName = "SSTM";
string ResourceType = "2D";
>;
sampler2D sstm = sampler_state {
Texture = <gReliefTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Wrap;
AddressV = Wrap;
};
texture gNormalTexture : NORMAL <
string ResourceName = "grey.jpg";
string UIName = "Normal Texture";
string ResourceType = "2D";
>;
sampler2D nm = sampler_state {
Texture = <gNormalTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Wrap;
AddressV = Wrap;
};
texture gMatrixTex <
string ResourceName = "grey.jpg";
string UIName = "Matrix Texture";
string ResourceType = "1D";
>;
sampler1D matrix_tex = sampler_state {
Texture = <gMatrixTex>;
};
float3x3 matTangent;
float3 worldEyePos : CAMERAPOSITION;
static const float AmbientIntensity = 1.0f; // The intensity of the ambient light.
static const float DiffuseIntensity = 1.0f; // The intensity of the diffuse light.
static const float SpecularIntensity = 1.0f; // The intensity of the specular light.
/********** CONNECTOR STRUCTURES *****************/
struct a2v //Application to a vertex
{
float4 pos : POSITION0;
float3 normal : NORMAL;
float4 tangent : TANGENT0;
float4 binormal : BINORMAL0;
float2 texcoord : TEXCOORD0;
float3 NSp : TEXCOORD1;
};
struct v2f //Vertex to a fragment (vertex output)
{
float4 hpos : POSITION0; //For rasterizer (not available in fragment shader, but must be written to)
float2 texcoord : TEXCOORD0;
float3 oNSp : TEXCOORD1;
float4 tangent : TEXCOORD2;
float3 eye : TEXCOORD3;
float3 worldLightDir : TEXCOORD4;
float4 binormal : TEXCOORD5;
float3 normal : TEXCOORD6;
float3 oPosition : TEXCOORD7;
float3 tangentSpaceEye : TEXCOORD8;
float3 tangentSpaceLightDir : TEXCOORD9;
};
struct outPixel
{
float4 colour : COLOR0;
};
/*** SHADER FUNCTIONS **********************************************/
v2f view_spaceVS(a2v IN,
uniform float4x4 WorldXf,
uniform float4x4 WvpXf
) {
// invert matrixes for FX Composer
WvpXf = transpose(WvpXf);
WorldXf = transpose(WorldXf);
v2f OUT = (v2f)0;
// vertex position in homogeneous clip space
OUT.hpos=mul(WvpXf, IN.pos);
OUT.texcoord = IN.texcoord;
// View vector in world space
float3 worldPos = mul(WorldXf, IN.pos).xyz;
OUT.eye = normalize(worldEyePos - worldPos); //Vertex to the eye (as opposed to incident eye->vert)
// Directional light so just normalize once
OUT.worldLightDir = normalize(float3(0, -1, 0));
// Planar approximation in world space
float4 N = float4(0, 1, 0, 0);
float4 B = float4(0, 0, 1, 0);
float4 T = float4(1, 0, 0, 0);
OUT.oNSp = mul(WorldXf, N);
//Position in world space
OUT.oPosition = worldPos;
//T, B, N in world space
OUT.normal = mul(WorldXf, N);
OUT.tangent = mul(WorldXf, T);
OUT.binormal = mul(WorldXf, B);
matTangent[0] = OUT.tangent;
matTangent[1] = OUT.binormal;
matTangent[2] = OUT.normal;
OUT.tangentSpaceEye = normalize(mul(OUT.eye, matTangent));
OUT.tangentSpaceLightDir = normalize(mul(-OUT.worldLightDir, matTangent));
return OUT;
}
//--------------------------
float4 color_mapping(v2f IN,
in float3 p_omega_out,
in float4 ambient,
in float4 diffuse,
in float4 specular,
in float specularPower,
in sampler2D color_map : register(s0),
in sampler2D sstm : register(s1),
in sampler2D nm : register(s3)
)
{
float3 BumpNormal = tex2D(nm, IN.texcoord)*2.0 - 1.0;
float4 amb = AmbientIntensity * ambient;
float4 diff = DiffuseIntensity * float4(p_omega_out, 1) * saturate(dot(IN.tangentSpaceLightDir,BumpNormal));
float3 R = normalize(2.0 * dot(BumpNormal, IN.tangentSpaceLightDir) * BumpNormal - IN.tangentSpaceLightDir);
float3 v = normalize(IN.tangentSpaceEye);
float spec = pow(saturate(dot(R,v)), specularPower) * SpecularIntensity;
// compute final color
float4 color = tex2D(color_map,IN.texcoord);
float4 finalcolor = (amb + diff + spec) * color;
//Remove this line to display p_omega_out with the diffuse and normal map
//-----------------------------------
finalcolor = float4(p_omega_out, 1.0);
//-----------------------------------
return finalcolor;
}
//--------------------------
float FindLayer(in float depthM,
in float2 umvm,
in sampler2D sstm : register(s1)
)
{
float4 ss_val = tex2Dlod(sstm, float4(umvm.x, umvm.y, 0, 1));
float layer = 0;
//Check red first, if depth is < red, layer = 0
//If and only if depth is greater than red, check if depth < green -> layer = 1
if(-depthM > ss_val.x)
{
if(-depthM > ss_val.y)
{
layer = 1;
if(-depthM > ss_val.z)
{
layer = 2;
}
}
}
//if(depthM > ss_val.w){layer = 3;}
return layer;
}
//--------------------------
float4 LayerThickness(in float3 m,
in float2 umvm,
in sampler2D sstm : register(s1)
)
{
float4 ss_val = tex2Dlod(sstm, float4(umvm.x, umvm.y, 0, 1));
return ss_val/4.0; //Divided by 4 because (1,0,0,0) = 1/4 red, (1, 1, 1, 1) = 0.25 + 0.25 + 0.25 + 0.25 = the full depth of 1
}
//--------------------------
float3 ReducedIntensity(in float3 p,
in float3 m,
in float3 lightdir,
in sampler2D sstm : register(s1),
in float3 normal,
in float2 umvm,
in float i,
in float3 PM_max,
in float2 upvp,
in float4 tangent,
in float4 binormal,
in float3 NSp,
in float3 diffuse,
in float num_samplesF
)
{
//L_ri(M, Omega_in)
float3 finalLightVector = float3(0, 0, 0);
float AttenuationKM = 1.0;
//Obtain a planar surface approximation for the current m depth [light and m in view space]
//light position - m
float3 omega_in = normalize(float3(0, 1, 0) - m);
float3 Nm = ((i*normal)+((num_samplesF - i)*NSp))/num_samplesF;
float3 Pm = ((i*PM_max) + ((num_samplesF - i)*p))/num_samplesF;
//Nm = normalize(Nm);
//Pm = normalize(Pm);
float cosTheta = cos(dot(Nm, omega_in));
//Calculate the distance ||KM||
float KM = length(dot((Pm*m),Nm))/cosTheta;
//Compute the thickness of the layers at the point M, lookup SSTM
float4 thicknessLayersM = LayerThickness(m, umvm, sstm);
//Compute the thickness of the layers at the point K
float3 K = m + (KM*-omega_in); //SWAPPED to go back up to K
float3 PK = K - p; //PK 0 first time round, p ad K are the same
float2 ukvk = (0,0);
ukvk.x = upvp.x + dot(PK, tangent.xyz);
ukvk.y = upvp.y + dot(PK, binormal.xyz);
//ukvk = normalize(ukvk);
float4 thicknessLayersK = LayerThickness(K, ukvk, sstm);
//Average thicknesses
float4 thicknessAverage = 0.5*(thicknessLayersM + thicknessLayersK);
float sigmaX = ((thicknessLayersM.x - thicknessLayersK.x)/2.0)/cosTheta;
float sigmaY = ((thicknessLayersM.y - thicknessLayersK.y)/2.0)/cosTheta;
float sigmaZ = ((thicknessLayersM.z - thicknessLayersK.z)/2.0)/cosTheta;
float sigmaW = ((thicknessLayersM.w - thicknessLayersK.w)/2.0)/cosTheta;
float sigmaTotal = sigmaX+sigmaY+sigmaZ+sigmaW;
float d1,d2,d3,d4;
d1 = min(KM - sigmaTotal, thicknessAverage.x/cosTheta);
d2 = min(KM - sigmaTotal, thicknessAverage.y/cosTheta);
d3 = min(KM - sigmaTotal, thicknessAverage.z/cosTheta);
d4 = min(KM - sigmaTotal, thicknessAverage.w/cosTheta);
//Calculate the attenuation along KM:
float att_1, att_2, att_3, att_4;
att_1 = exp(-2.6 * d1);
att_2 = exp(-6.6 * d2);
att_3 = exp(-1.5 * d3);
att_4 = exp(-1.0 * d4); //TODO: Make not HARD CODED!
AttenuationKM = att_1*att_2*att_3*att_4;
//Estimate the reduced intensity, light position - k
float3 omega_in_k = float3(0, 1, 0) - K;
finalLightVector = omega_in_k*AttenuationKM;
return finalLightVector;
}
//--------------------------
float PhaseFunction(float g, float theta)
{
float pTheta = (1.0-(g*g))/4.0*3.14*(1.0+g*cos(theta))*(1.0+g*cos(theta));
return pTheta;
}
//--------------------------
/************ PIXEL SHADER ******************/
float4 pixel_shader(v2f IN,
uniform float specularPower,
uniform float4 ambient,
uniform float4 diffuse,
uniform float4 specular,
uniform sampler2D cm, //diffuse color map
uniform sampler2D sstm, //Subsurface Texture
uniform sampler1D matrix_tex, //Floating Point texture containing scattering coefficients
uniform sampler2D nm //Normal map, not needed
) : COLOR0
{
float3 p = IN.oPosition; //The pixel position in world space
float num_samplesF = 50.0f;
//Omega out is the view vector to the point
float3 omega_out = IN.eye; //The view vector in world space
//L(P, Omega_out) The lighting contribution vector from point P
float3 p_omega_out = float3(0,0,0);
float AttenuationPM = 1.0;
float Depth_max = 1.0;
float3 M_max = p - ((Depth_max/dot(IN.oNSp, omega_out))*omega_out);
float3 PM_max = M_max - p;
float3 PMstep = PM_max/num_samplesF;
float tan = dot(PM_max, IN.tangent.xyz);
float bi = dot(PM_max, IN.binormal.xyz);
float2 dsdt = float2(tan, bi); //normalize(IN.eye.xy);
float2 texCoordStep = float2(dsdt.x/num_samplesF, dsdt.y/num_samplesF);
float2 umvm = IN.texcoord.xy;
float depthM = 0;
float depthStep = dot(PMstep, IN.normal); //This needs to be a value between 0-1
float3 m = p; //M starts of as the point p and increases in depth
float theta = dot(IN.worldLightDir.xyz, omega_out);//The angle between the light vector and the eye vector
float currentLayer = 0;
float3 reducedIntensity;
float4 mScattering; //Check this
float4 currentLayerCoeffs_S, currentLayerCoeffs_T;
float currentLayerCoeffs_g; //RGBA = S-T-g-Blank
float3 myTest;
for(int i = 0; i < num_samplesF; i++)
{
float iF = i;
//Point M localization
currentLayer = FindLayer(depthM, umvm, sstm); //Returns a value between 0 and 3
//Estimate the reduced intensity - L_ri(M, omega_in)
reducedIntensity = ReducedIntensity(p, m, IN.worldLightDir.xyz, sstm, IN.normal.xyz, umvm,
iF, PM_max, IN.texcoord, IN.tangent, IN.binormal, IN.oNSp, diffuse, num_samplesF); //IMPLICIT CAST
//Estimate the single scattering at point M:
float3 coeffsPixel = float3(currentLayer/16.0, ((currentLayer+4.0)/16.0), ((currentLayer+8.0)/16.0)); //16 pixels in tex, divide by 16 for 0-1 tex space
currentLayerCoeffs_S = tex1Dlod(matrix_tex, float4(coeffsPixel.r, 0, 0, 1)); //0-3rd pixel
currentLayerCoeffs_T = tex1Dlod(matrix_tex, float4(coeffsPixel.g, 0, 0, 1)); //4-7th pixel range
currentLayerCoeffs_g = tex1Dlod(matrix_tex, float4(coeffsPixel.b, 0, 0, 1)); //8-11th pixel range -- only r component of this texel used
mScattering = currentLayerCoeffs_S * float4(reducedIntensity, 1.0) * PhaseFunction(currentLayerCoeffs_g.x, theta); //L_ri(M, omega_out)
//Attenuate the scattered radiance along PM and add the contribution of point M
p_omega_out += float3(mScattering * AttenuationPM * -PMstep);
//Move to the next sample M and compute its tex coords and attenuation
umvm.x += texCoordStep.x;
umvm.y += texCoordStep.y;
depthM += depthStep;
m += PMstep;
AttenuationPM *= exp(-currentLayerCoeffs_T*length(PMstep));
}
return color_mapping(IN, p_omega_out, ambient, diffuse, specular, specularPower, cm, sstm, nm);
}
///////////////////////////////////////
/// TECHNIQUES ////////////////////////
///////////////////////////////////////
technique SSTM <
string Script = "Pass=p0;";
> {
pass p0 <
string Script = "Draw=geometry;";
> {
VertexShader = compile vs_3_0 view_spaceVS(gWorldXf, gWvpXf);
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;
AlphaBlendEnable = false;
CullMode = None;
PixelShader = compile ps_3_0 pixel_shader(
specularPower,
ambient,
diffuse,
specular,
cm,
sstm,
matrix_tex,
nm);
}
}
[/source]
The file is attached
here as well because it's not really displaying properly here.