Learned something today

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
albinopapa
Posts: 4190
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Learned something today

Post by albinopapa » July 23rd, 2020, 7:58 pm

I've been wanting to make my own 2D drawing pipeline and thought I had things figured out. A rectangle that has been translated to surround the object holds the position and it's dimensions, this way I wouldn't have to pass position, width and height separately. Since the width and height would be provided, I thought I'd just use these dimensions in a scaling matrix. I also had to pass in the orientation if I wanted to have the sprites rotate.

Aside from that, I thought that since the size was used for scaling, I could just use a set of vertices that are square in shape and the rotation and scaling would take care of things. For square sprites this worked fine and I never noticed any weird stretching or compressing. Well, that changed on this current project where the sprites aren't square. I was really confused, but I took some of the values into a spreadsheet to play around with and found that if I kept the vertices square the rotations didn't affect the shape. So for my situation, the dimensions of the sprite are 45x65 and with the set of vertices I used ( -.5, -.5 for top left and .5, .5 for bottom right ) the dimensions stayed 45x65 and the texture would rotate causing the image to compress when rotated 90 degrees.

So now I have to do some more math when setting up these sprites using a rectangle and angle. The vertices need to be in a ratio of width and height, and the scale would need to be the same in X and Y...this is going to be confusing and probably bite me if I don't keep this in mind.

What I found to calculate the correct vertices and scaling matrix:
First, decide which way to divide the dimensions: width/height or height/width. I chose height/width as my test.
Second, since the result has normalized the dimensions in terms of the other the scaling can be the same and with my choice, setting the width for xScale and yScale seems to give correct results. ( width * (height/width) = height ).

So not terribly difficult, just thought I'd share something on this ghost town of a forum.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3935
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Learned something today

Post by chili » July 27th, 2020, 4:27 pm

Boo.

What you making this 2D drawing pipeline for, and what are you building it on? :]
Chili

albinopapa
Posts: 4190
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Learned something today

Post by albinopapa » July 27th, 2020, 8:00 pm

I've modified the chili framework and it's based on the 3D fundamentals pipeline technique.

I'm using it for the flexibility of sprite rotation, pixel shader, sampler and color blend.

After understanding your usage of templates with the 3D fundamentals framework, I was able to add template parameters for a few missing features like texture sampler ( PointerSampler ) and blend state ( AlphaBlend ).

Krautersuppe, an artist, a sound guy and myself are trying to complete a game. We first thought about doing rotation using 8 sprite frames, but realized how much work it was going to be for the artist, so decided to just do the rotation mathematically.

We are currently just throwing out ideas to each other and coding stuff up to see how things look, nothing concrete yet. We decided to stick with the chili framework as a way of honoring the person who taught us to code, plus the game won't be 3D so won't need the HW3D framework nor the GPU for speed, not yet anyway.

I think another reason is to not have any 3rd party dependencies if we can avoid it. If things get too hectic, it might be worth looking into DXTK and checking out the sprite batch, and sticking with D3D to get access to actual pixel shaders for effects.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4190
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Learned something today

Post by albinopapa » July 27th, 2020, 9:00 pm

Also, if you recall, I wanted to make a 2D drawing api that mimicked the style of the standard library, but haven't figured a few implementation details out yet.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3935
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Learned something today

Post by chili » July 28th, 2020, 2:00 am

So you're going directly with textured quad rendering instead of pixel buffer manipulation. I sort of want to do some videos on that someday, but I don't know if I'll ever get to it.

If you wanna max out the perf, definitely look into sprite batching with sprite atlases. You can also put all the corresponding geometry in a single buffer and uses offsets for the rendering, really cutting down on the number of pipeline state changes. Idk about using stuff like the geometry shader for generating the geometry from smaller parameters though.
Chili

albinopapa
Posts: 4190
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Learned something today

Post by albinopapa » July 28th, 2020, 6:52 am

So you're going directly with textured quad rendering instead of pixel buffer manipulation
Not sure what you mean by pixel buffer manipulations.
If you wanna max out the perf, definitely look into sprite batching with sprite atlases. You can also put all the corresponding geometry in a single buffer and uses offsets for the rendering
I've actually seen references to doing stuff like this for instancing. Create a large buffer for all the world matrices for instance that way you don't have to update individual buffers. Which I think would accomplish the same end result, higher frame rates with less pipeline state changes. When you say sprite atlas, do you mean texture atlas?

I've heard about using points to represent positions, then in the geometry shader extrapolate the rest of the vertices of a triangle or quad...mostly in the context of particles.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3935
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Learned something today

Post by chili » July 28th, 2020, 12:21 pm

Since the geometry doesn't need to be one connected mesh (use indexed triangle list), you can put the quads for many sprites into buffer and render them all with a single draw call, really cutting down overhead. Splitting resources on different channels depending on how dynamic can be huge too. For example, all tiles and other fixed sprites can be be in a single buffer, rendered with a single draw and "moved" (camera translated) by a vertex shader translation alone, no need to map and update coordinates. Dynamic sprites can be put on separate layers so you can update their positions and texture coordinates independently.
Chili

albinopapa
Posts: 4190
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Learned something today

Post by albinopapa » July 29th, 2020, 11:06 am

When I first heard of structured bindings, I recalled some detailed setup for getting it to work, but I'm guessing it had to do with classes and private members. Anyway, just realized it works with zero setup for structs which have no private members.
Vec2 pos = { 3, 4 };
auto[x, y] = pos;
// x == 3, y == 4;

I actually used it for a RectF:
RectF bounds = { 0, 0, 800, 600 };
auto[ left, top, right, bottom ] = bounds;

And here I thought it only worked with std::tuple and std::pair out of the box, didn't think it would be automatic for structs.

While it seems kind of pointless for RectF and Vec2, I mostly use structured bindings for std::pair ( and if I used std::tuple I'd us it for that as well ). All because thing.first and thing.second are nonsense and noise.

For instance, in chili's more recent video, he use std::unordered_map. With the map when you add something to it, you get something like an
std::pair<bool, std::unordered_map<type1, type2>::iterator>>

Since chili is a C++ God, he can easily just use if( !result.first ){ result.second.first++; } or something like that. However, it doesn't have to be so confusing.

Code: Select all

auto[ was_added, iterator ] = map.emplace( value );
if( !was_added ){
    auto[ key, value ] = *iterator;
    ++value;
}
When using structured bindings, the bindings are references, so using them is relatively cheap and it makes the code way more readable.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply