Page 1 of 1

[Solved!] Highlights in wrong places.

Posted: Mon Nov 17, 2008 4:59 pm
by Mel
I've started messing with shaders, and i've found some troubles. To be honest, i'm quite a newbee in the shader programming tasks, so, i simply am cluesless. The shading highlights aren't where they're suposed to be, but the shader works, more or less, right. It is taken and a bit modified directly from the Render Monkey shader tool.

Anyone see something out of place in the shaders, or in the code?

to make a graphical explanation of this:

Image


Here, we see that there should be a little of highlights in the tigh, perhaps but there isn't.

Image

And in this image the light is behind the models, so, little, or no highlight should be present, and there they are.

I've tried some combinations, and none of them gave a satisfactory result, this is the closest stage to what a good phong shader should be, IMO, so, if anyone who knew about shaders a bit could take a peek and say what would be out of place, would be a great help. Thanks!

This is the code.

Code: Select all

#include <iostream>
#include <irrlicht.h>

#pragma comment(lib, "Irrlicht.lib")

using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

//a small and pointy tweak, using the "user data" i give the callback full access to all the irrlicht device :)
//god bless that pointers are still good ol' 32 bits integers ^O^

class bumpPhongCNS : public IShaderConstantSetCallBack{
      public:
      virtual void  OnSetConstants (IMaterialRendererServices *services, s32 userData){

              IrrlichtDevice *dev=(IrrlichtDevice *) userData;
              
              matrix4 matViewProjection=dev->getSceneManager()->getActiveCamera()->getProjectionMatrix();
              matViewProjection*=dev->getVideoDriver()->getTransform(ETS_VIEW);
              matViewProjection*=dev->getVideoDriver()->getTransform(ETS_WORLD);
              
              vector3df lightPos = vector3df(100,100,100);
              
              services->setVertexShaderConstant("fvLightPosition",reinterpret_cast<f32*>(&lightPos),3);
              vector3df camPos = dev->getSceneManager()->getActiveCamera()->getPosition();
              services->setVertexShaderConstant("fvEyePosition",reinterpret_cast<f32*>(&camPos),3);
 
              matrix4 matView=dev->getSceneManager()->getActiveCamera()->getProjectionMatrix();
              matView*=dev->getVideoDriver()->getTransform(ETS_WORLD);
              
              services->setVertexShaderConstant("matView",&matView[0],16);
              services->setVertexShaderConstant("matViewProjection",&matViewProjection[0],16);
              
              SColorf lightAmbient = SColorf(.1,.1,.1,1);
              services->setPixelShaderConstant("fvAmbient",reinterpret_cast<f32*>(&lightAmbient),4);
              SColorf lightDiffuse = SColorf(1,1,1,1);
              services->setPixelShaderConstant("fvDiffuse",reinterpret_cast<f32*>(&lightDiffuse),4);
              
              float specularPower = 25;
              services->setPixelShaderConstant("fSpecularPower",reinterpret_cast<f32*>(&specularPower),1);

              return;
      }
};

