Draw a triangle on 2d image

Problems building or running the engine, queries about how to use features etc.
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Draw a triangle on 2d image

Post by slapin »

Hi, all!

I need to draw a set of filled triangles consisting of colored vertices and edges on 2d image. The vertex colors should smoothly transition into each other. Is there some API in Ogre for that or some external library? That is needed for heightmap implementation...

rpgplayerrobin
Orc Shaman
Posts: 788
Joined: Wed Mar 18, 2009 3:03 am
x 447

Re: Draw a triangle on 2d image

Post by rpgplayerrobin »

I think your question needs a lot more information. I could easily think of 3 different ways of what you are actually asking for.

But since I can only presume right now because of lack of information, I guess you want to render the terrain as a heightmap or something similar?
Then simply just create a new entity of the mesh you want to render, set its per vertex color information, set a material to it with shaders that render what you want from the per vertex color, and then create a new render target that renders only that entity to a 2D texture.

You can filter out all other objects either by:

  • Creating a whole new scene manager and handling it there instead of in your main scene
  • Using a RenderTargetListener with preRenderTargetUpdate/postRenderTargetUpdate to hide/show what you want
  • Setting ent->setVisibilityFlags and renderTargetViewport->getVisibilityMask
rpgplayerrobin
Orc Shaman
Posts: 788
Joined: Wed Mar 18, 2009 3:03 am
x 447

Re: Draw a triangle on 2d image

Post by rpgplayerrobin »

Example code:

Code: Select all


// Create the render target texture
m_texture = TextureManager::getSingleton().createManual(textureName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
	1024,
	1024,
	0,
	PF_R8G8B8,
	TU_RENDERTARGET,
	0);

// Create the render target camera
m_cameraRTT = sceneManager->createCamera(cameraName);
SceneNode* parent = sceneManager->getRootSceneNode()->createChildSceneNode();
parent->attachObject(m_cameraRTT);

// Setup the render target
m_renderTarget = m_texture->getBuffer()->getRenderTarget();
Ogre::Viewport* tmpViewport = m_renderTarget->addViewport(m_cameraRTT);
tmpViewport->setBackgroundColour(ColourValue(1.0f, 1.0f, 1.0f, 1.0f));
tmpViewport->setClearEveryFrame(true);
tmpViewport->setOverlaysEnabled(false);
tmpViewport->setSkiesEnabled(false);
tmpViewport->setShadowsEnabled(false);
tmpViewport->setVisibilityMask(8); // Also then set setVisibilityFlags to 8 in the entity
m_renderTarget->setAutoUpdated(false);

// Update the render target to render to the texture
m_renderTarget->update();
slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

Thanks but I need entirely different thing.
I have some numeric data which belongs to the vertices of a set of triangles (imagine something you paint on top of vertices in Blender).

Code: Select all

struct vertexData {
	Ogre::Vector3 position;
	Ogre::Vector3 uv;
	float v1, v2, v3, v3,
		v4, v5, v6, v7;
};
std::vector<vertexData> data; // loaded from file, about 55K things
std::vector<int> indices; // triangles out of above things, loaded from same file.

I need to extrapolate the data and cache them so I can easily get the value. For that I want to use UV value as 2D triangle vertex and
consider the values as colors.

Code: Select all

int i;
Ogre::Image image(PF_R8G8B8, 512, 512);
image.setTo(Ogre::ColourValue(0, 0, 0, 1));
for (i = 0; i < indices.size(); i += 3)
{
    vertexData p1 = data[indices[i]];
    vertexData p2 = data[indices[i + 1]];
    vertexData p3 = data[indices[i + 2]];
    drawVertexColor2DTriangle(image, p1.uv * 512, p2.uv * 512, p3.uv * 512,
    	Ogre::ColorValue(p1.v1, p1.v2, p1.v3),
    	Ogre::ColorValue(p2.v1, p2.v2, p2.v3),
    	Ogre::ColorValue(p3.v1, p3.v2, p3.v3));
}

And then I will be able to get the value for any UV without it having to be exactly value from data, which would be much faster,
The approach is similar to deformation maps and height maps in shaders.

So what I need is to find this drawVertexColor2DTriangle() function or implement it. Any ideas?
I remember doing something like that in past but I forgot too much and I was hoping there is some library or already made function which I can use for this thing...

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

It looks like I need baricentric interpolation between 3 values for each pixel value...

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

Sorry, today I'm dumb af.

Code: Select all

struct Vertex2D {
	float x, y;
	Ogre::ColourValue color;

Vertex2D(float x, float y, const Ogre::ColourValue &color)
	: x(x)
	, y(y)
	, color(color)
{
}
};

bool calculateBarycentricCoordinates(int px, int py, const Vertex2D &v0,
				     const Vertex2D &v1, const Vertex2D &v2,
				     float &u, float &v, float &w)
{
	// triangle area
	float area = 0.5f * ((v1.x - v0.x) * (v2.y - v0.y) -
			     (v2.x - v0.x) * (v1.y - v0.y));
	if (area == 0)
		return false; // one of the sides is zero, skip it

u = 0.5f * ((v1.x - px) * (v2.y - py) - (v2.x - px) * (v1.y - py)) /
    area;
v = 0.5f * ((v2.x - px) * (v0.y - py) - (v0.x - px) * (v2.y - py)) /
    area;
w = 1.0f - u - v;

return u >= 0 && v >= 0 && w >= 0;
}

