Normals in RGB, heightmap in Alpha, passing to shader

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Normals in RGB, heightmap in Alpha, passing to shader

Post by Viking86 »

Greetings, I have a shader in which it passes a texture in 1, and the normals and heightmap in the second picture.
Thanks to some great people here i know how to pass textures to the shader

Code: Select all

int baseMap=0;
services->setPixelShaderConstant("baseMap", (float*)(&baseMap), 1);
int reliefMap=1;
services->setPixelShaderConstant("reliefMap", (float*)(&reliefMap), 1); 
The shader seems to work , when passing just a texture and a heigthmap i get the same results in irrilicht was in rendermonkey. The problem is when i give the required texture (normals in rgb component, heightmap in alpha component) it has no effect, i see a regular texture.

when creating the material from the shader i put EMT_PARALLAX_MAP_SOLID as the base material.

Image

any ideas why would this be happening? Perhaps the irrilicht .bmp format reader ?
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

Not intending to hijack the thread, but how exactly does the base material for a shader work? Doesn't the shader override the base material?
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

What does the "baseMap" and "reliefMap" variables look like in the shader?

It's not textures, right?
Viz_Fuerte
Posts: 91
Joined: Sun Oct 19, 2008 5:29 pm
Location: Valencia (Spain)
Contact:

Post by Viz_Fuerte »

The normal thing is that they require two textures (even three) to carry out a similar type of effect, but also, you can use the alpha channel of a texture to store textures that are not in color (black and white only for "bump map..." or height in "parallax, relief map...").

If the effect was set to GLSL change would be easy to accept another texture, but is written in assembly and is more difficult (at least for me).

I leave a link of a simple program to add texture to the alpha channel (like everybody else but is easier).
http://www.leadwerks.com/ccount/click.php?id=60
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Post by Viking86 »

slavik262 wrote:Not intending to hijack the thread, but how exactly does the base material for a shader work? Doesn't the shader override the base material?
I don't think it does in a complete sense, for example try putting a transparent material type as a base, you will get a transparent effect on your texture.
Valmond wrote: What does the "baseMap" and "reliefMap" variables look like in the shader?
It looks like this

Code: Select all

uniform sampler2D baseMap;
uniform sampler2D reliefMap;
The way the textures are passed is in the first post, i don't get any errors though like in the post you linked


here is the fragment and vertex shader along with the textures, and a rendermonkey project file
http://rapidshare.com/files/382283194/N ... r.zip.html


Viz_Fuerte wrote:I leave a link of a simple program to add texture to the alpha channel (like everybody else but is easier).
Thank you, I used photoshop before
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

Code: Select all

sampler2D
means texture (don't know if you can use it for other things but I think you can't), and

Code: Select all

services->setPixelShaderConstant("baseMap", (float*)(&baseMap), 1);
doesn't set a texture, it sets just one float (4 bytes) on that texture - entry.
Check out the link as Bate seems to have done the same thing as you do (setting a float on a texture variable).
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Post by Viking86 »

Valmond wrote:

Code: Select all

sampler2D
means texture (don't know if you can use it for other things but I think you can't), and

Code: Select all

services->setPixelShaderConstant("baseMap", (float*)(&baseMap), 1);
doesn't set a texture, it sets just one float (4 bytes) on that texture - entry.
Check out the link as Bate seems to have done the same thing as you do (setting a float on a texture variable).
Thnx for the answer, but I think thats the least of my problems as the texture loading does work.

after playing around in rendermonkey i found the main problem
tangents and binormals, when i set these to uniform values i get something resembling the desired effect. Now I am not sure how best to pass these in irrilcht, i have done this in the shader
instead of

Code: Select all

uniform vec3 rm_Binormal;
uniform vec3 rm_Tangent;
i put

Code: Select all

uniform vec4 Tangent;
uniform vec4 BiNormal;

...
vec3 rm_Tangent = vec3(gl_ModelViewMatrix * Tangent);
   vec3 rm_Binormal = vec3(gl_ModelViewMatrix * BiNormal);
