Laser beam with spread out end

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
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Laser beam with spread out end

Post by robmar »

So this should have been simple enough, but :roll:
I created a beam using two triangles (based on the beam post here), works fine until I adjust the end vertices to spread the beam...
What happens is that the leftside triangle (A) which has its base at the end of the beam, if made wider naturally maps the texture as if the other
triangle (B) was the same scale. As it isn't the beam texture diverges between the triangles making up the beam. Can´t see any easy way to adjust that, could do it in a shader, but that's getting tricky for a simple beam effect.

Code: Select all

      -------
     |\      |
     |  \  B |
    |     \    |
   |        \    |
   |           \  |
  |     A        \ |
 |                 \ |
|                    \|
------------------- 
(for some reason the spaces in the triangle diag collapse when submitted!)
So seems triangle primitives expect a linear area mapping for the texture, so when the triangles are different sizes, the texture gets distorted.
Is there any way to make a simple beam quad/rectangle that can be spread out at one end without distorting the texture?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

Hm, that should not happen. You just move the vertices and don't change the UV's? Then A and B should both now just stretch a bit more the same way. I need some test-case for this.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Laser beam with spread out end

Post by robmar »

Yes but triangle A is much bigger than B, so the GPU is spreading the texture evenly, and in triangle B it's more compressed. It's seems the GPU/DX driver assumes any triangle with UV's 0,0-1,0-1,1 will have texture 0.5, 0.5 in the middle of the diagonal, whereas my beam would need it to be 0.5, 0.9, if you follow me.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

I follow what you say - but that is not how it usually works. It takes vertex positions and interpolates the UV's for every point in between. You can split an area into any amount of triangles of any size - as long as the uv's don't change the textured result should not change. Maybe make a screenshot for me? Could be I get an idea about it then.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

Hm, I wrote me a test - and you are kinda right. I have to think about this - not yet making sense to me.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

OK, really sorry for wrong info earlier. It totally blows my mind that I've never before run into this. I was so certain it would behave different, but now I see it - it does make sense.

edit: In case someone else wants experiment, my current test:

Code: Select all

#include <irrlicht.h>

using namespace irr;

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif

class BeamNode : public irr::scene::ISceneNode
{
public:
	
	BeamNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* smgr, irr::s32 id)
		: irr::scene::ISceneNode(parent, smgr, id)
		, End(core::vector3df(1000.f, 0.f, 0.f))
		, WidthStart(100.f)
		, WidthEnd(100.f)
	{
		MeshBuffer = new irr::scene::SMeshBuffer();
		MeshBuffer->Indices.set_used(6);
		MeshBuffer->Indices[0] = 0;
		MeshBuffer->Indices[1] = 1;
		MeshBuffer->Indices[2] = 2;
		MeshBuffer->Indices[3] = 3;
		MeshBuffer->Indices[4] = 0;
		MeshBuffer->Indices[5] = 2;
		MeshBuffer->Vertices.set_used(4);

		//Material.BackfaceCulling = false;
		Material.Lighting = false;
	}

	virtual ~BeamNode()
	{
		MeshBuffer->drop();
	}

	//! Set the ruler end-point relative to it's start position
	void setRelativeEnd(const irr::core::vector3df& end)
	{
		End = end;
	}

	//! Width is radius right now...so, it's 2*width
	void setWidthStart(irr::f32 w)
	{
		WidthStart = w;
	}

	void setWidthEnd(irr::f32 w)
	{
		WidthEnd = w;
	}

	void OnRegisterSceneNode() override
	{
		if ( isVisible() )
		{
			SceneManager->isCulled(this);
			SceneManager->registerNodeForRendering(this);
		}
	}

	void render() override
	{
		scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
		irr::video::IVideoDriver * driver = SceneManager->getVideoDriver();

		refreshMesh(camera);

		driver->setTransform(irr::video::ETS_WORLD, AbsoluteTransformation);
		driver->setMaterial(Material);
		driver->drawIndexedTriangleList((const irr::video::S3DVertex*)(MeshBuffer->getVertices()),
											MeshBuffer->getVertexCount(),
											MeshBuffer->getIndices(), MeshBuffer->getIndexCount()/3);

		//irr::video::SMaterial m2 = Material;
		//m2.Wireframe = true;
		//m2.ZBuffer = video::ECFN_DISABLED;
		//m2.setTexture(0,0);
		//driver->setMaterial(m2);
		//driver->drawIndexedTriangleList((const irr::video::S3DVertex*)(MeshBuffer->getVertices()),
		//									MeshBuffer->getVertexCount(),
		//									MeshBuffer->getIndices(), MeshBuffer->getIndexCount()/3);
	}

	const irr::core::aabbox3d<irr::f32>& getBoundingBox() const override
	{
		return MeshBuffer->getBoundingBox();
	}

	irr::u32 getMaterialCount() const override
	{
		return 1;
	}

	irr::video::SMaterial& getMaterial(irr::u32 i) override
	{
		return Material;
	}

