Cube environment map in HLSL

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Cube environment map in HLSL

Post by Mel »

This is a HLSL code for a custom cubic environment map system i've been thingking lately. The best of it is that it works well! :)

It is a 2 Dynamic lights, phong shader with a reflection map done with a custom system for cube maps. Obviously, it would work better if we had the cube map already implemented in Irrlicht, but until then, this is a good sustitutive IMO.

This is the Vertex shader.

Code: Select all

float3 fvLightPosition1;
                 float3 fvLightPosition2;
                 float3 fvEyePosition;
                 float4x4 matWorld;
                 float4x4 matWorldViewProjection;
                 float4x4 matWorldInv;

struct VS_INPUT 
                   {
                   float4 Position : POSITION0;
                   float2 Texcoord : TEXCOORD0;
                   float3 Normal :   NORMAL0;
                   float3 Binormal : BINORMAL0;
                   float3 Tangent :  TANGENT0;
   
                   };

struct VS_OUTPUT 
                   {
                   float4 Position :        POSITION0;
                   float2 Texcoord :        TEXCOORD0;
                   float3 ViewDirection :   TEXCOORD1;
                   float3 LightDirection1:   TEXCOORD2;
                   float3 LightDirection2:   TEXCOORD3;
                   float3 truViewDir:        TEXCOORD4;
                   float3 truNormal:         TEXCOORD5;
   
                   };

VS_OUTPUT vs_main( VS_INPUT IN )
                   {
                   VS_OUTPUT OUT;
                   OUT.Position = mul( IN.Position, matWorldViewProjection );
                   OUT.Texcoord = IN.Texcoord;
   
                   float3 RealPos = mul(IN.Position, matWorld);
   
                   float3 viewVec = fvEyePosition - RealPos;
                   OUT.truViewDir=viewVec;
                   float3 lightVec1 = fvLightPosition1 - RealPos;
                   float3 lightVec2 = fvLightPosition2 - RealPos;
   
                   float3 tViewVec;
                   float3 tLightVec1;
                   float3 tLightVec2;

 float3 Tangent = normalize(IN.Tangent);
                   float3 Normal = normalize(IN.Normal);
                   float3 Binormal = cross( Normal , Tangent );
                   Tangent = cross( Normal,Binormal);
   
                   Tangent = mul( matWorldInv,Tangent );
                   Binormal = mul( matWorldInv,Binormal );
                   Normal = mul( matWorldInv,Normal );
                   OUT.truNormal=Normal;
   
                   tViewVec.x = dot(viewVec,Tangent);
                   tViewVec.y = dot(viewVec,Binormal);
                   tViewVec.z = dot(viewVec,Normal);
   
                   tLightVec1.x = dot(lightVec1,Tangent);
                   tLightVec1.y = dot(lightVec1,Binormal);
                   tLightVec1.z = dot(lightVec1,Normal);

 tLightVec2.x = dot(lightVec2,Tangent);
                   tLightVec2.y = dot(lightVec2,Binormal);
                   tLightVec2.z = dot(lightVec2,Normal);
   
                   OUT.ViewDirection = tViewVec;
                   OUT.LightDirection1 = tLightVec1;
                   OUT.LightDirection2 = tLightVec2;
   
                   return( OUT );
                   }
And this is the Pixel Shader.

Code: Select all

float4 LightColor1;
                 float4 LightColor2;

sampler2D baseMap;
                   sampler2D bumpMap;
                   sampler2D refMap;

