Hey!
My engine is currently setup for 2D rendering and now I just wanted to add the 3D feature so that by only adding the z-value could determine what object is infront or behind another one, instead of sorting the spritebuffer based on some layers.
So i thought that by giving the vertexattribs an extra float for z, make the sprite have a V3f instead of V2f for pos and glEnable(GL_DEPTH_TEST); and glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); I would then only be able to change the z-coordinate to make SPRITE zooom in/out.
It didn't work, so i wonder what are the minimal steps necesary to go from 2D -> 3D.
Must I use matrices here??
the vertex-shader im using is this:
VS.h
#version 330 core layout (location = 0) in vec3 pos; layout (location = 1) in vec4 col; layout (location = 2) in vec2 texCoord; out vec4 VS_col_out; out vec2 VS_texCoord_out; uniform vec2 winDim; uniform vec2 ballPos; void main() { vec4 v4_pos; v4_pos.x = pos.x - 1.0f; v4_pos.y = pos.y - 1.0f; v4_pos.z = pos.z; v4_pos.w = 1.0f; gl_Position = v4_pos; VS_col_out = col; VS_texCoord_out = texCoord; }
Changing z coordinate like you do won't do "zoom in/out". All it will is to change "layer" where it is drawn - in front/back of others.
To change size depending on distance, you need to use some kind of projection matrix, or explicitly change width/height of object you're rendering depending on z value.
Okay i see, but nothing happends when I change the Z value, all my tiles have z = 1.0f and my ship have a z = -1.0f but the tiles are "closer" to the camera and ship doesn't show. And also when i enable Depth-test and clear the depth-buffer-bit the transparent blending stops.
Initialize()
for(int y = 0; y < tm_dim.y; y++) { for(int x = 0; x < tm_dim.x; x++) { u32 i = x + (tm_dim.x * y); int rx = CJ_RandIRange(7, 9, CJ_RAND_INCLUDE); int ry = CJ_RandIRange(8, 10, CJ_RAND_INCLUDE); game->tilemap[i].pos = v3f(0.0f + (tp.x * x), 0.0f + (tp.y * y), 1.0f); game->tilemap[i].size = v3f(tp.x, tp.y, 0.0f); game->tilemap[i].col = v4f(1.0f, 1.0f, 1.0f, 1.0f); game->tilemap[i].tcoord_p = game->texture_map[0][i];//v2f(rx * tp.x, 1.0f - (ry * tp.y)); game->tilemap[i].tcoord_sz = v2f(1.0f * tp.x, 1.0f * tp.y); } } game->ship.sprite = Push(game, SPRITE, 1); game->ship.sprite->pos = v3f(0.5f, 0.5f, -1.0f); game->ship.sprite->size = v3f(0.1f, 0.15f, 0.0f); game->ship.sprite->col = v4f(1.0f, 1.0f, 1.0f, 1.0f); game->ship.sprite->tcoord_p = v2f(5.0f * tp.x, 1.0f - (2.0f * tp.y)); game->ship.sprite->tcoord_sz = v2f(1.0f * tp.x, 1.0f * tp.y); game->ship.hitpoints = 10;
Updating the vbo
void UpdateVBO_SPRITE(CJ_VBO *vbo, GAME_HANDLER *game) { CJ_VTX_SPRITE *pVertex = (CJ_VTX_SPRITE*)vbo->base; SPRITE *spr = (SPRITE*)game->sprite_batch.data; // Updating the data that's sent to the VBO for(u32 i = 0; i < game->sprite_batch.count; i++) { //V2f pos = spr[i].pos; V3f pos = spr[i].pos; V3f size = spr[i].size; V4f col = spr[i].col; V2f tCoord_p = spr[i].tcoord_p; V2f tCoord_sz = spr[i].tcoord_sz; pVertex[(i * 4) + 0].pos = v3f(pos.x, pos.y, pos.z); pVertex[(i * 4) + 1].pos = v3f(pos.x, pos.y + size.y, pos.z); pVertex[(i * 4) + 2].pos = v3f(pos.x + size.x, pos.y + size.y, pos.z); pVertex[(i * 4) + 3].pos = v3f(pos.x + size.x, pos.y, pos.z); pVertex[(i * 4) + 0].col = col; pVertex[(i * 4) + 1].col = col; pVertex[(i * 4) + 2].col = col; pVertex[(i * 4) + 3].col = col; pVertex[(i * 4) + 0].tCoord = v2f(tCoord_p.x, tCoord_p.y); pVertex[(i * 4) + 1].tCoord = v2f(tCoord_p.x, tCoord_p.y + tCoord_sz.y); pVertex[(i * 4) + 2].tCoord = v2f(tCoord_p.x + tCoord_sz.x, tCoord_p.y + tCoord_sz.y); pVertex[(i * 4) + 3].tCoord = v2f(tCoord_p.x + tCoord_sz.y, tCoord_p.y); } }
-1 and +1 values are right on the border of clipping. Use something that is between -1 and +1. For example, Like -0.1 and +0.1
Typically you use transformation matrix, to transform arbitrary z range you want to -1..+1 interval.
For alpha blending to work properly you will need to render in back-to-front order. Regardless of zbuffer. Because alpha blending is not commutative operation.
I looked at the wrong shader...
But let's say you want an explosion sprite to take place over an enemy ship. The Explosion sprite has transparency in it but since the explosion has a smaller z-value (closer to the camera) the transparency will block the enemy ship anyway.
How do you solve that problem usually?
Classically you solve it by sorting your sprites on cpu, and then drawing them in back-to-front order. Usually you don't have so many sprites that this would be a problem.
For complex 3d applications there are some more complex ways to render order independent transparency from arbitrary polygon rendering order - for example, by storing all overlapping source pixels for every framebuffer pixel in linked list, then sorting everything per pixel in correct order and resolving blended transparency in back-to-front with special compute shader.
http://developer.amd.com/wordpress/media/2013/06/2041_final.pdf
https://de.slideshare.net/hgruen/oit-and-indirect-illumination-using-dx11-linked-lists
https://on-demand.gputechconf.com/gtc/2014/presentations/S4385-order-independent-transparency-opengl.pdf
https://github.com/gangliao/Order-Independent-Transparency-GPU