void drawVertexColor2DTriangle(Ogre::Image &image, const Vertex2D &v0,
			 const Vertex2D &v1, const Vertex2D &v2)
{
	// Determine bounding box of the triangle
	int minX = std::min({ v0.x, v1.x, v2.x });
	int minY = std::min({ v0.y, v1.y, v2.y });
	int maxX = std::max({ v0.x, v1.x, v2.x });
	int maxY = std::max({ v0.y, v1.y, v2.y });

// Clamp to image bounds
minX = std::max(0, minX);
minY = std::max(0, minY);
maxX = std::min((int)image.getWidth() - 1, maxX);
maxY = std::min((int)image.getHeight() - 1, maxY);

for (int y = minY; y <= maxY; ++y) {
	for (int x = minX; x <= maxX; ++x) {
		float u, v, w;
		if (calculateBarycentricCoordinates(x, y, v0, v1, v2, u,
						    v, w)) {
			// Interpolate colors
			Ogre::ColourValue color = u * v0.color +
						  v * v1.color +
						  w * v2.color;

			image.setColourAt(color, x, y, 0);
		}
	}
}
}

Was struggling to make it work and suddenly it worked. It is not most efficient method but I don't need to do it too often. The resulting map will be
constantly used though...
Next I will need to find some good compression method...

paroj
OGRE Team Member
OGRE Team Member
Posts: 2238
Joined: Sun Mar 30, 2014 2:51 pm
x 1217

Re: Draw a triangle on 2d image

Post by paroj »

I mean sure.. but thats literally a vertex colored mesh that you have there, where the uvs are the vertex positions and v1, v2, v3 are the "color" values. You could use your GPU for that - e.g. with Ogre to abstract the graphics API..

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

That would require render target rendering and I remember I spent a lot of time to make it work last time when toying with water...
And I can't just create it, use it once and destroy it here and now immediately as it will require a few frames to pass...

I guess it is fine for now as it is and I will convert it to shader when I finish with other things. This map creations runs once for each map on "mesh" data changes, which happen only during development (and data build is 30 seconds each step because I need to process "base mesh" and "changed mesh" which have random vertex order and I need to index them to find proper triangle corners to get changes list for base mesh.
So each change set of 58 will take 30 seconds to process and 1 second to make map; if I eliminate that 1 second that won't make my life much easier.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

Additionally, I think the best thing about CPU approach is that I will be able to use threads and batch jobs on
headless servers, with massive parallel jobs, i.e. in cmake rules. The GPU approach will require window and
will have to run on desktop and will optimize only actual map building, the rest will remain on CPU... So I guess I
choose CPU approach until it will become the bottleneck.

rpgplayerrobin
Orc Shaman
Posts: 788
Joined: Wed Mar 18, 2009 3:03 am
x 447

Re: Draw a triangle on 2d image

Post by rpgplayerrobin »

That would require render target rendering and I remember I spent a lot of time to make it work last time when toying with water...

My code above takes care of all that basically.

And I can't just create it, use it once and destroy it here and now immediately as it will require a few frames to pass...

This is why more information is needed than you gave, because if that is your issue, it must mean that you read it back on the CPU?
Because if you simply bind it again to the GPU (for a material using a shader for example), it has no issues.
Also, you can use blit on it to copy it to another texture, which you can read instantly, but it will give you a temporary performance drop when you do so (around half FPS if you blit from a newly rendered texture and read from it each frame, but it should not be a problem at all for you since you just render the texture once and not every frame).
I even found that even if you do wait a couple of frames, my computer still forces a GPU->CPU sync point, which is the entire bottleneck of actually reading from a GPU texture each frame.

If it is on the server as you mentioned in the last post, I understand your issue more in detail. But again, I think you should mention all of this in the beginning of a post, otherwise anyone helping you is just guessing.

slapin
Bronze Sponsor
Bronze Sponsor
Posts: 250
Joined: Fri May 23, 2025 5:04 pm
x 16

Re: Draw a triangle on 2d image

Post by slapin »

Sorry, I try, but sometimes I can't explain whole context. It is a batch job. The map itself is read on CPU and read rarely to construct objects, not every frame. It is used to create geometry and textures which later go to GPU and CPU-side data like colliders and SDF. As long as original data remain unchanged the map is never re-generated. So they are re-generated only during development and never in final running game. Maybe by mods if that ever happen.

What is slow is comparison of 2 meshes per UV. I.e. Having 2 meshes with 12 submeshes each. I need to produce index to associate mesh2 uv to mesh1 uv closest by distance and remember index. That is what takes 30 seconds (55K verts). The map rendering takes 1s. There is 55 maps in total to produce.
if that will take under hour I'll be super happy... For now I need to reliably produce UV2 with Ogre gltf imports which seems to be problematic without patching...