I get this, similar to what i need but with artifacts, it is supposed to change depending on viewpoint (i suck at glsl)
Image
Viz_Fuerte
Posts: 91
Joined: Sun Oct 19, 2008 5:29 pm
Location: Valencia (Spain)
Contact:

Post by Viz_Fuerte »

Remember that Irrlicht stores the information on tangents and binormal of differently type.

ONLY OPENGL

for Tangent:

Code: Select all

vec3 t = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
for Binormal:

Code: Select all

vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
Also, remember to convert the mesh to tangents.
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Post by Viking86 »

Viz_Fuerte wrote:Remember that Irrlicht stores the information on tangents and binormal of differently type.

ONLY OPENGL

for Tangent:

Code: Select all

vec3 t = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
for Binormal:

Code: Select all

vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
Also, remember to convert the mesh to tangents.
Thank you, by adding the code for normals the effect does look a bit better
From a distance its a ok
Image

but getting near it does show some errors
Image

Now I took your advice and loaded a mesh and then made a tangent mesh as in the per pixel tutorial
Image

again it looks good from a distance, it seems im on the right track, just no completely there yet :)
Do I need to set up the gl_MultiTexCoord2 and gl_MultiTexCoord1 textures or does Irrilicht do this automaticly?

Now I changed only the .vert shader code from the original

Code: Select all

uniform vec3 fvLightPosition;
uniform vec3 fvEyePosition;

varying vec2 Texcoord;
varying vec3 eyeSpacePos;
varying vec3 eyeSpaceLight;
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
   
attribute vec3 rm_Binormal;
attribute vec3 rm_Tangent;
   
void main(void)
{ 
   eyeSpacePos = vec3(gl_ModelViewMatrix * gl_Vertex);
   eyeSpaceLight = (gl_ModelViewMatrix * vec4(fvLightPosition ,1.0)).xyz;
                       
   eyeSpaceTangent  = normalize(gl_NormalMatrix * rm_Tangent);
   eyeSpaceBinormal = normalize(gl_NormalMatrix * rm_Binormal);
   eyeSpaceNormal   = normalize(gl_NormalMatrix * gl_Normal);
   
   Texcoord   = gl_MultiTexCoord0.xy;
   
   gl_Position = ftransform();
}
to

Code: Select all

uniform vec3 fvLightPosition;
uniform vec3 fvEyePosition;

varying vec2 Texcoord;
varying vec3 eyeSpacePos;
varying vec3 eyeSpaceLight;
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
   
//uniform vec3 rm_Binormal;
//uniform vec3 rm_Tangent;
//uniform vec4 Tangent;
//uniform vec4 BiNormal;

   
void main(void)
{  //vec3 rm_Tangent = vec3(gl_ModelViewMatrix * Tangent);
   //vec3 rm_Binormal = vec3(gl_ModelViewMatrix * BiNormal);

[b]   vec3 rm_Tangent = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
   vec3 rm_Binormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);	[/b]


   eyeSpacePos = vec3(gl_ModelViewMatrix * gl_Vertex);
   eyeSpaceLight = (gl_ModelViewMatrix * vec4(fvLightPosition ,1.0)).xyz;
                       
   eyeSpaceTangent  = normalize(gl_NormalMatrix * rm_Tangent);
   eyeSpaceBinormal = normalize(gl_NormalMatrix * rm_Binormal);
   eyeSpaceNormal   = normalize(gl_NormalMatrix * gl_Normal);
   
   Texcoord   = gl_MultiTexCoord0.xy;
   
   gl_Position = ftransform();
}
while the light and eye position are given like this in the callback method

Code: Select all

float fvLightPosition [3] = {-100, 30, 1000 }; 
services->setVertexShaderConstant("fvLightPosition",reinterpret_cast<f32*>(&fvLightPosition), 3);
float fvEyePosition [3] = {-0.44587, -0.44587, 100.0 };
services->setVertexShaderConstant("fvEyePosition",reinterpret_cast<f32*>(&fvEyePosition), 3);
Viz_Fuerte
Posts: 91
Joined: Sun Oct 19, 2008 5:29 pm
Location: Valencia (Spain)
Contact:

Post by Viz_Fuerte »

while the light and eye position are given like this in the callback method
Using GLSL is easier to program, and you can use the real position of the light, without having to send the information to the shader.
Always use this: gl_LightSource[0].position.xyz

If you may want, use the code that I have done, so, we took off our problems :D


Parallax.vert

Code: Select all

varying vec3 lightVec; 	
varying vec3 eyeVec;	
 	                     		
void main()	
{

	gl_Position = ftransform();		
	gl_TexCoord[0] = gl_MultiTexCoord0;				

	vec3 n = normalize(gl_NormalMatrix * gl_Normal);
	vec3 t = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
	vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
   	
	vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
	
	vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex;			
	lightVec.x = dot(tmpVec, t);		
	lightVec.y = dot(tmpVec, b);		
	lightVec.z = dot(tmpVec, n);			
	tmpVec = -vVertex;
	eyeVec.x = dot(tmpVec, t);		
	eyeVec.y = dot(tmpVec, b);		
	eyeVec.z = dot(tmpVec, n);
}
Parallax.frag

Code: Select all

varying vec3 lightVec;	
varying vec3 eyeVec;	
	
uniform sampler2D colorMap;	
uniform sampler2D normalMap;
uniform sampler2D heightMap;
	
// This is the radius of the light (1.0/radius)
const float invRadius = 1.0/1024;

void main()	
{		
	float distSqr = dot(lightVec, lightVec);		
	float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);		
	vec3 lVec = lightVec * inversesqrt(distSqr);
		
	vec3 vVec = normalize(eyeVec);

	float height = texture2D(heightMap, gl_TexCoord[0].xy).r;
	height = height * 0.05 + -0.05;/// BUMPSIZE + , -
	vec2 newUV = gl_TexCoord[0].xy + vVec.xy * height;
				
	vec4 base = texture2D(colorMap,newUV);	
	vec3 bump = normalize(texture2D(normalMap,newUV.xy).rgb * 2.0 - 1.0);	

	vec4 vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
		
	float diffuse = max( dot(lVec, bump), 0.0 );		
	vec4 vDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * diffuse;	
		
	float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), gl_FrontMaterial.shininess );		
	vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular *specular;	
	
	gl_FragColor = (vAmbient*base + vDiffuse*base + vSpecular*base) * att;
}
This code works without problems :wink:

PD: In the future, I recommend using this program: Shader Maker
http://cg.in.tu-clausthal.de/publications.shtml

It's small but powerful, is that I use to program in GLSL and it works very well.
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Post by Viking86 »

Thank you very much, If you are ever in croatia (or I in spain) you have a drink on me :)

But I was trying to implement relief mapping, not parallax mapping :)
The fragment shader is long :)

Code: Select all

uniform vec4 fvAmbient;
uniform vec4 fvSpecular;
uniform vec4 fvDiffuse;
uniform float fSpecularPower;

uniform sampler2D baseMap;
uniform sampler2D reliefMap;

uniform float depth;
uniform float tile;
//uniform int linear_search_steps; min 11
//uniform int binary_search_steps; min 5

varying vec2 Texcoord;   
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
varying vec3 eyeSpaceLight;
varying vec3 eyeSpacePos;


float ray_intersect_rm(in vec2 dp,in vec2 ds);

