light problems with normal maps

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
HydroNom
Posts: 7
Joined: Thu Jul 10, 2008 8:16 am

light problems with normal maps

Post by HydroNom »

Hello,

I have a problem with lighting of an object using normal maps. I try to create a planet which got it's light from a star. When I use EMT_SOLID as material type, then everything is fine. I can rotate the planet and it looks as it should be. The picture below shows some following frames captured:

Image

When I'm using normal or parallax mapping, the light seems to be fixed to a static point on the object surface. When I rotate the planet, the light is moving. When the planet rotates to 180°, the planet is black as I would look to the back side. Then it switches to completely enlighted at next frame. See the next picture:

Image

I only rotate the planet. Camera and light is not moving!

The code is not difficult:

Code: Select all

    vector3df vPPos = vector3df(-120000,102000,-100000);
    ISceneNode *pEarth = smgr->addSphereSceneNode(71500,64,NULL,10,vPPos);
    pEarth->setMaterialTexture(0, driver->getTexture("media/earthmap1k.jpg"));

    video::ITexture* normalMap = driver->getTexture("media/earthbump1k.jpg");
	driver->makeNormalMapTexture(normalMap, 20.0f);
    pEarth->setMaterialTexture(1, normalMap);

    pEarth->setMaterialType(video::EMT_NORMAL_MAP_SOLID);
    scene::ISceneNodeAnimator* anim =
        smgr->createRotationAnimator(core::vector3df(0,0.5f,0));
    pEarth->addAnimator(anim);
    anim->drop();

    ICameraSceneNode *pCam = smgr->addCameraSceneNode(0, core::vector3df(0,0,0), vPPos, 3);
    pCam->setFarValue(3000000);

    scene::ILightSceneNode* light1 = smgr->addLightSceneNode(0, core::vector3df(4000000,0,0),video::SColorf(1.0f, 1.0f, 0.9f, 1.0f), 20000000.0f, 2);
I tried this also with more smaller numbers (planet size of 200), but the effect is the same. What's wrong there?
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

yeah i noticed the same problem thats why i had to write my own parallax shader.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
HydroNom
Posts: 7
Joined: Thu Jul 10, 2008 8:16 am

Post by HydroNom »

Hm, do you know where the problem is located? In the PerPixelLighting example there is a similar scene, where this problem seems not to be present.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The sphere scene node is not using tangent meshes, so you cannot apply the shaders directly. You have to convert the sphere into the proper mesh format first.
HydroNom
Posts: 7
Joined: Thu Jul 10, 2008 8:16 am

Post by HydroNom »

But when I copy the earth sphere code from the example to my testing app, I got the same effect, an this uses tangent meshes???
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

Code: Select all

IAnimatedMesh* mesh = smgr->getMesh("sampleMesh.b3d");
scene::IMesh* tangentMesh = smgr->getMeshManipulator()->createMeshWithTangents(mesh->getMesh(0));
node  = smgr->addMeshSceneNode(tangentMesh);

Image
HydroNom
Posts: 7
Joined: Thu Jul 10, 2008 8:16 am

Post by HydroNom »

Yes, this is what I have done. But I discovered another reason of this problem, because this behaviour occurs with the OpenGL driver also with tangent meshes (I had my example on OpenGL for a test). When I switch to DirectX, everything is working...
LoneKiltedNinja
Posts: 4
Joined: Wed Sep 24, 2008 5:39 am

Post by LoneKiltedNinja »

Alright. This is exactly the issue I'm running into, and it's driving me nuts, and I could really use an OpenGL solution since for my particular project (NDA, sorry) DirectX isn't going to be an option.

Obviously OpenGL can handle things correctly, as evidenced by Per Pixel Lighting example 11. But like HydroNom, I've tried dropping the exact same earth model with the exact same normal map into my own project, running the mesh through the tangent generator as suggested here and performed in the example, and it still lights as if the light is attached to and/or counter-rotating about the model. Parallax distortion may also be going a little screwy.

I've tried playing with all the differences I can find between my code and the example code (fixed vs FPS camera, point vs directional light, sphere mesh vs loaded model with and without creating tangent mesh, 1 light vs 2 lights, scale & distance, fog vs no, event receiver vs no, order of instantiating camera/lights/models, even enabling EMF_NORMALIZE_NORMALS on the material) to no avail. Can anyone think of any other important factors in getting the stock shaders working correctly?

Edit: I even dropped my for-real model into the working example and it lit just fine even without running it through the tangent generator (high-end high-poly Maya obj, it probably has the tangents already). There's something I'm obviously not quite catching, but I could swear I've been through the example code, line by line, at least 5 times :P

I'll keep poking, and post the solution if I find it, but until then any help would be greatly appreciated.

Edit2: For the nonbelievers, here's a stripped down example demonstrating the problem. rainbow.png could really be anything, earthbump.bmp and earth.x are as provided in the examples, the whole thing is basically the Hello World example with parallax added. And the problem persists regardless of whether everything is parented to a root dummy node or to 0. If anyone bothers to run this on their own, thank you in advance, and if it actually works correctly on your machine under OpenGL, I'll be quite curious to know, since that means it does actually boil down to an OpenGL implementation issue that the stock parallax example somehow unintentionally circumvents...

Code: Select all

int main()
{
	video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

	printf("Please select the driver you want for this example:\n"\
		" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
		" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
		" (f) NullDevice\n (otherKey) exit\n\n");

	char i;
	std::cin >> i;

	switch(i)
	{
		case 'a': driverType = video::EDT_DIRECT3D9;break;
		case 'b': driverType = video::EDT_DIRECT3D8;break;
		case 'c': driverType = video::EDT_OPENGL;   break;
		case 'd': driverType = video::EDT_SOFTWARE; break;
		case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
		case 'f': driverType = video::EDT_NULL;     break;
		default: return 0;
	}

	IrrlichtDevice *device = createDevice( driverType, core::dimension2d<s32>(640, 480), 16,
			false, false, false, 0);
	device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");

	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();
	gui::IGUIEnvironment* guienv = device->getGUIEnvironment();

	guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
		core::rect<s32>(10,10,260,22), true);

	driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
	video::E_MATERIAL_TYPE type = video::EMT_PARALLAX_MAP_SOLID;
	// set up for parallax, etc.
     video::IMaterialRenderer* renderer = driver->getMaterialRenderer(type);
	if (renderer && renderer->getRenderCapability() != 0){
          cout<<"Can't do parallax mapping on this hardware."<<endl;
          type = video::EMT_NORMAL_MAP_SOLID;
          renderer = driver->getMaterialRenderer(type);
     }
     if (renderer && renderer->getRenderCapability() != 0){
          cout<<"Can't even do normal mapping."<<endl;
          type = video::EMT_SOLID;
          renderer = driver->getMaterialRenderer(type);
     }

     scene::ISceneNode *root = smgr->addEmptySceneNode();

     scene::ILightSceneNode *light1 =
		smgr->addLightSceneNode(root, core::vector3df(0,30,-40),
		video::SColorf(0.8f,0.8f,0.8f,0.0f), 500.0f);

     //scene::IAnimatedMesh *sphereMesh = smgr->addSphereMesh("",5,16,16);
     scene::IAnimatedMesh *sphereMesh = smgr->getMesh("earth.x");
     scene::IMeshManipulator *manipulator = smgr->getMeshManipulator();
	scene::IMesh *tangentMesh = manipulator->createMeshWithTangents(sphereMesh->getMesh(0));
	scene::IMeshSceneNode* node2 = smgr->addMeshSceneNode(
          tangentMesh,
          root,//parent
          -1,//id
          core::vector3df(0,25,-20),//position
          core::vector3df(0,180,0),//rotation
          core::vector3df(1,1,1),//scale
          false); // still add if mesh pointer NULL
     node2->setMaterialType(type); // set the type for all materials
     node2->getMaterial(0).setTexture(0, driver->getTexture("rainbow.png"));
     video::ITexture* normalMap = driver->getTexture("earthbump.bmp");
	driver->makeNormalMapTexture(normalMap, 1.0f);
     node2->getMaterial(0).setTexture(1, normalMap);
     node2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
     
     scene::ISceneNodeAnimator* anim =
         smgr->createRotationAnimator(core::vector3df(0,0.2f,0));
     node2->addAnimator(anim);
     anim->drop();


	smgr->addCameraSceneNode(root, core::vector3df(0,30,-40), core::vector3df(0,5,0));

	while(device->run())
	{
		driver->beginScene(true, true, video::SColor(255,100,101,140));

		smgr->drawAll();
		guienv->drawAll();

		driver->endScene();
	}

	device->drop();

	return 0;
}
Post Reply