Drawing a simple triangle (VertexBuffer + RenderOperation)

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Drawing a simple triangle (VertexBuffer + RenderOperation)

Post by Mind Calamity »

I'm trying to create, fill and draw a simple vertex buffer with 3 pairs of vertex colors and positions I've searched but haven't been able to find an example of proper usage of RenderOperation.

This is what I have:

Code: Select all

#include "Ogre.h"
#include <iostream>
#include <stdio.h>
using namespace Ogre;

class Writer
{
public:
	void setVertexBuffer(size_t count)
	{
		// data init:
		std::vector<Vector3> pos;
		pos.push_back(Vector3(-10, 0, -20));
		pos.push_back(Vector3(0, 10, -20));
		pos.push_back(Vector3(10, 0, -20));
		std::vector<ColourValue> col;
		col.push_back(ColourValue::Red);
		col.push_back(ColourValue::Green);
		col.push_back(ColourValue::Blue);
		std::vector<float> vertData;
		for (int i = 0; i < pos.size(); i++)
		{
			vertData.push_back(pos[i].x);
			vertData.push_back(pos[i].y);
			vertData.push_back(pos[i].z);

			vertData.push_back(col[i].r);
			vertData.push_back(col[i].g);
			vertData.push_back(col[i].b);
			vertData.push_back(col[i].a);
		}

		// basic initialisation of render op
		mRenderOp.vertexData = OGRE_NEW Ogre::VertexData();
		mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_FAN;
		mRenderOp.useIndexes = false;
		
		// Setup our render operation to match the type
		Ogre::VertexDeclaration* vd = mRenderOp.vertexData->vertexDeclaration;
		vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
		vd->addElement(0, sizeof(float) * 3, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);

		// vertex size: 3 for position + 4 for color (RGBA)
		mVertexBuffer = Ogre::HardwareBufferManager::getSingleton().
			createVertexBuffer(7*sizeof(float), pos.size(),
			Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
			false);
		
		assert(!mVertexBuffer.isNull() && "Error creating a vertex buffer");

		void* copy_target = mVertexBuffer->lock(
			Ogre::HardwareVertexBuffer::HBL_DISCARD);

		assert(copy_target && "Ogre vertex buffer is invalid");

		std::memcpy(copy_target, &vertData[0], vertData.size()*
			sizeof(float));

		mVertexBuffer->unlock();
		mRenderOp.vertexData->vertexCount = pos.size();
		mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
	}

	void draw()
	{
		Ogre::Root::getSingleton().getRenderSystem()->_render(mRenderOp);
	}

	RenderOperation mRenderOp;
	HardwareVertexBufferSharedPtr mVertexBuffer;
};

int main()
{
	Root* root = new Root();
	bool succ = root->restoreConfig() || root->showConfigDialog();
	if (!succ) { delete root; return -1; }

	RenderWindow* wnd = root->initialise(true);
	SceneManager* mgr = root->createSceneManager(ST_GENERIC);
	Camera* cam = mgr->createCamera("");
	cam->setNearClipDistance(0.1f);
	cam->setFarClipDistance(1000);
	mgr->setAmbientLight(ColourValue::White);
	Viewport* vp = wnd->addViewport(cam);
	vp->setBackgroundColour(ColourValue(0.3, 0.3, 0.3));
	Writer w;
	w.setVertexBuffer(3);
	while (!wnd->isClosed())
	{
		w.draw();
		root->renderOneFrame();
		Ogre::WindowEventUtilities::messagePump();
	}

	return 0;
}
It throws an "invalid call" exception under D3D9, and renders nothing under OpenGL. What am I doing wrong ?

Full exception:

Code: Select all

OGRE EXCEPTION(3:RenderingAPIException): Failed to DrawPrimitive : Invalid call in D3D9RenderSystem::_render at F:/Libraries/ogre/Source/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp (line 3581)
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 534

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Kojack »

Code: Select all

 vd->addElement(0, sizeof(float) * 3, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
VET_COLOUR is a single unsigned int (32 bit rgba), not 3 floats.
Although I've often wondered (but never tried) what would happen if an element type of VES_DIFFUSE was used with a datatype like VET_FLOAT4. No idea it that works.
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Mind Calamity »

Okay, so third edit.

I'm trying out with code from betajaen's Gorilla, the part where he creates and fills the vertex buffers:

Code: Select all

#include "Ogre.h"
#include <iostream>
#include <stdio.h>
using namespace Ogre;
struct Vertex
{
	Ogre::Vector3 position;
	Ogre::ColourValue colour;
};
class Writer
{
public:
	void setVertexBuffer(size_t count)
	{
		std::vector<Vertex> vertices;
		Vertex a, b, c;
		a.position = Vector3(-10, 0, -10);
		b.position = Vector3(0, 10, -10);
		c.position = Vector3(10, 0, -10);
		a.colour = ColourValue::Red;
		b.colour = ColourValue::Green;
		c.colour = ColourValue::Blue;
		vertices.push_back(a);
		vertices.push_back(b);
		vertices.push_back(c);
		//vertices.push_back({Vector3::ZERO, ColourValue::Red});

		// basic initialisation of render op
		mRenderOp.vertexData = OGRE_NEW Ogre::VertexData();
		
		// Setup our render operation to match the type
		Ogre::VertexDeclaration* vd = mRenderOp.vertexData->vertexDeclaration;
		size_t offset = 0;
		vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
		vd->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);

		mVertexBuffer = Ogre::HardwareBufferManager::getSingleton().
			createVertexBuffer(vd->getVertexSize(0), vertices.size(),
			Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
			false);

		Vertex* data = (Vertex*)mVertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
		for (size_t i = 0; i < vertices.size(); i++)
			*data++ = vertices[i];
		mVertexBuffer->unlock();

		mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_FAN;
		mRenderOp.useIndexes = false;
		mRenderOp.vertexData->vertexCount = vertices.size();
		mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
	}

	void draw()
	{
		Ogre::Root::getSingleton().getRenderSystem()->_render(mRenderOp);
	}

	RenderOperation mRenderOp;
	HardwareVertexBufferSharedPtr mVertexBuffer;
};

int main()
{
	Root* root = new Root();
	bool succ = root->restoreConfig() || root->showConfigDialog();
	if (!succ) { delete root; return -1; }

	RenderWindow* wnd = root->initialise(true);
	SceneManager* mgr = root->createSceneManager(ST_GENERIC);
	Camera* cam = mgr->createCamera("");
	cam->setNearClipDistance(0.1f);
	cam->setFarClipDistance(1000);
	mgr->setAmbientLight(ColourValue::White);
	Viewport* vp = wnd->addViewport(cam);
	vp->setBackgroundColour(ColourValue(0.3, 0.3, 0.3));
	Writer w;
	w.setVertexBuffer(3);
	while (!wnd->isClosed())
	{
		w.draw();
		root->renderOneFrame();
		Ogre::WindowEventUtilities::messagePump();
	}

	return 0;
}
Still doesn't work, I'm really not sure what it could be at this point.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 534

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Kojack »

Hmm, thinking more on it (remembering how FVF works and checking the msdn at http://msdn.microsoft.com/en-us/library ... 85%29.aspx ) changing the type won't work, at least in directx (I don't use opengl, so don't know it as well). D3DFVF_DIFFUSE (the underlying d3d flag for Ogre::VES_DIFFUSE) only accepts an unsigned int for colour. If I wanted to give a floating point colour to a vertex, I'd probably pass it as a texture coordinate then use a shader to treat it as a colour. Using a standard 32bit colour instead of 128 bit HDR colour is probably easier though.

As a side note, I see you are doing direct rendering, bypassing the scene manager. I've had no end of trouble getting that to work in ogre, it's extremely fussy. Not saying it can't be done, but it's never gone as easy as I've wanted. There's virtually no info on it either, most forum questions on it were answered with something like "if you need to ask, you shouldn't be doing it".
For example, in your second bit of code:

Code: Select all

   while (!wnd->isClosed())
   {
      w.draw();
      root->renderOneFrame();
      Ogre::WindowEventUtilities::messagePump();
   }
Nothing from w.draw() will be visible because the renderOneFrame will clear the screen before w.draw()'s output reaches the monitor (via the buffer swap at the end of renderOneFrame). You also can't call rendering methods outside of a beginframe and endframe, renderOneFrame controls them. You'd need to start and stop them manually, such as with Ogre::Root::getSingleton().getRenderSystem()->_beginFrame();
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Mind Calamity »

Bullseye, Kojak!

I was rendering it badly, but now I ran into another issue, I get still nothing (blank) in D3D9, it seems fine in OGL though.

Here's my partially working code for OGL:

Code: Select all

#include "Ogre.h"
#include <iostream>
#include <stdio.h>
using namespace Ogre;
struct Vertex
{
	Ogre::Vector3 position;
	Ogre::ColourValue colour;
};
class Writer : public RenderQueueListener
{
public:
	void setVertexBuffer(size_t count)
	{
		std::vector<Vertex> vertices;
		Vertex a, b, c;
		a.position = Vector3(-1, 0, 0);
		b.position = Vector3(0, 1, 0);
		c.position = Vector3(1, 0, 0);
		a.colour = ColourValue::Red;
		b.colour = ColourValue::Green;
		c.colour = ColourValue::Blue;
		vertices.push_back(a);
		vertices.push_back(b);
		vertices.push_back(c);
		//vertices.push_back({Vector3::ZERO, ColourValue::White});

		// basic initialisation of render op
		mRenderOp.vertexData = OGRE_NEW Ogre::VertexData();
		
		// Setup our render operation to match the type
		Ogre::VertexDeclaration* vd = mRenderOp.vertexData->vertexDeclaration;
		size_t offset = 0;
		vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
		vd->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);

		mVertexBuffer = Ogre::HardwareBufferManager::getSingleton().
			createVertexBuffer(vd->getVertexSize(0), vertices.size(),
			Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
			false);

		Vertex* data = (Vertex*)mVertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
		for (size_t i = 0; i < vertices.size(); i++)
			*data++ = vertices[i];
		mVertexBuffer->unlock();

		mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_STRIP;
		mRenderOp.useIndexes = false;
		mRenderOp.vertexData->vertexCount = vertices.size();
		mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
	}

	virtual void renderQueueStarted(uint8 queueGroupId, const String& invocation, bool& skipThisInvocation)
	{
	}

	virtual void renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation)
	{
		if (queueGroupId != Ogre::RENDER_QUEUE_OVERLAY)
			return;
		Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem();
		rs->_setWorldMatrix(Ogre::Matrix4::IDENTITY);
		rs->_setProjectionMatrix(Ogre::Matrix4::IDENTITY);
		rs->_setViewMatrix(Ogre::Matrix4::IDENTITY);
		rs->_render(mRenderOp);
	}

	RenderOperation mRenderOp;
	HardwareVertexBufferSharedPtr mVertexBuffer;
};

