# libGDX upload z-axis of sprite to graphics card

Background: I want to obtain each fragments position via vertex interpolation to then calculate the light vector for phong shading (L = [Fragment pos] - [light source pos]).

Problem:

At the moment I am using libGDX's com.badlogic.gdx.graphics.g2d.Sprites to upload my 2d sprites via the batch to the graphics card. However they only transport the x and y information for each vertex ( I think in the shader z is 0). I also want to upload the z axis of the sprite for use with normal map based pixel shading (calculate the vector of the incoming light).

Should I use a com.badlogic.gdx.graphics.Mesh for that or can I extend the Sprite class and somehow put the z axis in the vertices float[] array? If I should do that, how do I do this?

• Have you seen this question? – ashes999 Aug 6 '15 at 10:14
• As far as I understood the answers keep the z axis on the cpu. – Benedikt S. Vogler Aug 6 '15 at 10:27
• As far as my research goes the best way is to do basically reimplement the Sprite by using the "Mesh" class but use a 3D coordinate instead in a vertex attribute. – Benedikt S. Vogler Aug 6 '15 at 11:41

You're mixing terms and techniques here, a 2D-Texture has no z-dimension. What you actually want for your normal-mapping is to fetch the texel t from the image using the usual 2D texture-coordinates and use these color-values t.rgb as a normal-vector.

• I want to extend my normal map shading (which is working) with the information of the position of the texel. I added an image to further describe my problem. I think I did not well in explaining what I want. I know that a 2d texture has no z dimension, however the quad has four vertices with each a coordinates with three components which then get interpolated in the fragment shader. – Benedikt S. Vogler Aug 6 '15 at 9:58
• Yes, this might be true, but your textures still have only 2 dimensions, thats what texture-coordinates are for. Usually, you never use your 3d-coordinates to fetch texels from a texture. – tkausl Aug 6 '15 at 10:17
• Yes, for the texture lookup I still have to use 2d texture coordinates. I want to calculate for each texel a vector to a light source for which I need 3d coordinates which is not related to the texture lookup (I hope). – Benedikt S. Vogler Aug 6 '15 at 10:23
• Yes, and this is now what normal-maps are for. You still have your 2D-Texture with 2D-Texture-coordinates but instead of using rgb as color-values as you usually do with textures you interpret rgb as a unit-vector, thats your normal-vector. – tkausl Aug 6 '15 at 10:25
• Normal maps give you the normal vector. However you also need the light vector / incoming vector which is "fragment position - light source pos". I am trying to get this to work fragment based. You are missing that I want to obtain the fragment position via interpolated vertex coordinates. Hope this helps to make things more clear. – Benedikt S. Vogler Aug 6 '15 at 10:35

To solve this the libGDX SpriteBatch can me modified to add another component to the coordinate in the vertex array.

1. Copy the source code of SpriteBatch to a new class.
2. Copy the source code of Sprite to a new class.
3. In the sprite class increase the field VERTEX_SIZE by 1.
4. Add the z component to methods like translate and getVertices()
5. In the SpriteBatch class add Z1-Z4 to the list of constants obtained in Batch.

Should look like this:

static public final int X1 = 0;
static public final int Y1 = 1;
static public final int Z1 = 2;
static public final int C1 = 3;
static public final int U1 = 4;
...


In the constructor change the vertex attributes to 3

new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE),


and in the line above the size * 10 to a size * 10, because of the four added vertex values.

Now use world coordinates for your sprites and pass the projection view matrix to the batch, so it gets uploaded to the graphic card. Now world and screen space coordinates are available in the fragment shader.

Beware that the depth buffer is disabled when using the spriteBatch. You can enable it by removing the

Gdx.gl.glDepthMask(false);


Source code can be found here. Maybe I forgot to mention something.