int main(int argc, char *argv[])
{

//We create a small direct3d9 device...

IrrlichtDevice *device=0;
ISceneManager *smgr=0;
IVideoDriver *driver=0;
IAnimatedMeshSceneNode *uni=0;
IAnimatedMeshSceneNode *uni2=0;
ISkinnedMesh *uniMesh=0;
IGPUProgrammingServices *gpu=0;
s32 material;
ICameraSceneNode *camara=0;

bumpPhongCNS *cons = new bumpPhongCNS();

device = createDevice(EDT_DIRECT3D9 , dimension2d<s32>(1024, 768),32,false,true,false,0);

if(device){

  smgr=device->getSceneManager();
  driver=device->getVideoDriver();
  
  if(!smgr||!driver){ exit(1);}

//add a camera, two lights

  camara=smgr->addCameraSceneNodeMaya();
  
  camara->setPosition(vector3df(0,1,3));
    
  smgr->addLightSceneNode(0, 
      vector3df(100, 100, 100),  
      SColorf(1, 1, 1),
      2000);
  smgr->addLightSceneNode(0, 
      vector3df(-100, -100, -100),  
      SColorf(.5,.5,.5),
      2000);


//We load a tiny cool mesh, perhaps Uni.

gpu = driver->getGPUProgrammingServices();

//We load the Shader...
//While it doesn't blow up, experiments are welcome! ^^

material = gpu->addHighLevelShaderMaterialFromFiles  (  
  "./datos/BumpPhongV.hlsl",  
  "vs_main",  
  EVST_VS_2_0,  
  "./datos/BumpPhongP.hlsl",  
  "ps_main",  
  EPST_PS_2_0,  
  cons,  
  EMT_SOLID,
  (s32)device
 ); 


uniMesh = (ISkinnedMesh *) smgr->getMesh("./datos/uni.X");
uniMesh->convertMeshToTangents();

if (uniMesh){
  uni = smgr->addAnimatedMeshSceneNode(uniMesh);
}

uni->setMaterialTexture(1,driver->getTexture("./datos/base.body.universe.normals.png"));
uni->getMaterial(0).MaterialType=(E_MATERIAL_TYPE)material;
uni->getMaterial(1).MaterialType=(E_MATERIAL_TYPE)material;
uni->getMaterial(2).MaterialType=(E_MATERIAL_TYPE)material;
uni->getMaterial(3).MaterialType=(E_MATERIAL_TYPE)material;

uni2=smgr->addAnimatedMeshSceneNode(uniMesh);

uni->setPosition(vector3df(-1,0,0));
uni2->setPosition(vector3df(1,0,0));

//We try to put shaders a go go!


  device->getCursorControl()->setVisible(false);
  
  int lastFPS;
  
  while(device->run()){
  
    driver->beginScene(true,true,SColor(0,64,128,160));
    smgr->drawAll();
    driver->endScene();
    
    int fps = driver->getFPS();

		if (lastFPS != fps)
		{
		  core::stringw str = L"PixelShader tests [";
		  str += driver->getName();
		  str += "] FPS:";
		  str += fps;
		  device->setWindowCaption(str.c_str());
		  lastFPS = fps;
		}
  
  }

}
//And That's all folks! :)
return 0;
}


Code: Select all


/////Vertex Shader/////////////////////////////////

float3 fvLightPosition;
float3 fvEyePosition;
float4x4 matView;
float4x4 matViewProjection;

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 LightDirection:   TEXCOORD2;
   
};

VS_OUTPUT vs_main( VS_INPUT Input )
{
   VS_OUTPUT Output;

   Output.Position         = mul( Input.Position, matViewProjection );
   Output.Texcoord         = Input.Texcoord;
   
   float3 fvObjectPosition = mul( Input.Position, matView );
   
   float3 fvViewDirection  = fvEyePosition - fvObjectPosition;
   float3 fvLightDirection = fvLightPosition - fvObjectPosition ;
     
   float3 fvNormal         = mul( Input.Normal, matView );
   float3 fvBinormal       = mul( Input.Binormal, matView );
   float3 fvTangent        = mul( Input.Tangent, matView );
      
   Output.ViewDirection.x  = dot( fvTangent, fvViewDirection );
   Output.ViewDirection.y  = dot( fvBinormal, fvViewDirection );
   Output.ViewDirection.z  = dot( fvNormal, fvViewDirection );
   
   Output.LightDirection.x  = dot( fvTangent, fvLightDirection );
   Output.LightDirection.y  = dot( fvBinormal, fvLightDirection );
   Output.LightDirection.z  = dot( fvNormal, fvLightDirection );
   
   return( Output );
   
}

Code: Select all

//////Pixel Shader//////////////////////////////////////////////

float4 fvAmbient;
float4 fvDiffuse;
float4 fvLightColor;
float fSpecularPower;

sampler2D baseMap;
sampler2D bumpMap;