protected:

	irr::core::vector3df getAbsoluteCenter() const { return getAbsolutePosition() + 0.5f*End; }

	void refreshMesh(const irr::scene::ICameraSceneNode* camera)
	{
		// Always aligns line to camera
		core::vector3df upVector = camera->isOrthogonal() ?  core::vector3df(0,1,0)
			: (camera->getAbsolutePosition() - getAbsoluteCenter() );

		core::vector3df upVectorN(upVector);
		upVectorN.normalize();
		core::vector3df dirN(End);
		dirN.normalize();
 		core::vector3df perp = -upVectorN.crossProduct(dirN);
		perp.normalize();

		const video::SColor LINE_COL(255,255,255,255);

		MeshBuffer->Vertices[0] = video::S3DVertex(perp*WidthStart, upVectorN, LINE_COL, core::vector2df(0,0));
		MeshBuffer->Vertices[1] = video::S3DVertex(End+perp*WidthEnd, upVectorN, LINE_COL, core::vector2df(1,0));
		MeshBuffer->Vertices[2] = video::S3DVertex(End-perp*WidthEnd, upVectorN, LINE_COL, core::vector2df(1,1));
		MeshBuffer->Vertices[3] = video::S3DVertex(-perp*WidthStart, upVectorN, LINE_COL, core::vector2df(0,1));
		MeshBuffer->recalculateBoundingBox();
	}

private:

	irr::core::vector3df End;
	irr::f32 WidthStart;
	irr::f32 WidthEnd;

	irr::scene::SMeshBuffer* MeshBuffer;
	irr::video::SMaterial	 Material;		
};

int main(int argc, char *argv[])
{
	IrrlichtDevice * Device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(1200,600) );
	if (!Device)
		return false;
	
	scene::ISceneManager* smgr = Device->getSceneManager();
	gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment();
    video::IVideoDriver* videoDriver =  Device->getVideoDriver();	

	smgr->addCameraSceneNode (0, core::vector3df(0, 0, 0),
								core::vector3df(0, 0, 1),
								-1);

	smgr->addLightSceneNode(0, core::vector3df(0, 0, 0),
							video::SColorf(1.0f, 1.0f, 1.0f),
							100.0f);

	BeamNode * beam = new BeamNode(smgr->getRootSceneNode(), smgr, -1);
	beam->setPosition(core::vector3df(-500, 0, 500));
	beam->getMaterial(0).setTexture(0, videoDriver->getTexture("../../media/irrlichtlogo.jpg"));
//	beam->getMaterial(0).setTexture(0, videoDriver->getTexture("my_media/rgbwb_cornerblocks_64x64.png"));
//	beam->getMaterial(0).setTexture(0, videoDriver->getTexture("my_media/text_color_alpha_512x512.png"));

	while ( Device->run() )
	{
		if ( Device->isWindowActive() )
		{
			irr::u32 time = Device->getTimer()->getRealTime();
			beam->setWidthEnd(100.f + (time/50) % 150);
			//beam->setWidthEnd(200.f);

			videoDriver->beginScene(true, true);

			smgr->drawAll();
			guiEnv->drawAll();

			videoDriver->endScene();
		}
		Device->sleep( 1 );
	}
	
	Device->closeDevice();
	Device->drop();
	
	return 0;
}
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

Seems even QUADS are just implemented with 2 triangles. This is far more tricky than I expected. At this point I also suspect it might need a shader. Or maybe many tiny polygons to distribute the distortion.

Maybe you can draw a real 3d line? So instead of shrinking one side you move it away from the camera instead? Ignore z-Buffer to still have it drawn on top of everything.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

I found one blog which might have a solution with shaders: https://www.reedbeta.com/blog/quadrilat ... ion-part-1
(I didn't test it).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Laser beam with spread out end

Post by robmar »

That's great, I'll try to recalculate the UVs based on that, of course my case is just 2 triangles, but how hard can the math be!
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Laser beam with spread out end

Post by robmar »

Image - Same distortion in the Beam node https://www.sendspace.com/file/dklr00.
So it looks like this is easy enough to solve in a shader as the article explains, but can it be done without having to use a shader to map each pixel to the correct perspective?
Can't really draw 3d lines as they wouldn't fill the space evenly.
Any other ideas?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

Yeah, the many tiny polygons idea (instead of just 2 long polygons - some kind of grid). Use enough until it looks good. Should be fine spending a few hundred polys for an effect unless it's used by tons of units at the same time.

Any recalculating UV's probably won't do it, I think those are as correct as they can be. It really clicked for me when I thought about using 3 polygons for a quad and then realized the center triangle wouldn't even change in any way when resizing one side of the quad. And it still would need another texture mapping (but each triangle a different one - so also can't fix this with a texture matrix).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Laser beam with spread out end

Post by robmar »

I had exactly the same thought about using 3 quads, but as you say that also suffers the same issue.
I need to keep things fast as it's already dropping frames, so using many triangles, which would be a good solution, isn't an option, I guess I can add the perspective pixel address code to the shader, but its already so big.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Laser beam with spread out end

Post by CuteAlien »

Many tiny triangles might not be much more expensive. As they cover the same area and that's often what is expensive. Depends a bit on where your bottleneck is, but making shader more fat could be more expensive. Thought I suppose shader solution will have the better result.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply