29
Oct
08

Subsurface Scatter Shader

GLSL translation of this fake sub-surface scattering shader by InvalidPointer.

I’m always amazed when these things actually work…

Vertex Shader:

////////////////////////////
// SUB-SURFACE SCATTER VS //
////////////////////////////

/* --------------------------
SubScatter Vertex Shader:

Fake sub-surface scatter lighting shader by InvalidPointer 2008.
Found at
http://www.gamedev.net/community/forums/topic.asp?topic_id=481494

HLSL > GLSL translation
toneburst 2008
-------------------------- */

// Set light-position
uniform vec3 LightPosition;

// Varying variables to be sent to Fragment Shader
varying vec3 worldNormal, eyeVec, lightVec, vertPos, lightPos;

void subScatterVS(in vec4 ecVert)
{
	lightVec = LightPosition - ecVert.xyz;
	eyeVec = -ecVert.xyz;
	vertPos = ecVert.xyz;
	lightPos = LightPosition;
}

////////////////
//  MAIN LOOP //
////////////////

void main()
{
	worldNormal = gl_NormalMatrix * gl_Normal;
	
	vec4 ecPos = gl_ModelViewProjectionMatrix * gl_Vertex;
	
	// Call function to set varyings for subscatter FS
	subScatterVS(ecPos);
	
	//Transform vertex by modelview and projection matrices
	gl_Position = ecPos;

	//Forward current texture coordinates after applying texture matrix
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}

Fragment Shader:

////////////////////////////
// SUB-SURFACE SCATTER FS //
////////////////////////////

/* --------------------------
SubScatter Fragment Shader:

Fake sub-surface scatter lighting shader by InvalidPointer 2008.
Found at
http://www.gamedev.net/community/forums/topic.asp?topic_id=481494

HLSL > GLSL translation
toneburst 2008
-------------------------- */

// Variables for lighting properties
uniform float MaterialThickness;
uniform vec3 ExtinctionCoefficient; // Will show as X Y and Z ports in QC, but actually represent RGB values.
uniform vec4 LightColor;
uniform vec4 BaseColor;
uniform vec4 SpecColor;
uniform float SpecPower;
uniform float RimScalar;
//uniform sampler2D Texture;

// Varying variables to be sent to Fragment Shader
varying vec3 worldNormal, eyeVec, lightVec, vertPos, lightPos;

float halfLambert(in vec3 vect1, in vec3 vect2)
{
	float product = dot(vect1,vect2);
	return product * 0.5 + 0.5;
}

float blinnPhongSpecular(in vec3 normalVec, in vec3 lightVec, in float specPower)
{
	vec3 halfAngle = normalize(normalVec + lightVec);
	return pow(clamp(0.0,1.0,dot(normalVec,halfAngle)),specPower);
}

// Main fake sub-surface scatter lighting function

vec4 subScatterFS()
{
	float attenuation = 10.0 * (1.0 / distance(lightPos,vertPos));
	vec3 eVec = normalize(eyeVec);
	vec3 lVec = normalize(lightVec);
	vec3 wNorm = normalize(worldNormal);
	
	vec4 dotLN = vec4(halfLambert(lVec,wNorm) * attenuation);
	//dotLN *= texture2D(Texture, gl_TexCoord[0].xy);
	dotLN *= BaseColor;
	
	vec3 indirectLightComponent = vec3(MaterialThickness * max(0.0,dot(-wNorm,lVec)));
	indirectLightComponent += MaterialThickness * halfLambert(-eVec,lVec);
	indirectLightComponent *= attenuation;
	indirectLightComponent.r *= ExtinctionCoefficient.r;
	indirectLightComponent.g *= ExtinctionCoefficient.g;
	indirectLightComponent.b *= ExtinctionCoefficient.b;
	
	vec3 rim = vec3(1.0 - max(0.0,dot(wNorm,eVec)));
	rim *= rim;
	rim *= max(0.0,dot(wNorm,lVec)) * SpecColor.rgb;
	
	vec4 finalCol = dotLN + vec4(indirectLightComponent,1.0);
	finalCol.rgb += (rim * RimScalar * attenuation * finalCol.a);
	finalCol.rgb += vec3(blinnPhongSpecular(wNorm,lVec,SpecPower) * attenuation * SpecColor * finalCol.a * 0.05);
	finalCol.rgb *= LightColor.rgb;
	
	return finalCol;	
}

////////////////
//  MAIN LOOP //
////////////////

void main()
{
	gl_FragColor = subScatterFS();
}

7 Responses to “Subsurface Scatter Shader”


  1. 1 Steve Elbows
    November 2, 2008 at 2:39 pm

    This is a beautiful shader, thanks so much 🙂

  2. 2 toneburst
    November 2, 2008 at 5:40 pm

    Hi Steve,

    yeah, it is nice, is’t it..
    All credit should go to InvalidPointer though. I really just translated it into GLSL from his original code.

    a|x

  3. 3 achim
    November 10, 2008 at 1:09 pm

    indeed very beautiful! thanks for the port to GLSL

    Cheers
    Achim

    PS: in case you don’t know about it, check http://www.derivative.ca
    Might be very interesting for you, but it’s PC only for now

  4. May 3, 2010 at 12:19 am

    well, m8

    this is amazing

    thx a lot for sharing your work in such a straight forward way

    have a gr8 day, and gr8 life 😉

    • 5 toneburst
      May 3, 2010 at 9:16 am

      Thanks, mate! I wish I had more time to devote to QC stuff these days. Hopefully I’ll be able to get back to it soon…

      a|x

  5. April 25, 2011 at 8:07 am

    Thanks for your amazing sharing~


Leave a comment


October 2008
M T W T F S S
 12345
6789101112
13141516171819
20212223242526
2728293031  

Links

Blog Stats

  • 502,032 hits