struct PS_INPUT 
{
   float2 Texcoord :        TEXCOORD0;
   float3 ViewDirection :   TEXCOORD1;
   float3 LightDirection:   TEXCOORD2;
   
};

float4 ps_main( PS_INPUT Input ) : COLOR0
{      
   float3 fvLightDirection = normalize( Input.LightDirection );
   float3 fvNormal         = normalize( ( tex2D( bumpMap, Input.Texcoord ).xyz * 2.0f ) - 1.0f );
   float  fNDotL           = dot( fvNormal, fvLightDirection ); 
   
   float3 fvReflection     = normalize( ( ( 2.0f * fvNormal ) * ( fNDotL ) ) - fvLightDirection ); 
   float3 fvViewDirection  = normalize( Input.ViewDirection );
   float  fRDotV           = max( 0.0f, dot( fvReflection, fvViewDirection ) );
   
   float4 fvBaseColor      = tex2D( baseMap, Input.Texcoord );
   
   float4 fvTotalAmbient   = fvAmbient * fvBaseColor; 
   float4 fvTotalDiffuse   = fvDiffuse * fNDotL * fvBaseColor ;
   float4 fvTotalSpecular  = tex2D( baseMap, Input.Texcoord ) * pow( fRDotV, fSpecularPower ) ;
   
   return( saturate( fvTotalAmbient + fvTotalDiffuse + fvTotalSpecular ) );
      
}

Posted: Mon Nov 17, 2008 8:59 pm
by BlindSide

Code: Select all

matrix4 matView=dev->getSceneManager()->getActiveCamera()->getProjectionMatrix();
              matView*=dev->getVideoDriver()->getTransform(ETS_WORLD);
             
              services->setVertexShaderConstant("matView",&matView[0],16)
