Hair Shader

Posted By: lostzac

Hair Shader - 02/12/13 10:55

I found this article
Hair Shading and Rendering

and was wondering if any of the gurus could whip up this kind of shader. I need the ability to pass the hair color to the shader as well so I cam simulate aging. I unfortunately do not have the knowledge base in writing shaders and figure this would be a little advance for me...
Posted By: HeelX

Re: Hair Shader - 02/12/13 12:26

I think that this is easy, the whole procedure is done in the pixel shader and it is explained in detail in that paper. Problem is, that there are little to no good and free human heads available with an adequate hair mesh. Do you have one that you are willing to contribute? If yes, I am sure that someone is going to check this out.
Posted By: lostzac

Re: Hair Shader - 02/12/13 12:31

I can give you a hair model and textures if you like..not a problem...
Posted By: HeelX

Re: Hair Shader - 02/12/13 12:32

Would it be a free model then? Then post it here.
Posted By: lostzac

Re: Hair Shader - 02/12/13 12:49

No it would not be free due to EULA issues....I can send you a link to the resources you would need, and the community is more then welcomed to the code. However I can not provide the community the models for download..
Posted By: lostzac

Re: Hair Shader - 02/13/13 12:37

Ok so I have tired to make a go of this myself, as it is something I need for my game, and one should not expect handouts..not to mention the more I can increase my knowledge base the better...

So breaking down the idea into parts, I figured I would first see if I could code the color change to make the colors of the hair...

Roots - being the Darkest
Main - the majority of the hair color
Highlights - being the lightest...

I know their is a lot more to real hair color but its a start..


This is the texture I am using with alpha channels , figuring the easiest way from what I have read would be to do an alpha-blending of the colors..where the texture was darkest would be the darkest color ect ect ect

Right now I am just trying to blend the color red into the hair
and I either am missing a step in the logic, or well as this is the first shader I am trying to write....way off base...

Code:
// Input parameters.
float4x4 matWorldView;
float4x4 matProj;

texture entSkin1;
sampler hair = sampler_state
{
    Texture = entSkin1;
 
    MinFilter = None;
    MagFilter = None;
    MipFilter = None;
    AddressU = clamp;
    AddressV = clamp;
};



// Vertex shader input structure.
struct VS_INPUT
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
};

// Vertex shader output structure.
struct VS_OUTPUT
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
};

// Vertex shader program.
VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
 
    //generate the view-projection matrix
    float4x4 vp = mul(matWorldView, matProj);
    output.Position = mul(input.Position, vp);
 
    output.TexCoord = input.TexCoord;
 
    return output;
}

float4 PS(VS_OUTPUT input) : COLOR
{
    float4 colour = tex2D(hair, input.TexCoord);
    
  
	 colour.r = (colour.r * colour.a) + (255 * 1);
	 colour.g = (colour.g * colour.a) + (0 * 1);
	 colour.b = (colour.b * colour.a) + (0 * 1);
;
    return colour;
}