float2 cube2uv(float3 IN){
                   float2 uv=0;
                   float3 inSQ=IN;

if(inSQ.x<0){inSQ.x=-inSQ.x;}
                   if(inSQ.y<0){inSQ.y=-inSQ.y;}
                   if(inSQ.z<0){inSQ.z=-inSQ.z;}

//We know that we will never divide by zero, so thse calculations are safe
//We map the coordinates in a texture with proportion 2:1, so we avoid rounding errors
//though it wastes the 25% of the texture space.

if(inSQ.x>=inSQ.y&&inSQ.x>=inSQ.z){
                   if(IN.x>0){
                   uv.x=0.125;
                   uv.y=0.25;
                   uv.x+=IN.z/IN.x*0.125;
                   uv.y-=IN.y/IN.x*0.25;
                   }else{
                   uv.x=0.625;
                   uv.y=0.25;
                   uv.x+=IN.z/IN.x*0.125;
                   uv.y+=IN.y/IN.x*0.25;
                   }
                   }
                   if(inSQ.y>inSQ.x&&inSQ.y>=inSQ.z){
                   if(IN.y>0){
                   uv.x=0.125;
                   uv.y=0.75;
                   uv.x-=IN.x/IN.y*0.125;
                   uv.y+=IN.z/IN.y*0.25;
                   }else{
                   uv.x=0.625;
                   uv.y=0.75;
                   uv.x+=IN.x/IN.y*0.125;
                   uv.y+=IN.z/IN.y*0.25;
                   }
                   }
                   if(inSQ.z>inSQ.x&&inSQ.z>inSQ.y){
                   if(IN.z>0){
                   uv.x=0.375;
                   uv.y=0.25;
                   uv.x-=IN.x/IN.z*0.125;
                   uv.y-=IN.y/IN.z*0.25;
                   }else{
                   uv.x=0.375;
                   uv.y=0.75;
                   uv.x-=IN.x/IN.z*0.125;
                   uv.y+=IN.y/IN.z*0.25;

 }
                   }
                 

return uv; 
                   }

struct PS_INPUT 
                   {
                   float2 Texcoord :        TEXCOORD0;
                   float3 ViewDirection :   TEXCOORD1;
                   float3 LightDirection1:   TEXCOORD2;
                   float3 LightDirection2:   TEXCOORD3;
                   float3 truViewDir:        TEXCOORD4;
                   float3 truNormal:         TEXCOORD5;
   
                   };

float4 ps_main( PS_INPUT IN ) : COLOR0
                   { 
                   float4 base = tex2D(baseMap,IN.Texcoord);
                   float3 normal = tex2D(bumpMap,IN.Texcoord);
                   normal = normal*2-1;
   
                   float3 viewDir = normalize(IN.ViewDirection);
   
                   float3 lightDir1 = normalize(IN.LightDirection1);
                   float3 lightDir2 = normalize(IN.LightDirection2);
   
                   normal = normalize(normal);
                   float3 truNormal=normalize(IN.truNormal);
   
                   float3 halfView1 = normalize(viewDir+lightDir1);
                   float3 halfView2 = normalize(viewDir+lightDir2);
                   float3 reflVec = reflect(-IN.truViewDir,truNormal);
                   float4 refl = tex2D(refMap,cube2uv(reflVec));
   
                   float diffuse1 = dot(normal,lightDir1)*1;
                   float specular1 = pow(dot(halfView1,normal),68)*base.w;
   
                   float diffuse2 = dot(normal,lightDir2)*1;
                   float specular2 = pow(dot(halfView2,normal),68)*base.w;
   
                   return(saturate(base *(diffuse1+specular1)*LightColor1 + 
                   base *(diffuse2+specular2)*LightColor2+refl*0.95));
                   }
These are some results of it in action.

Image

But the reflection maps are better seen in a video.

http://www.youtube.com/watch?v=jwBQH1-GkyE
http://www.youtube.com/watch?v=CaeoIv0pjtQ

If you feel like using it. This chart shows how to order the map.

Image
Last edited by Mel on Sat Nov 27, 2010 3:25 pm, edited 1 time in total.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Strong99
Admin
Posts: 687
Joined: Fri Mar 31, 2006 7:06 pm
Location: Netherlands
Contact:

Post by Strong99 »

the cubemap texture is fited into one large texture? The sampler2D refMap?

Nice shader :D sometimes better alternative than rendering the whole environment.
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

Yes, The refmap texture is divided into some parts, and each of them is a face of the cube map. The good thing is that, perhaps, it allows for easy dynamic environment mapping. Or more effects that use a cube map as a source of information.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Very nice

Try something like "return clamp(uv, 0.01, 0.99);" to get rid of the border artifacts. You lose some info in the edges but usually for environment maps it doesn't matter.

Extra points if you adapt this technique to generate point-light shadow maps :P
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

I'll try.. let's see if it works.

What are point-light shadowmaps?

EDIT. googled it... seems interesting... i'll try something if i get to do a good LiSPSM implementation...

RE-EDIT. I tried what you told me. It didn't work. Although i disabled the MipMapping just for the sake of it, and seemed to work flawlessly. It seems that the black dots were points in which the refmap didn't have MIPMAP detail, so, they appeared black. Disabling the MipMap levels for that texture worked pretty well, ill post some screens later.

After this i will try an experiment with Image Based Lighting. The "cubemap" support is there, the next step is easy.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
Post Reply