Hiding the sphere with "ghost" object...

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
hbraun
Posts: 28
Joined: Tue Dec 16, 2008 7:33 pm
Location: Porto Alegre, Brazil
Contact:

Hiding the sphere with "ghost" object...

Post by hbraun »

Hi Folks,

I want your help and thoughts :)

I intend to make a flying sphere to be occluded by an invisible (transparent) cube.
But I´ve tried a helluva of things and its still not working.
The idea was to write on the ZBuffer with the transparent cube, so when the sphere are actually behind the transparent cube, it would only render the background and other objects.

Or maybe using ColorMask for hiding the cube...

Here is some not working coding:

Code: Select all

driver->setAllowZWriteOnTransparent( true );		smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);	
	IMeshSceneNode *cubeNode1 = smgr->addCubeSceneNode(10);
	cubeNode1->setPosition( core::vector3df( 0, 5, 0 ) );	
	cubeNode1->setMaterialTexture( 0 , driver->getTexture("scene/alfa.png") );
	cubeNode1->getMaterial(0).MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;
	cubeNode1->getMaterial(0).ZWriteEnable = true;	
	//cubeNode1->getMaterial(0).ZBuffer = ECFN_LESSEQUAL;
	//cubeNode1->getMaterial(0).ColorMask = ECP_RGB;	
	//cubeNode1->getMaterial(0).setFlag( EMF_COLOR_MASK, true );
		
	IMeshSceneNode *sphereNode = smgr->addSphereSceneNode(4);
	sphereNode->setPosition( core::vector3df(0, 4, 0) );
	scene::ISceneNodeAnimator *flyCircle = smgr->createFlyCircleAnimator(core::vector3df(0,4,0),10);
	sphereNode->addAnimator(flyCircle);
	flyCircle->drop();

	IMeshSceneNode *groundNode = smgr->addCubeSceneNode(50);
	groundNode->setScale( core::vector3df(1, 0.03, 1) );
	groundNode->setMaterialTexture( 0 , driver->getTexture("scene/tex.jpg") );
	groundNode->setPosition( core::vector3df(0, -1.5 * 0.5, 0) );
Thanks in advance!

Braun
hbraun
Posts: 28
Joined: Tue Dec 16, 2008 7:33 pm
Location: Porto Alegre, Brazil
Contact:

Post by hbraun »

Really? No one? :(

This process is used in AR environments, so that the virtual rendering gets occluded by something that exists in the incoming image (we must know our world and positions).

Is there any tutorial how to use Stencil with Irrlicht?

Cheers,

Braun
hbraun
Posts: 28
Joined: Tue Dec 16, 2008 7:33 pm
Location: Porto Alegre, Brazil
Contact:

Post by hbraun »

[SOLVED]

Using ortho2d projection... :)

Thanks,

Braun
Luben
Posts: 568
Joined: Sun Oct 09, 2005 10:12 am
Location: #irrlicht @freenode

Post by Luben »

Sorry for being slow in answering.

To begin, there's the problem of the transparent cube always being rendered after the solid sphere; Irrlicht renders transparent objects after solid ones. There are ways to circumvent that though, for example by making a custom scene node, which creates a cube mesh and stores as a member. Then in OnRegisterSceneNode, one would register as one does in the CustomSceneNode-example, but pass ESNRP_SKY_BOX as a second parameter to registerNodeForRendering. This makes sure that the cube is rendered before both solid objects and transparent objects(If we'd pass ESNRP_SOLID, the cube might still get rendered after the sphere). Then in the render function, make the driver render the mesh in question.
Cube meshes can be created with calls to

Code: Select all

SceneManager->getGeometryCreator()->createCubeMesh(sizeVector)
(Note that this mesh needs to be dropped when it's no longer needed)
I don't give any guarantees that it'll work, but it's a place to start at least :)

I also dont know about stenciling in irrlicht, so i too call for someone to enlighten us in this area.

And what's an AR environment? :)
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Post by serengeor »

Augmented Reality I guess :roll:
Working on game: Marrbles (Currently stopped).
hbraun
Posts: 28
Joined: Tue Dec 16, 2008 7:33 pm
Location: Porto Alegre, Brazil
Contact:

Post by hbraun »

Yeah,
Augmented Reality :)

Thanks for the idea Luben, I solved the problem using Color Mask (material properties) combined with ortho2d projection for the webcam pictures. I thought that by just setting the "ALLOW_ZWRITE_ON_TRANSPARENT" attribute it would work, but it didnt.

I guess I was not clear of my objective, here is my working screenshot, the cube is invisible, but it stills hides the sphere and not the picture plane...

Thanks again,

Braun

Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

For what is the ortho projection? Just use the draw2DImage before calling drawAll() and it should be ok. For the rest, yes, colormask is the best way here. It's much faster than rendering a transparent object and will work under all circumstances. Well, you might want two scene managers actually, because otherwise you might get render order problems.
bilygates
Posts: 13
Joined: Tue Feb 23, 2010 10:35 pm

Post by bilygates »

hbraun wrote:I solved the problem using Color Mask (material properties)
hybrid wrote:For the rest, yes, colormask is the best way here.
Can you elaborate, please? :) I think I'm having a similar problem with a transparent texture. I have two scene nodes: one with a transparent texture (blue circle) on top of another one with a opaque texture (square wall). Depending on their positions, they get randomly rendered in the wrong Z order. Some screenshots:

1.
Image

2. With "smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);". The circle is now on top but with a gray background.
Image

And here's the code (you can move the circle with the W A S D keys:

Code: Select all

#include <irrlicht.h>

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

class MyEventReceiver : public IEventReceiver {
public:

