lớn bring some life to lớn the currently đen abyss of our trò chơi world, we will render sprites to fill the void. A sprite has many definitions, but it"s effectively not much more than a 2 chiều image used together with some data to lớn position it in a larger world (e.g. Position, rotation, & size). Basically, sprites are the render-able image/texture objects we use in a 2 chiều game.Bạn đang xem: Lách 2d full màn hình
We can, just like we did in previous chapters, create a 2d shape out of vertex data, pass all data khổng lồ the GPU, & transform it all by hand. However, in a larger application like this we rather have some abstractions on rendering 2 chiều shapes. If we were lớn manually define these shapes & transformations for each object, it"ll quickly get messy.
In this chapter we"ll define a rendering class that allows us lớn render a large amount of unique sprites with a minimal amount of code. This way, we"re abstracting the game play code from the gritty OpenGL rendering code as is commonly done in larger projects. First, we have to lớn set up a proper projection matrix though.
Bạn đang xem: Prerendered Or Real Time
2D projection matrix
We know from the coordinate systems chapter that a projection matrix converts all view-space coordinates khổng lồ clip-space (and then to normalized device) coordinates. By generating the appropriate projection matrix we can work with different coordinates that are easier to lớn work with, compared lớn directly specifying all coordinates as normalized device coordinates.
We don"t need any perspective applied lớn the coordinates, since the trò chơi is entirely in 2D, so an orthographic projection matrix would suit the rendering quite well. Because an orthographic projection matrix directly transforms all coordinates to normalized device coordinates, we can choose khổng lồ specify the world coordinates as screen coordinates by defining the projection matrix as follows:
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f); The first four arguments specify in order the left, right, bottom, và top part of the projection frustum. This projection matrix transforms all x coordinates between 0 và 800 khổng lồ -1 & 1, and all y coordinates between 0 & 600 to -1 & 1. Here we specified that the top of the frustum has a y coordinate of 0, while the bottom has a y coordinate of 600. The result is that the top-left coordinate of the scene will be at (0,0) & the bottom-right part of the screen is at coordinate (800,600), just lượt thích screen coordinates; the world-space coordinates directly correspond to the resulting pixel coordinates.
This allows us to lớn specify all vertex coordinates equal khổng lồ the px coordinates they end up in on the screen, which is rather intuitive for 2 chiều games.
Rendering an actual sprite shouldn"t be too complicated. We create a textured quad that we can transform with a mã sản phẩm matrix, after which we project it using the previously defined orthographic projection matrix.Since Breakout is a single-scene game, there is no need for a view/camera matrix. Using the projection matrix we can directly transform the world-space coordinates khổng lồ normalized device coordinates.
lớn transform a sprite, we use the following vertex shader:
#version 330 corelayout (location = 0) in vec4 vertex; // out vec2 TexCoords;uniform mat4 model;uniform mat4 projection;void main() TexCoords = vertex.zw; gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0); cảnh báo that we store both the position and texture-coordinate data in a single vec4 variable. Because both the position & texture coordinates contain two floats, we can combine them in a single vertex attribute.
The fragment shader is relatively straightforward as well. We take a texture and a màu sắc vector that both affect the final color of the fragment. By having a uniform màu sắc vector, we can easily change the màu sắc of sprites from the game-code:
#version 330 corein vec2 TexCoords;out vec4 color;uniform sampler2D image;uniform vec3 spriteColor;void main() color = vec4(spriteColor, 1.0) * texture(image, TexCoords); khổng lồ make the rendering of sprites more organized, we define a SpriteRenderer class that is able to lớn render a sprite with just a single function. Its definition is as follows:
First, let"s delve into the initRenderData function that configures the quadVAO:
void SpriteRenderer::initRenderData() // configure VAO/VBO unsigned int VBO; float vertices = // pos // tex 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f ; glGenVertexArrays(1, &this->quadVAO); glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindVertexArray(this->quadVAO); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); Here we first define a set of vertices with (0,0) being the top-left corner of the quad. This means that when we apply translation or scaling transformations on the quad, they"re transformed from the top-left position of the quad. This is commonly accepted in 2 chiều graphics and/or GUI systems where elements" positions correspond khổng lồ the top-left corner of the elements.
Next we simply sent the vertices to lớn the GPU và configure the vertex attributes, which in this case is a single vertex attribute. We only have lớn define a single VAO for the sprite renderer since all sprites nội dung the same vertex data.
Rendering sprites is not too difficult; we use the sprite renderer"s shader, configure a mã sản phẩm matrix, and set the relevant uniforms. What is important here is the order of transformations:
void SpriteRenderer::DrawSprite(Texture2D &texture, glm::vec2 position, glm::vec2 size, float rotate, glm::vec3 color) // prepare transformations this->shader.Use(); glm::mat4 mã sản phẩm = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(position, 0.0f)); model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); mã sản phẩm = glm::rotate(model, glm::radians(rotate), glm::vec3(0.0f, 0.0f, 1.0f)); mã sản phẩm = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); mã sản phẩm = glm::scale(model, glm::vec3(size, 1.0f)); this->shader.SetMatrix4("model", model); this->shader.SetVector3f("spriteColor", color); glActiveTexture(GL_TEXTURE0); texture.Bind(); glBindVertexArray(this->quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); When trying lớn position objects somewhere in a scene with rotation and scaling transformations, it is advised lớn first scale, then rotate, & finally translate the object. Because multiplying matrices occurs from right khổng lồ left, we transform the matrix in reverse order: translate, rotate, and then scale.
The rotation transformation may still seem a bit daunting. We know from the transformations chapter that rotations always revolve around the origin (0,0). Because we specified the quad"s vertices with (0,0) as the top-left coordinate, all rotations will rotate around this point of (0,0). The origin of rotation is at the top-left of the quad, which produces undesirable results. What we want to vì is move the origin of rotation to lớn the center of the quad so the quad neatly rotates around this origin, instead of rotating around the top-left of the quad. We solve this by translating the quad by half its size first, so its center is at coordinate (0,0) before rotating.