void main(void)
{
   vec4 relief,color;
   vec3 t_eyeSpacePos,norm_eyeSpacePos,l,viewRay, lightRay;
   vec2 dp,ds,uv;
   float realDepth,a;

   // ray intersect in view direction
   t_eyeSpacePos  = eyeSpacePos;
   norm_eyeSpacePos  = normalize(t_eyeSpacePos);
   a  = dot(eyeSpaceNormal,-norm_eyeSpacePos);
   viewRay  = normalize(vec3(dot(norm_eyeSpacePos,eyeSpaceTangent),dot(norm_eyeSpacePos,eyeSpaceBinormal),a));
   viewRay  *= depth/a;
   dp = Texcoord*tile;
   ds = viewRay.xy;
   realDepth  = ray_intersect_rm(dp,ds);
   
   // get rm and color texture points
   uv=dp+ds*realDepth;
   relief=texture2D(reliefMap,uv);
   color=texture2D(baseMap,uv);

   // expand normal from normal map in local polygon space
   relief.xy=relief.xy*2.0-1.0;
   relief.z=sqrt(1.0-dot(relief.xy,relief.xy));
   relief.xyz=normalize(relief.x*eyeSpaceTangent+relief.y*eyeSpaceBinormal+relief.z*eyeSpaceNormal);

   // compute light direction
   t_eyeSpacePos += norm_eyeSpacePos*realDepth*a;
   l=normalize(t_eyeSpacePos-eyeSpaceLight.xyz);
   
   // ray intersect in light direction
   dp+= ds*realDepth;
   a  = dot(eyeSpaceNormal,-l);
   lightRay  = normalize(vec3(dot(l,eyeSpaceTangent),dot(l,eyeSpaceBinormal),a));
   lightRay *= depth/a;
   ds = lightRay.xy;
   dp-= ds*realDepth;
   float dl = ray_intersect_rm(dp,ds);
   float shadow = 1.0;
   vec3 specular_shadow=fvSpecular.xyz;
   if (dl<realDepth-0.05) // if pixel in shadow
   {
      shadow=dot(fvAmbient.xyz,vec3(1.0))*0.333333;
      specular_shadow=vec3(0.0);
   }

   // compute diffuse and specular terms
   float att=max(0.0,dot(-l,eyeSpaceNormal));
   float diff=shadow*max(0.0,dot(-l,relief.xyz));
   float spec=max(0.0,dot(normalize(-l-norm_eyeSpacePos),relief.xyz));

   // compute final color
   vec4 finalcolor;
   finalcolor.xyz=fvAmbient.xyz*color.xyz+
      att*(color.xyz*fvDiffuse.xyz*diff+specular_shadow*pow(spec,fSpecularPower));
   finalcolor.w=1.0;   
   gl_FragColor = vec4(finalcolor.rgb,1.0);
   
}

float ray_intersect_rm(in vec2 dp, in vec2 ds)
{
   const int linear_search_steps=11;
   const int binary_search_steps=6;
   float depth_step=1.0/float(linear_search_steps);

   // current size of search window
   float size=depth_step;
   // current depth position
   float depth=0.0;
   // best match found (starts with last position 1.0)
   float best_depth=1.0;

   // search front to back for first point inside object
   for( int i=0;i<linear_search_steps-1;i++ )
   {
      depth+=size;
      vec4 t=texture2D(reliefMap,dp+ds*depth);

      if (best_depth>0.996)   // if no depth found yet
      if (depth>=t.w)
         best_depth=depth;   // store best depth
   }
   depth=best_depth;
   
   // recurse around first point (depth) for closest match
   for( int i=0;i<binary_search_steps;i++ )
   {
      size*=0.5;
      vec4 t=texture2D(reliefMap,dp+ds*depth);
      if (depth>=t.w)
      {
         best_depth=depth;
         depth-=2.0*size;
      }
      depth+=size;
   }

   return best_depth;
}
and the vertex i posted before (with this i get the last pictures i posted)

Code: Select all

uniform vec3 fvLightPosition;
uniform vec3 fvEyePosition;

varying vec2 Texcoord;
varying vec3 eyeSpacePos;
varying vec3 eyeSpaceLight;
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
   
