Am I using SDL_RenderGeometry correctly?

Using SDL2 built from main on 6/10/21 to test out the new SDL_RenderGeometry. Am I doing something wrong? I’m trying to render a quad with a texture. If I render a rectangle as below, everything works as I expect:

SDL_Color col{ 0xff,0xff,0xff,0xff };
	std::vector<SDL_Vertex> verticies{
		{{300.0f,200.0f},	col,	{0.0f,0.0f}},
		{{800.0f,200.0f},	col,	{1.0f,0.0f}},
		{{300.0f,700.0f},	col,	{0.0f,1.0f}},
		{{800.0f,700.0f},	col,	{1.0f,1.0f}},
	};
	std::array<int, 6> indexList = { 0,1,2,2,1,3 };
	SDL_RenderGeometry(mRenderer, texture, verticies.data(), (int)verticies.size(), indexList.data(), (int)indexList.size());

This gives me the following output:


But if I change the verticies to draw a trapezium instead, like this:

SDL_Color col{ 0xff,0xff,0xff,0xff };
	std::vector<SDL_Vertex> verticies{
		{{500.0f,200.0f},	col,	{0.0f,0.0f}},
		{{700.0f,200.0f},	col,	{1.0f,0.0f}},
		{{300.0f,700.0f},	col,	{0.0f,1.0f}},
		{{800.0f,700.0f},	col,	{1.0f,1.0f}},
	};
	std::array<int, 6> indexList = { 0,1,2,2,1,3 };
	SDL_RenderGeometry(mRenderer, texture, verticies.data(), (int)verticies.size(), indexList.data(), (int)indexList.size());

Then the result is not what I expect. You can clearly see the two triangles being drawn with textures that don’t make sense together.


I’m totally new to this sort of api, so my question is: Is this output correct (I assume it is)?. If so, is there a way to use the api in a way that will map the texture onto the quad, rather than seperately onto two triangles? I would expect (perhaps incorrectly) to end up with something like this:

If something like this isn’t possible, what is possible using textures and RenderGeometry?Perhaps I have a fundamental misunderstanding of the api.

1 Like

The result seems “correct” for each triangle.

Also think this is ok.
you expect something that would be done by:

Guess this is what’s meant to happen then. Though I must admit, I’m struggling to see much use for textures in RenderGeometry, if it works like this?

Thanks for the suggestion. I’m not sure how to make use of that patch… I downloaded the diff file and tried to apply it with git, but it failed.

Rendering triangles allows more precise cuts for atlas textures, different shapes, plus you can have per vertex color modulation. you can also integrate with other libs that outputs triangles.

The diff is old, but you can see how it works and try to do something with it.

1 Like

Yeah, I’m using the SDL_RenderGeometry to draw filled and shaded shapes using per vertex shading, and it works really nicely. Not sure how to make any real life use of the texture feature, but I guess that’s my inexperience!

you can also do the shading with a texture

Well, I thought about it some more, and with a few tricks I was able to get the effect I wanted. This is great, it basically completes the “SNES on steroids” claim/feature set for the SDL2 renderer - I can now project and scale backgrounds with mostly hardware acceleration, and without having to leave the comfort of the SDL2 renderer.

I love SDL!

by

or, using a more indicative texture:

by

3 Likes

Great!
But how did you get the correct result?

Well, it’s not truly correct - its more a case of making it look visually acceptable. It’s very very simple. Starting with something that looks bad:

Instead of mapping the texture to one quad, divide that quad into bits, and map each bit to the appropraite part of the texture… here’s with 3x3 for 9 quads:

Ok, still looks bad, but seems obvious that by increasing the number of sub quads, we can arrive at something visually acceptable… here’s with 15x15:

So we are drawing 15x15x2 =550 triangles instead of two, and have something that looks good. We only need to calculate 225 projection points per frame. (which why I say mostly in hardware - we still need to do those projections on the CPU).

2 Likes

Something else that allows you to get a better result with fewer quads is to draw 4 triangles per quad, using the centrepoint of each quad (as found by the intersection of the diagonals) as an extra vertex.

1 Like

Thanks for sharing. It seems a good workaround. There is a little distortion, but you can even split in smaller quads.

I’ve updated the previous patch so it applies correctly (and also look at what it ).
It allow to modify the model view matrix, (for Opengl and d3d backend)
so you can do a translation/rotation/re-scale of the renderer output.
(if you want to restrict the transformation to a specific RenderCopy, you probably need to call RenderFlush before/after the RenderCopy)

This doesn’t seem enough for what you want.
but it may be a good start, because I think you would need:

  • imodify do a rotation around x axis, for the model view. (currtly it’s only aroud z)
  • also allow to modify the projection matrix to have to change the perspective
2 Likes

Thanks, I’ll take a look at that. Regarding my “solution” - yes, some distortion remains, and the amount of subquads you need in order to make it look ok depends on the nature of the texture.

1 Like

Ryan told me off when I asked for this, lol!

The index array (indices parameter) lets you construct 2 triangles from 4 vertices (a quad). That’s the way GPU APIs expose rendering quads, so that’s the best way to do it.

The original poster was expecting a perspective-correct projection instead of an affine projection when rendering geometry. The best way to achieve perspective-correct rendering is to use a perspective projection matrix and 3D position coordinates (both of which are outside the scope of SDL’s 2D rendering API). Tessellating the non-perspective-correct geometry can achieve similar results, as already discussed.

@thd79
I’ve quickly updated the patch to see if it was feasible with SDL_Renderer.

So now you can set a rotation of ‘angle’ around the x axis (eg (1,0,0), at point named ‘center’ )
(Rotation matrix - Wikipedia “Rotation matrix from axis and angle”)

SDL_RenderGetViewport(renderer, &viewport);
center.x = viewport.w/2;
center.y = viewport.h/2;
angle = -0.1;
SDL_RenderPushTransformRotationAxis(renderer, angle, &center, 1, 0, 0);

Then you can add a simple projection matrix:
https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/building-basic-perspective-projection-matrix

float fov = 140; 
float near = 1;
float far = 20;
SDL_RenderPushProjection(renderer, fov, near, far);

Render your stuff

RenderCopy()
SDL_RenderFlush()
SDL_RenderPopTransform(renderer);
SDL_RenderPopProjection(renderer);

There may be bugs, but it seems to render something which should look like what you expect.

hehe, probably fears this question will be asked over and over :slight_smile:

Would probably help if the SDL_RenderGeometry docs mentioned that it only does affine texture mapping :slight_smile:

To be fair, this is not part of the official SDL release yet!

I guess now, with hardware triangle drawing and affine only texture mapping, we could think of the SDL2 renderer as a Playstation rather than a SNES?