	virtual bool OnEvent(const SEvent& event) {
		if (event.EventType == irr::EET_KEY_INPUT_EVENT)
			KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

		return false;
	}

	virtual bool IsKeyDown(EKEY_CODE keyCode) const	{
		return KeyIsDown[keyCode];
	}
	
	MyEventReceiver() {
		for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
			KeyIsDown[i] = false;
	}

private:
	bool KeyIsDown[KEY_KEY_CODES_COUNT];

};

SMesh* CreateBoxMesh(f32 width, f32 height) {

	f32 halfWidth = width / 2,
		halfHeight = height / 2;

	video::S3DVertex Vertices[4];
	Vertices[0] = video::S3DVertex(-halfWidth, halfHeight, 0, 0, 0, 0, video::SColor(0,255,255,255), 0, 0);
	Vertices[1] = video::S3DVertex(halfWidth, halfHeight, 0, 0, 0, 0, video::SColor(0,255,255,255), 1, 0);
	Vertices[2] = video::S3DVertex(halfWidth, -halfHeight, 0, 0, 0, 0, video::SColor(0,255,255,255), 1, 1);
	Vertices[3] = video::S3DVertex(-halfWidth, -halfHeight, 0, 0, 0, 0, video::SColor(0,255,255,255), 0, 1);

	u16 indices[] = {0,1,2, 2,3,0};

	SMeshBuffer *buffer = new SMeshBuffer;
	buffer->append(Vertices, 4, indices, 6);

	SMesh *mesh = new SMesh;
	mesh->addMeshBuffer(buffer);

	buffer->drop();

	aabbox3d<f32> Box;
	Box.reset(Vertices[0].Pos);
	for (int i = 1; i < 4; ++i)	{
		Box.addInternalPoint(buffer->Vertices[i].Pos);
	}
	mesh->setBoundingBox(Box);
	
	return mesh;

}

int main() {

	SMesh *tempMesh;
	ISceneNode *box1, *box2;
	SMaterial myMaterial;
	vector3df pos;
	MyEventReceiver receiver;

	IrrlichtDevice* device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(640, 480), 16, false, false, false, &receiver);

	if (device == 0)
		return 1;

	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();
	smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); 
	ICameraSceneNode *irrCamera = smgr->addCameraSceneNode();
	matrix4 ortho;
	ortho.buildProjectionMatrixOrthoLH(640.f, 480.f, 0.f, 1100.f);

	irrCamera->setProjectionMatrix(ortho, true);
	irrCamera->setPosition(vector3df(0, 0, -100));
	irrCamera->setTarget(vector3df(0, 0, 0));
	irrCamera->updateAbsolutePosition();

	// Setup material	
	myMaterial.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;
	myMaterial.Lighting = false;

	// Create 1st box
	tempMesh = CreateBoxMesh(200, 200);
	box1 = smgr->addMeshSceneNode(tempMesh);
	tempMesh->drop();
	box1->setAutomaticCulling(EAC_BOX);
	box1->setPosition(vector3df(0, 0, 0));
	myMaterial.setTexture(0, device->getVideoDriver()->getTexture("square_wall.png"));
	box1->getMaterial(0) = myMaterial;

	// Create 2nd box
	tempMesh = CreateBoxMesh(150, 150);
	box2 = smgr->addMeshSceneNode(tempMesh);
	tempMesh->drop();
	box2->setAutomaticCulling(EAC_BOX);
	box2->setPosition(vector3df(0, 0, -2));
	myMaterial.setTexture(0, device->getVideoDriver()->getTexture("blue_circle.png"));
	box2->getMaterial(0) = myMaterial;

	u32 nextStepTime = 0;

	while (device->run()) {

		u32 currentTime = device->getTimer()->getTime();
		if (currentTime >= nextStepTime) {

			nextStepTime = currentTime + u32(1000.f / 60.f);

			pos = box2->getPosition();
			if (receiver.IsKeyDown(KEY_KEY_W)) pos.Y += 1.f;
			if (receiver.IsKeyDown(KEY_KEY_A)) pos.X -= 1.f;
			if (receiver.IsKeyDown(KEY_KEY_S)) pos.Y -= 1.f;
			if (receiver.IsKeyDown(KEY_KEY_D)) pos.X += 1.f;
			box2->setPosition(pos);
			
			driver->beginScene(true, true, video::SColor(255,113,113,133));
			smgr->drawAll();
			driver->endScene();

		}
		
	}

	device->drop();
	
	return 0;
}

Thank you in advance!
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Simply set the opaque material to EMT_SOLID. Should work immediately.
bilygates
Posts: 13
Joined: Tue Feb 23, 2010 10:35 pm

Post by bilygates »

Thank you, that works like a charm in this case. But what should I do if I want to use a transparent texture for the other scene node too?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I'm not sure if ortho projection affects z-buffer fighting. But it could be worth changing the far value of the camera and introducing some more distance between the two objects.
bilygates
Posts: 13
Joined: Tue Feb 23, 2010 10:35 pm

Post by bilygates »

I tried a few experiments:
  • If I change the far value to 200, I have to place the objects at a minimum distance of 80 pixels (on the Z axis) for the problem to go away.
  • If I change the far value to 50000, I still need to place the objects at a minimum of 80 pixels (nothing changes).
  • If, however, I move the camera away from the objects with

    Code: Select all

    irrCamera->setPosition(vector3df(0, 0, -1000));
    I can put the objects closer, at a distance of about 20 pixels.
So, is there any way to solve this besides placing my objects far apart from each other? Is it a matter of imprecision? Any ideas? :(
Post Reply