technique Terrain
{
    pass Main
    {
        AlphaBlendEnable = true;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}



The issue I am having is the white are receiving the tint I want, but the rest is coming back grey...



Can someone point me in the right direction
Posted By: lostzac

Re: Hair Shader - 02/13/13 19:49



I have the alpha issue sorted out...next on the list is to add in lighting and highlights...
Posted By: xbox

Re: Hair Shader - 02/15/13 00:28

I know nothing about shaders, but Here is a "hair" texture that I made from the article provided.

Posted By: lostzac

Re: Hair Shader - 02/15/13 10:00

Yeah I am not having much luck at the moment...as I am just learning.. probably should teach myself the basics first...so am going through the workshops and reading tutorials in hopes to get a better grasp..That is a really good texture bu the way, Thank you and I will try to use it.
Posted By: xbox

Re: Hair Shader - 02/15/13 12:31

haha grin , keep at the tutorials, that's the only way to learn. I give you credit for at least trying to learn. If you use my texture then cool, if not, don't worry about it. I wish you the best of luck though. laugh
Posted By: lostzac

Re: Hair Shader - 02/15/13 13:32

Yeah in the past i have counted on the kindness of other programmers like HeelX contributions to handle any Shaders I thought I would need, and spent my time learning c lite.

Thanks for the wish, I have managed to get the coloring down right, and working on alpha mask, and lighting now....
Posted By: lostzac

Re: Hair Shader - 03/12/13 14:09

Ok so in working on this shader I am coming up with two issues I seek input on..





I can not figure out why the Hair is coming up with the blueish color,and its also causing my eye [Pic2] to display through the skin...(This only happens when I have the Hair material on)

Here is my code thus far
Code:
//////////////////////////////
// Hair Fx
//////////////////////////////

//////////////////////////////
// Matrix
//////////////////////////////
float4x4 matWorldViewProj; 
float4x4 matWorld;
float4x4 matView;
float4x4 matWorldInv;
float4x4 matViewInv;

//////////////////////////////
// Lighting
//////////////////////////////
float4 vecLightPos[8];
float4 vecLightColor[8];
float4 vecAmbient;
float4 vecDiffuse;
float4 vecSpecular;

//////////////////////////////
// Coloring
//////////////////////////////
float specExp1 = 10;
float specExp2 = 0;

//////////////////////////////
// Tweakables
//////////////////////////////
float primeShift = 10;
float secondShift = 15;

//////////////////////////////
// Texture Reference
//////////////////////////////
texture entSkin1;
texture entSkin2;
texture entSkin3;
texture entSkin4;

sampler2D ColorSampler = sampler_state
{
	Texture = entSkin1;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = WRAP;
	AddressV = WRAP;
};

sampler ShiftSampler = sampler_state
{ 
	Texture = entSkin2;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = WRAP;
	AddressV = WRAP;
};

sampler SpecSampler = sampler_state
{ 
	Texture = entSkin3;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = WRAP;
	AddressV = WRAP;
};

sampler AmbOccSampler = sampler_state
{ 
	Texture = entSkin3;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = WRAP;
	AddressV = WRAP;
};

//////////////////////////////
// Data Structs
//////////////////////////////
struct appdata 
{
    float3 Position	: POSITION;
    float4 UV		: TEXCOORD0;
    float4 Normal	: NORMAL;
    float4 Tangent	: TANGENT0;
    float4 Binormal	: BINORMAL0;
};

struct vertexOutput 
{
    float4 HPosition	: POSITION;
    float2 UV		: TEXCOORD0;
    float3 LightVec	: TEXCOORD1;
    float3 WorldNormal	: TEXCOORD2;
    float3 WorldTangent	: TEXCOORD3;
    float3 WorldBinormal : TEXCOORD4;
    float3 WorldView	: TEXCOORD5;
    float4 LightColor : COLOR0;
};

//////////////////////////////
// Additonal Functions
//////////////////////////////
float3 ShiftTangent(float3 T, float3 N, float shift)
{
	float3 shifttedT = T + shift * N;
	return normalize(shifttedT);
}

float StrandSpecular(float3 T, float3 V, float3 L, float exponet)
{
	float3 H = normalize(L+V);
	float dotTh = dot(T,H);
	float sinTh = sqrt(1.0 - dotTh * dotTh);
	float dirAtten = smoothstep(-1.0,0.0, dot(T,H));
	return dirAtten * pow(sinTh,exponet);
}

float4 DoPointLight(float3 P, float3 N, int i)
{
	// calculate the light ray pointing from the light to the surface
   float3 D = (float3)vecLightPos[i]-P;
	
	// calculate the angle between surface and light ray
   float NdotL = dot(N,normalize(D));

	// modulate the light by the surface angle
   float4 Color = vecLightColor[i] * NdotL;

	// calculate the light attenuation factor
   float fac = 0.f;
   if (NdotL >= 0.f && vecLightPos[i].w > 0.f)
   {
		// get the distance factor
      float LD = length(D)/vecLightPos[i].w;
      if (LD < 1.f)
        fac = 1.f - LD;
   }
   return Color * fac;
}


//////////////////////////////
// Vertex Shader
//////////////////////////////
vertexOutput simpleVS(appdata IN) 
{
   vertexOutput OUT = (vertexOutput)0;
    
   OUT.WorldNormal = mul(IN.Normal,matWorldInv).xyz;
    
   OUT.WorldTangent = mul(IN.Tangent,matWorldInv).xyz;
    
   OUT.WorldBinormal = mul(IN.Binormal,matWorldInv).xyz;
    
   float4 Po = float4(IN.Position.xyz,1); // homogeneous location
    
   float4 Pw = mul(Po,matWorld);	// convert to "world" space

   float3 N = normalize(IN.Normal);
   float3 P = mul(IN.Position,matWorld);

   for (int i=0; i<8; i++)
   {
      OUT.LightVec = vecLightPos[i] - Pw.xyz;
		OUT.LightColor += DoPointLight(P,N,i);  
   }
 
    OUT.UV = IN.UV.xy;

    OUT.WorldView = normalize(matViewInv[3].xyz - Pw.xyz);

    OUT.HPosition = mul(Po,matWorldViewProj);

    return OUT;
}

//////////////////////////////
// Pixle Shader
//////////////////////////////
float4 hairPS_t(vertexOutput IN) : COLOR 
{
	float shiftTex = tex2D(ShiftSampler, IN.UV) - 0.5;
	float t1 = ShiftTangent(IN.WorldTangent,IN.WorldNormal,primeShift+shiftTex);
	float t2 = ShiftTangent(IN.WorldTangent,IN.WorldNormal,secondShift+shiftTex);
	
	float3 diffuse = saturate(lerp(0.25,1.0,dot(IN.WorldNormal,IN.LightVec)));
	diffuse*=vecDiffuse.rgb;
	
	float3 specular = vecSpecular * StrandSpecular(t1,IN.WorldView,IN.LightVec,specExp1);
	float specMask = tex2D(SpecSampler,IN.UV);
	specular+= vecSpecular * specMask * StrandSpecular(t2,IN.WorldView,IN.LightVec,specExp2);

	float4 FinalColor = (0.0,0.0,0.0,1.0);
	float4 Color = tex2D(ColorSampler,IN.UV);
	FinalColor.rgb = (diffuse+specular) * Color.rgb * IN.LightColor;
	FinalColor.rgb*= tex2D(AmbOccSampler,IN.UV).rgb;
	FinalColor.a = Color.a;
	return Color;
}

///////////////////////////////////////
/// TECHNIQUES 
////////////////////////
technique Hair
 {		
 	pass p0
 	{
		ZEnable = true;
		ZWriteEnable = true;
		CullMode = ccw;
		ZFunc = Less;
		AlphaBlendEnable=true;
		//SrcBlend=srcalpha;
		//DestBlend=invsrcColor;
		AlphaTestEnable = True;
		BlendOpAlpha = ADD;	
		VertexShader = compile vs_2_0 simpleVS();
		PixelShader = compile ps_2_0 hairPS_t();
	}	
}



again seeking any ideas to these issues
Posted By: Ch40zzC0d3r

Re: Hair Shader - 03/12/13 14:54

Im not very farmilar with shader programming but the blue could be the same as the background color, try to chnage the color.
For the Z-Buffer sorting bug use this:

zWriteEnable = true;
alphaTestEnable = true;
alphaBlendEnable = false;

And remove BlendOpAlpha = ADD;
Posted By: lostzac

Re: Hair Shader - 03/12/13 17:16

Originally Posted By: Ch40zzC0d3r
Im not very farmilar with shader programming but the blue could be the same as the background color, try to chnage the color.
For the Z-Buffer sorting bug use this:



zWriteEnable = true;
alphaTestEnable = true;
alphaBlendEnable = false;

And remove BlendOpAlpha = ADD;



the alphaBlendEnable change to false fixed both issues
Thank you
Posted By: lostzac

Re: Hair Shader - 03/13/13 11:26

ok now I am running into a similar issue with the beards...



This is without AlphaBlending or AlphaTest as I wanted to make sure it was creating the shells



This one is AlphaBlendEnable = True



This one is AlphaTestEnable = True and AlphaBlendEnable = false

Here is the code I am using...(Fur Shader off wiki with less shells basicaly)

Code:
//////////////////////////////
// Hair Fx
//////////////////////////////
#define nrm normalize
#define sat saturate
#define dst distance

//////////////////////////////
// Matrix
//////////////////////////////
float4x4 matWorld;
float4x4 matViewProj;
float4x4 matWorldViewProj;
float4 vecViewPos;
float4 vecTime;

//////////////////////////////
// Lighting
//////////////////////////////
float4 vecSunDir;
float4 vecAmbient;
float4 vecLightColor[8];
float4 vecLightPos[8];
int iLights;

//////////////////////////////
// Coloring
//////////////////////////////


//////////////////////////////
// Tweakables
//////////////////////////////
float  vecSkill1;
float4 vecSkill41;
float4 vecSkill45;

//////////////////////////////
// Texture Reference
//////////////////////////////
texture entSkin1;
texture entSkin2;

sampler SKIN = sampler_state {texture = <entSkin1>;};
sampler FUR = sampler_state {texture = <entSkin2>;};


//////////////////////////////
// Data Structs
//////////////////////////////


//////////////////////////////
// Additonal Functions
//////////////////////////////



//////////////////////////////
// Vertex Shader
//////////////////////////////
float4 VS (	uniform float O,
		in float4 P : POSITION,
		in float2 T : TEXCOORD0,
		in float3 N : NORMAL,

		out float4 tex : TEXCOORD0,
		out float3 light : TEXCOORD1) : POSITION 
{		
	tex.xy = T;	
	tex.z = pow(O / 30,2);	
	tex.w = 0.5 - (dst(mul(P,matWorld),vecViewPos) > vecSkill1);
	
	P.xyz += vecSkill41.x * O * N + tex.z;
	float4 pos = mul(P,matWorld);
	//pos.y -= tex.z * vecSkill45.x;
	pos.z -= tex.z * vecSkill45.x;
	
	light = vecAmbient;
	for (int L=0; L<iLights; L++) 
		light += (1 - sat(length(pos.xyz - vecLightPos[L].xyz) / vecLightPos[L].w))
		* sat(dot(mul(N,matWorld),-nrm(pos - vecLightPos[L])))
		* vecLightColor[L] * 10;
	
	return mul(pos,matViewProj);
}

//////////////////////////////
// Pixle Shader
//////////////////////////////
float4 PS (	in float4 tex : TEXCOORD0,
		in float3 light : TEXCOORD1) : COLOR 
{
	clip(tex.w);

	float3 skin 	= tex2D(SKIN,tex.xy);
	float  len 	= tex2D(FUR,tex.xy).a;
	float4 fur 	= tex2D(FUR,tex.xy * vecSkill41.w);

	fur.a = (fur.rgb * vecSkill41.z - pow(tex.z,4)) * len;
	clip (fur.a);
	fur.rgb = lerp(fur,skin,vecSkill41.y);
	fur.rgb *= light;
	return fur;
}
	
///////////////////////////////////////
/// TECHNIQUES 
////////////////////////
technique t 
{	
	pass p 
	{
		ZEnable = true;
		ZWriteEnable = true;
		AlphaBlendEnable =false;
		AlphaTestEnable = TRUE;

		VertexShader = compile vs_2_0 VS(1);
		PixelShader = compile ps_2_0 PS();
	}
	
	pass p {VertexShader = compile vs_2_0 VS(2);PixelShader = compile ps_2_0 PS();}
	pass p {VertexShader = compile vs_2_0 VS(3);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(4);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(5);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(6);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(7);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(8);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(9);PixelShader = compile ps_2_0 PS();}
//	pass p {VertexShader = compile vs_2_0 VS(10);PixelShader = compile ps_2_0 PS();}
}



again any ideas would be helpful
Posted By: lostzac

Re: Hair Shader - 03/13/13 11:54

I am assuming the reason I am running into these issues has to deal with a render order or something similar to do with the zDepth...Is that all possible ? The image should look like image 2 but with the whole face their ...
Posted By: lostzac

Re: Hair Shader - 03/13/13 13:09

solved...was in the way i was designing the maps to render the facial hair...





Still have to play around with the images and coloring to get the desired results...but at least I know where the problem is now
Posted By: sivan

Re: Hair Shader - 03/13/13 13:52

it's getting really cool!
Posted By: HeelX

Re: Hair Shader - 03/13/13 14:29

I'm not sure if the treatment of the alpha channel is right, because cutout alpha is a bad idea for realistic hair. I guess you will get sorting errors with alphablending, maybe applying an alpha-to-coverage PP step could solve it; read here: Covering New Ground: Foliage Rendering in Pure
Posted By: Hummel

Re: Hair Shader - 03/13/13 14:52

What they suggest in this paper is not alpha-to-coverage:
Originally Posted By: paper
Alpha-to-coverage converts the alpha value output by the pixel shader into a coverage
mask. This coverage mask is combined with the standard multisample coverage mask to
determine which samples should be updated.
Alpha-to-coverage, when combined with alpha testing, gives softer edges without
sacrificing the ability to use the z-buffer with unsorted primitives. Although this is an
improvement on simple alpha testing, the resulting alpha gradients can be of poor
quality compared to those obtained in alpha blending. This is particularly true when
using a low number of samples or on hardware that doesn't support flexible coverage
masks.
The cases where alpha-to-coverage delivers suitable results are rather rare, since it works best for translucent surfaces which cover a preferably moderately large and homogeneous colored/translucent screen space area. wink
The technique described in the paper should be worth a try, though.
Posted By: lostzac

Re: Hair Shader - 03/13/13 18:40

I will take a look at the paper as it is driving me crazy every-time I add a new effect to be pulling my little left hair out due to something not rendering out
Posted By: Slin

Re: Hair Shader - 03/13/13 22:36

Actually for the hair, all blending problems can be solved by first rendering the head with depthtest and zwriteenable set and then the hair with zwriteenable off and alphablending on, if you need more than one hair layer, most (?) modelling tools allow to sort the face indices and thus the polygons rendering order by for example their distance to the center, if you do this from the inside to the outside, it should just work (at least if MED doesn´t destroy that order later on...).
Posted By: lostzac

Re: Hair Shader - 03/17/13 10:49

Added the ability to change hair color through the vecSkills
© 2024 lite-C Forums