int main()
{
	Root* root = new Root();
	bool succ = root->restoreConfig() || root->showConfigDialog();
	if (!succ) { delete root; return -1; }

	RenderWindow* wnd = root->initialise(true);
	SceneManager* mgr = root->createSceneManager(ST_GENERIC);
	Camera* cam = mgr->createCamera("");
	cam->setNearClipDistance(0.1f);
	cam->setFarClipDistance(1000);
	mgr->setAmbientLight(ColourValue::White);
	Viewport* vp = wnd->addViewport(cam);
	vp->setBackgroundColour(ColourValue(0.3, 0.3, 0.3));
	Writer* w = new Writer();
	w->setVertexBuffer(3);
	mgr->addRenderQueueListener(w);

	while (!wnd->isClosed())
	{
		root->renderOneFrame();
		Ogre::WindowEventUtilities::messagePump();
	}

	delete w;
	delete root;
	return 0;
}
I'll try to use VET_COLOUR for the color instead of FLOAT4.
I also adjusted the coordinates to be appropriate for identity projection (-1, 1).

Here's a screenshot: http://i.imgur.com/1HScFsG.png

Edit: Using VET_COLOUR changed nothing - still blank in D3D9, but this gave me a bit of hope.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 534

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Kojack »

Just for the hell of it, try swapping the vertex order. Maybe it's being backface culled. (That should be the same in both d3d and opengl, but it's best to be safe, the first thing I do when triangles don't turn up is reverse winding)
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Mind Calamity »

Kojack wrote:Just for the hell of it, try swapping the vertex order. Maybe it's being backface culled. (That should be the same in both d3d and opengl, but it's best to be safe, the first thing I do when triangles don't turn up is reverse winding)
What the hell ? That actually worked, but it doesn't render with vertex colors: http://prntscr.com/5nyaj3

Here's what I tried:
BAC - works
CBA - works
ACB - works
CAB - doesn't
ABC - doesn't

Works means that it displays a black triangle, doesn't means that it doesn't render the triangle at all.

Edit: This is probably due to D3D9 being confused without a material, I'll try adding materials.

Edit2: Yep, it's the material, applying a simple vertex color material fixes the blackness issue.


Here's the full code:

Code: Select all

#include "Ogre.h"
#include <iostream>
#include <stdio.h>
using namespace Ogre;
struct Vertex
{
	Ogre::Vector3 position;
	Ogre::ARGB colour;
};
class Writer : public RenderQueueListener
{
public:
	SceneManager* mSceneMgr;
	Ogre::MaterialPtr mMat;
	Writer(SceneManager* mgr)
	{
		mSceneMgr = mgr;
	}