What is this? You are supposed to pass the view matrix, not the "world projection" (If there is such a thing :P , I've never seen world and projection being used together...)

That aside, bumpmapping can be a bit tricky to get right and so can specular highlights. I suggest starting from scratch with a basic phong lighting shader so you can wrap your head around the concept easier. There are tons of hlsl tutorials on the net for writing phong lighting shaders. This one looks pretty nice at a glance.

EDIT: Ignore the "technique blocks" thing at the end of tutorial I linked, it's irrelevant.

Posted: Mon Nov 17, 2008 9:03 pm
by dlangdev
And in this image the light is behind the models, so, little, or no highlight should be present, and there they are.
Yeah, i know what u mean there. I've seen that show-up in my demo as well. It's annoying as hell to see that show-up and mess-up the render.

I think it's because there is a missing piece of code that should calculate for some kind of raycasting to eliminate that light passing through fragments.

Anyway, I don't know the solution, though I tried writing one up in RenderMonkey but got nowhere with it.

Try playing around with NdotL and see if will take you near a soultion.

Also see if you can calculate for the umbra/penumbra and test if the eye is inside them, then return a different lightvalue.

Posted: Mon Nov 17, 2008 9:29 pm
by dlangdev
Wait, I should've added this one but there is one solution you can use.

Have you heard of specular map? A texture map containing specular values? They should--at least--take you nearer to the solution.

Or....

Try using an environment map, that one you should not miss. It's awesome!

Posted: Tue Nov 18, 2008 5:30 pm
by Mel
Yeah, i know, but i also want normal mapping, so, the reflections may show a good bumping on them. In fact that is a trick i've used tons of times :) And without the proper shader, it doesn't show well.

@BlindSide. Curious, isn't it? but if i didn't set the matrices like that, the model wouldn't move from 0,0,0. I'll try what you put, thanks!

Posted: Wed Nov 19, 2008 11:33 am
by Mel
I tried the shaders you recomended me BlindSide, and the result is that it works much better than the rendermonkey ones. The only trouble i have now is that it seem like the effect won't move from the origin of the world, no matter what i do, works for positive angles of light, but don't for negatives... I'm not sure of what goes wrong, but i'm sure it has to see with the callback when setting the constants. Any idea to this newbee in shader programation? ^^U Thanks!

Code: Select all

class bumpPhongCNS : public IShaderConstantSetCallBack{
      public:
      virtual void  OnSetConstants (IMaterialRendererServices *services, s32 userData){

              IrrlichtDevice *dev=(IrrlichtDevice *) userData;
              ISceneManager *smgr=dev->getSceneManager();
//Vertex Shader constants.
              matrix4 matViewProjection=dev->getSceneManager()->getActiveCamera()->getProjectionMatrix();
              matViewProjection*=dev->getVideoDriver()->getTransform(ETS_VIEW);
              matViewProjection*=dev->getVideoDriver()->getTransform(ETS_WORLD);
              services->setVertexShaderConstant("matWorldViewProj",&matViewProjection[0],16);
              matrix4 matWorldInverseTranspose=dev->getVideoDriver()->getTransform(ETS_WORLD);
              services->setVertexShaderConstant("matWorld",&matWorldInverseTranspose[0],16);                            
              matWorldInverseTranspose = matWorldInverseTranspose.getTransposed();
              matWorldInverseTranspose.makeInverse();
              services->setVertexShaderConstant("matWorldIT",&matWorldInverseTranspose[0],16);           

              vector3df camPos = dev->getSceneManager()->getActiveCamera()->getPosition();
              services->setVertexShaderConstant("viewPosition",reinterpret_cast<f32*>(&camPos),3);

//pixel Shader constants.

              vector3df lightDir = smgr->getSceneNodeFromName("Uni")->getPosition()-
                                   smgr->getSceneNodeFromName("luz")->getPosition();
              services->setPixelShaderConstant("dirLightDir",reinterpret_cast<f32*>(&lightDir),3);
              vector3df lightColor = vector3df(0.75,.85,1);//color en formato flotante
              services->setPixelShaderConstant("dirLightColor",reinterpret_cast<f32*>(&lightColor),3);

              return;
      }
};

//PixelShader

// Light direction global-level semantic
float3 dirLightDir;
float3 dirLightColor;

struct PS_INPUT {
	float4 position : POSITION0;
	float2 texCoord : TEXCOORD0;
	float3 normal : TEXCOORD1;
	float3 view : TEXCOORD2;
};

sampler2D baseMap;
sampler2D bumpMap;
 
// Pixel Shader Function
float4 ps_main(PS_INPUT IN) : COLOR {
       
	// Normalize all vectors in pixel shader to get phong shading
	// Normalizing in vertex shader would provide gouraud shading

	float3 light = normalize(-dirLightDir);
	float3 view = normalize(IN.view);
	float3 normal = normalize(IN.normal);
    
    normal= normalize(normal + (tex2D( bumpMap, IN.texCoord ).xyz*2.0)-1.0 );
           
	// Calculate the half vector
	float3 halfway = normalize(light + view);

    float2 texCoord = IN.texCoord;
    float4 texColor = tex2D(baseMap, texCoord);

    float3 emissive = 0.5;
 
	// Calculate the ambient reflection
 
    float3 ambient = 0.1*texColor;
 
	// Calculate the diffuse reflection
 
    float3 diffuse = saturate(dot(light,normal)) * texColor.rgb;
 
    float3 specular = pow(saturate(dot(normal, halfway)),25.0) * texColor.rgb;
 
	// Calculate the specular reflection

	float3 color = saturate(ambient + diffuse + specular) * dirLightColor;

	float alpha = 1.0;
	return float4(color, alpha);
}

//VertexShader

float4x4 matWorldViewProj;
float4x3 matWorldIT;
float4x4 matWorld;
float3 viewPosition;

struct VS_INPUT {
	float4 position : POSITION0;
	float3 normal : NORMAL0;
	float2 texCoord : TEXCOORD0;
};
 

struct VS_OUTPUT {
	float4 position : POSITION0;
	float2 texCoord : TEXCOORD0;
	float3 normal : TEXCOORD1;
	float3 view : TEXCOORD2;
};

#define	PS_INPUT VS_OUTPUT
 

VS_OUTPUT vs_main(VS_INPUT IN) {
	VS_OUTPUT OUT;

	OUT.position = mul(IN.position, matWorldViewProj);

	OUT.texCoord = IN.texCoord;

    OUT.normal = mul(matWorldIT, IN.normal);
    
	float3 worldPos = mul(IN.position, matWorld).xyz;
	OUT.view = viewPosition - worldPos;
 
	return OUT;
}

Posted: Wed Nov 19, 2008 3:32 pm
by BlindSide
First, just pass the absolute position of the light, you don't need to do object - lightPosition (Or whatever you are doing). Second, transform the like position using the inverse world matrix like so:

Code: Select all

vector3df lightPosition = light->getPosition();
matrix4 invWorld;
driver->getTransform(ETS_WORLD).getInverse(invWorld);
invWorld.transformVect(lightPosition); // Or is it transformVec, can't remember off the top of my head.
Then just pass lightPosition as the shader constant. There might be other problems here but you should get this sorted out first.

Cheers

EDIT: No wait a second, you need to pass in the light position, not direction, and then subtract the vertex position (In world space, you get this by passing ETS_WORLD then multiplying with the stock vertex position), then normalize that vector to get the light direction. Check out the phong shader in XEffects, I admit it's messy (Since I nabbed it off the NVidia shader library aaages ago), but it should be a good reference point to learn from.

Posted: Wed Nov 19, 2008 8:21 pm
by Mel
I'll try it then :) A question you may know, or may not... but i'm curious. Why are needed the binormal vectors and the Tangent vectors for normal mapping? takin in consideration normal maps, those, besides the normals are the only needed to achieve the lighting effect, right?

Posted: Wed Nov 19, 2008 10:30 pm
by dlangdev
From what I read, the space needs to shift to tangent space, which means a matrix is needed, though not all of them use tangent matrix.

Posted: Thu Nov 20, 2008 4:03 pm
by Mel
I wish i knew... very good news!

Image

Not only i have ended a good looking phong shader, also, i've added it fresnel reflections! ^^

After taking a peek to blindside's shaders, i found some very interesting information, and a trick i didn't know. x and y components of a normal vector could be used to place a non cube reflection map in the model ;) His phong shader was... all messed up. But i took the reflection idea from what he had done. Also, took his variable settings, assuming they were written right, and modified them a bit to rewrite the shader i tried last time. And that is the result! :)

I will leave this here for the people who wants to see how it works, source and shaders included.

http://rapidshare.com/files/165674054/S ... resnel.rar

Thank you very much for your great help! :)

Posted: Wed Nov 26, 2008 3:20 am
by BlindSide
His phong shader was... all messed up.
Yeah I got it a few years ago from the NVidia shader library and didn't bother cleaning it up. The screenshot looks nice.

Posted: Wed Nov 26, 2008 10:00 pm
by Mel
Thanks! Maybe it doesn't have a BumpMap, but it would work really nice for a car paint, perhaps, it could be modified so it interpolated with the normal 2 colours, and then, use it to create more effects. or perhaps, translucency, fake SSS effects.

Posted: Fri Dec 24, 2010 3:12 pm
by jiedi123
Mel wrote:I wish i knew... very good news!

Image

Not only i have ended a good looking phong shader, also, i've added it fresnel reflections! ^^

After taking a peek to blindside's shaders, i found some very interesting information, and a trick i didn't know. x and y components of a normal vector could be used to place a non cube reflection map in the model ;) His phong shader was... all messed up. But i took the reflection idea from what he had done. Also, took his variable settings, assuming they were written right, and modified them a bit to rewrite the shader i tried last time. And that is the result! :)

I will leave this here for the people who wants to see how it works, source and shaders included.

http://rapidshare.com/files/165674054/S ... resnel.rar

Thank you very much for your great help! :)

Its cant download; (File not found.)
can you send to me
my email is xiacaojun@gmail.com
thanks