//uniform vec3 rm_Binormal;
//uniform vec3 rm_Tangent;
//uniform vec4 Tangent;
//uniform vec4 BiNormal;

   
void main(void)
{  //vec3 rm_Tangent = vec3(gl_ModelViewMatrix * Tangent);
   //vec3 rm_Binormal = vec3(gl_ModelViewMatrix * BiNormal);

   vec3 rm_Tangent = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
   vec3 rm_Binormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);	
	

   eyeSpacePos = vec3(gl_ModelViewMatrix * gl_Vertex);
   eyeSpaceLight = (gl_ModelViewMatrix * vec4(fvLightPosition ,1.0)).xyz;
                       
   eyeSpaceTangent  = normalize(gl_NormalMatrix * rm_Tangent);
   eyeSpaceBinormal = normalize(gl_NormalMatrix * rm_Binormal);
   eyeSpaceNormal   = normalize(gl_NormalMatrix * gl_Normal);
   
   Texcoord   = gl_MultiTexCoord0.xy;
   
   gl_Position = ftransform();
}
The data i use is here http://rapidshare.com/files/383489314/N ... 2_.7z.html
(the normalmap has the heightmap in the alpha chanell Photoshop ftw)

I found the shader creator but it wont start on my pc for some reason :/
It runs on the laptop but relief mapping is cpu intensive so it runs at 1fps if it doesen't crash the system. I use rendermonkey for shader editing


p.s your code runs fine but i get this (i only pass the textures to the shader since they are the only uniform vars )
http://www.imagesforme.com/show.php/111 ... oard01.jpg
Viz_Fuerte
Posts: 91
Joined: Sun Oct 19, 2008 5:29 pm
Location: Valencia (Spain)
Contact:

Post by Viz_Fuerte »

Thank you very much, If you are ever in croatia (or I in spain) you have a drink on me
OMG That is done :wink:

The relief mapping, is somewhat slow (or too slow).
The alternative that looks like "something", is the Parallax occlusion mapping but it is another thing.

Your code is an example that brings the Shader Designer of TyphoonLabs 8)
The only thing to do is change the line attributes, as I said earlier.

Relief.vert

Code: Select all

varying vec2 texCoord;
varying vec3 eyeSpaceVert;
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
varying vec3 eyeSpaceLight;

void main(void)
{ 
   eyeSpaceVert = (gl_ModelViewMatrix * gl_Vertex).xyz;
   eyeSpaceLight = (gl_ModelViewMatrix * vec4(gl_LightSource[0].position.xyz,1.0)).xyz;
   
   eyeSpaceTangent  = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
   eyeSpaceBinormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
   eyeSpaceNormal   = gl_NormalMatrix * gl_Normal;
   
   texCoord   = gl_MultiTexCoord0.xy;
   
   gl_Position = ftransform();
}
In the code of Relief.frag, must be left as is and add the corresponding values, if not done so, will not work.

I test the code and it works perfectly, a bit slow, but it works.
Viking86
Posts: 24
Joined: Tue Apr 20, 2010 2:29 pm

Post by Viking86 »

Viz_Fuerte wrote:
Thank you very much, If you are ever in croatia (or I in spain) you have a drink on me
OMG That is done :wink:

The relief mapping, is somewhat slow (or too slow).
The alternative that looks like "something", is the Parallax occlusion mapping but it is another thing.

Your code is an example that brings the Shader Designer of TyphoonLabs 8)
The only thing to do is change the line attributes, as I said earlier.

Relief.vert

Code: Select all

varying vec2 texCoord;
varying vec3 eyeSpaceVert;
varying vec3 eyeSpaceTangent;
varying vec3 eyeSpaceBinormal;
varying vec3 eyeSpaceNormal;
varying vec3 eyeSpaceLight;

void main(void)
{ 
   eyeSpaceVert = (gl_ModelViewMatrix * gl_Vertex).xyz;
   eyeSpaceLight = (gl_ModelViewMatrix * vec4(gl_LightSource[0].position.xyz,1.0)).xyz;
   
   eyeSpaceTangent  = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
   eyeSpaceBinormal = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
   eyeSpaceNormal   = gl_NormalMatrix * gl_Normal;
   
   texCoord   = gl_MultiTexCoord0.xy;
   
   gl_Position = ftransform();
}
In the code of Relief.frag, must be left as is and add the corresponding values, if not done so, will not work.

I test the code and it works perfectly, a bit slow, but it works.
Thank you, could you post the shadercallback code, as I said ShaderDesigner wont start on my pc, so im not sure on the required values of the uniform variables.

Can you post a screenshot how it looks like on your pc :)?
Post Reply