	void setVertexBuffer(size_t count)
	{
		std::vector<Vertex> vertices;
		Vertex a, b, c;
		a.position = Vector3(-1, 0, 0);
		b.position = Vector3(0, 1, 0);
		c.position = Vector3(1, 0, 0);
		a.colour = ColourValue::Red.getAsARGB();
		b.colour = ColourValue::Green.getAsARGB();
		c.colour = ColourValue::Blue.getAsARGB();
		vertices.push_back(b);
		vertices.push_back(a);
		vertices.push_back(c);
		//vertices.push_back({Vector3::ZERO, ColourValue::White});

		// basic initialisation of render op
		mRenderOp.vertexData = OGRE_NEW Ogre::VertexData();
		
		// Setup our render operation to match the type
		Ogre::VertexDeclaration* vd = mRenderOp.vertexData->vertexDeclaration;
		size_t offset = 0;
		vd->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
		//vd->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
		//offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
		vd->addElement(0, offset, Ogre::VET_COLOUR_ARGB, Ogre::VES_DIFFUSE);
		offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR_ARGB);

		mVertexBuffer = Ogre::HardwareBufferManager::getSingleton().
			createVertexBuffer(vd->getVertexSize(0), vertices.size(),
			Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
			false);

		Vertex* data = (Vertex*)mVertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
		for (size_t i = 0; i < vertices.size(); i++)
			*data++ = vertices[i];
		mVertexBuffer->unlock();

		mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_STRIP;
		mRenderOp.useIndexes = false;
		mRenderOp.vertexData->vertexCount = vertices.size();
		mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
		MaterialManager& matmgr = MaterialManager::getSingleton();
		mMat = matmgr.getByName("VertexColor");
	}

	virtual void renderQueueStarted(uint8 queueGroupId, const String& invocation, bool& skipThisInvocation)
	{
	}

	virtual void renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation)
	{
		if (queueGroupId != Ogre::RENDER_QUEUE_OVERLAY)
			return;
		Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem();
		rs->_setWorldMatrix(Ogre::Matrix4::IDENTITY);
		rs->_setProjectionMatrix(Ogre::Matrix4::IDENTITY);
		rs->_setViewMatrix(Ogre::Matrix4::IDENTITY);
		mSceneMgr->_setPass(mMat->getTechnique(0)->getPass(0));
		rs->_render(mRenderOp);
	}

	RenderOperation mRenderOp;
	HardwareVertexBufferSharedPtr mVertexBuffer;
};

int main()
{
	Root* root = new Root();
	bool succ = root->restoreConfig() || root->showConfigDialog();
	if (!succ) { delete root; return -1; }

	RenderWindow* wnd = root->initialise(true);
	ResourceGroupManager::getSingleton().addResourceLocation("../materials", "FileSystem");
	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
	SceneManager* mgr = root->createSceneManager(ST_GENERIC);
	Camera* cam = mgr->createCamera("");
	cam->setNearClipDistance(0.1f);
	cam->setFarClipDistance(1000);
	mgr->setAmbientLight(ColourValue::White);
	Viewport* vp = wnd->addViewport(cam);
	vp->setBackgroundColour(ColourValue(0.3, 0.3, 0.3));
	Writer* w = new Writer(mgr);
	w->setVertexBuffer(3);
	mgr->addRenderQueueListener(w);

	while (!wnd->isClosed())
	{
		root->renderOneFrame();
		Ogre::WindowEventUtilities::messagePump();
	}

	delete w;
	delete root;
	return 0;
}
And the material:

Code: Select all

material VertexColor
{
   technique
   {
      pass
      {
         diffuse vertexcolour
         specular vertexcolour
         ambient vertexcolour
         lighting on

      }
   }
}
I'll try to write a wiki article or something ASAP, this part of OGRE is really not documented well.
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
User avatar
shadowfeign
Goblin
Posts: 213
Joined: Mon Jan 26, 2009 11:51 pm
x 15

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by shadowfeign »

I think this tutorial covers basically what you were talking about from what I skimmed. http://www.ogre3d.org/tikiwiki/tiki-ind ... =Tutorials It's a little old but I don't think it's probably close.
User avatar
Mind Calamity
Ogre Magi
Posts: 1255
Joined: Sat Dec 25, 2010 2:55 pm
Location: Macedonia
x 81

Re: Drawing a simple triangle (VertexBuffer + RenderOperatio

Post by Mind Calamity »

Well. kind of. It does cover filling the vertex buffers, but what I was aiming to do was render a constantly-changing vertex buffer which you can only do through ManualObject, but I didn't want to go that way, RenderOperation gives me a lot more control than ManualObject does.

Still, that's a very neat page that I haven't had the time to read yet, and completely forgot about. Thanks guys, for all your help. :)
BitBucket username changed to iboshkov (from MindCalamity)
Do you need help? What have you tried?
- xavier
---------------------
HkOgre - a Havok Integration for OGRE | Simple SSAO | My Blog | My YouTube | My DeviantArt
Post Reply