3D Fundamentals Texture Mapping Geometry Question

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

3D Fundamentals Texture Mapping Geometry Question

Post by WilsonHuang » September 25th, 2020, 11:12 am

I'm at 3D Fundamentals Texture Mapping series. I don't understand "unfolding the geometry of the cube" part video.
Chili gives following code:

Code: Select all

	CubeFolded( float size )
	{
		const float side = size / 2.0f;
		vertices.emplace_back( -side,-side,-side ); // 0
		tc.emplace_back( 1.0f,0.0f );
		vertices.emplace_back( side,-side,-side ); // 1
		tc.emplace_back( 0.0f,0.0f );
		vertices.emplace_back( -side,side,-side ); // 2
		tc.emplace_back( 1.0f,1.0f );
		vertices.emplace_back( side,side,-side ); // 3
		tc.emplace_back( 0.0f,1.0f );
		vertices.emplace_back( -side,-side,side ); // 4
		tc.emplace_back( 1.0f,1.0f );
		vertices.emplace_back( side,-side,side ); // 5
		tc.emplace_back( 0.0f,1.0f );
		vertices.emplace_back( -side,side,side ); // 6
		tc.emplace_back( 1.0f,0.0f );
		vertices.emplace_back( side,side,side ); // 7
		tc.emplace_back( 0.0f,0.0f );
		vertices.emplace_back( -side,-side,-side ); // 8
		tc.emplace_back( 1.0f,0.0f );
		vertices.emplace_back( side,-side,-side ); // 9
		tc.emplace_back( 0.0f,0.0f );
		vertices.emplace_back( -side,-side,-side ); // 10
		tc.emplace_back( 0.0f,1.0f );
		vertices.emplace_back( -side,-side,side ); // 11
		tc.emplace_back( 0.0f,0.0f );
		vertices.emplace_back( side,-side,-side ); // 12
		tc.emplace_back( 1.0f,1.0f );
		vertices.emplace_back( side,-side,side ); // 13
		tc.emplace_back( 1.0f,0.0f );
	}
How to calculate the vertices and tc position?
For example ( -side,-side,-side ) and ( 1.0f,0.0f ).
I can understand when cube has 8 vertices in 3D space, but confused when cube become net (14 vertices) in 3D.
Also how to determine the order of vertices position?

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

Re: 3D Fundamentals Texture Mapping Geometry Question

Post by albinopapa » September 25th, 2020, 7:52 pm

Vertex positions are based on the distance from some origin of the model. For the cube it's the origin is the center and the vertices' positions are some distance from the center.

The order in which you put those vertices depends on what API you are using and how it calculates whether a triangle is facing toward the camera or away. This is called the winding order. If I recall correctly, DX uses a clockwise winding order. Since the 3D Fundamentals framework is based on D3D, it too uses clockwise winding order. One of the issues I've had over and over while trying to generate my own geometry like this is making sure that mentally you rotate the cube so that each face is facing you when you list out the vertices. Same holds true for any shape you are trying to generate.

Texture coordinates describe how far into a texture a vertex would be if flattened and overlaid on top of it. In the case of the cube in this example, each face would take up the entire texture since the coordinates are from 0.0 - 1.0. You could also unfold the cube so look like a cross where all faces share the same texture. The texture coordinates for each vertex would then be some scaled down version to fit in the range of 0.0 - 1.0.

Say your texture is 100x100 ( normally you'd want a texture to be a power of 2, but this is example ) and your cube was unfolded instead of each face having it's own texture. Again, the cube laid out to look like a cross, the top 2 vertices might be the bottom edge of the top face. Assuming the mesh is stretched to go from top to bottom of the texture and the mesh is centers horizontally.

Code: Select all

   _
 _|_|_
|_|_|_|
  |_|
  |_|
As you can see, there are 6 faces and 14 vertices.
Starting from the top of the ascii diagram the faces might be:
top
left, front, right
bottom
back

So, the texture coordinates might be something like:
top face:
/*top edge*/ ( .40f, .00f ), ( .60f, .00f ) // pixel position in 100x100 texture ( 39, 0 )
/*bottom edge*/ ( .40f, .25f ), ( .60f, .25f ) // pixel position in 100x100 texture ( 39, 25 )

left face:
/*top edge*/ ( .20f, .25f ), ( .40f, .25f ) // pixel position in 100x100 texture ( 19, 24 ), ( 39, 24 )
/*bottom edge*/ ( .20f, .50f ), ( .40f, .50f ) // pixel position in 100x100 texture ( 19, 49 ), ( 39, 49 )

front face:
/*top edge*/ ( .40f, .25f ), ( .60f, .25f ) // pixel position in 100x100 texture ( 39, 24 ), ( 59, 24 )
/*bottom edge*/ ( .40f, .50f ), ( .60f, .50f ) // pixel position in 100x100 texture ( 39, 49 ), ( 59, 49 )

right face:
/*top edge*/ ( .60f, .25f ), ( .80f, .25f ) // pixel position in 100x100 texture ( 59, 24 ), ( 79, 24 )
/*bottom edge*/ ( .60f, .50f ), ( .80f, .50f ) // pixel position in 100x100 texture ( 59, 49 ), ( 79, 49 )

bottom face:
/*top edge*/ ( .40f, .50f ), ( .60f, .50f ) // pixel position in 100x100 texture ( 39, 49 ), ( 59, 49 )
/*bottom edge*/ ( .40f, .75f ), ( .60f, .75f ) // pixel position in 100x100 texture ( 39, 74 ), ( 59, 74 )

back face:
/*top edge*/ ( .40f, .75f ), ( .60f, .75f ) // pixel position in 100x100 texture ( 39, 74 ), ( 59, 74 )
/*bottom edge*/ ( .40f, 1.0f ), ( .60f, 1.0f ) // pixel position in 100x100 texture ( 39, 99 ), ( 59, 99 )

Here instead of using the range 1-100 or 0-100, I used 0-99 because it makes indexing easier, but the way chili does it is 0-100 and just clamps the upper value to to the range 0-99 so any TC that is < 0 ends up getting index 0 and any TC that is >= 1.0 gets index 99.
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: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D Fundamentals Texture Mapping Geometry Question

Post by albinopapa » September 25th, 2020, 7:55 pm

I showed 24 texture coordinates, but some are shared. If you omit duplicates, you get 14 unique texture coordinates.
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

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: 3D Fundamentals Texture Mapping Geometry Question

Post by WilsonHuang » September 26th, 2020, 4:33 am

albinopapa wrote:
September 25th, 2020, 7:52 pm
Vertex positions are based on the distance from some origin of the model. For the cube it's the origin is the center and the vertices' positions are some distance from the center.

The order in which you put those vertices depends on what API you are using and how it calculates whether a triangle is facing toward the camera or away. This is called the winding order. If I recall correctly, DX uses a clockwise winding order. Since the 3D Fundamentals framework is based on D3D, it too uses clockwise winding order. One of the issues I've had over and over while trying to generate my own geometry like this is making sure that mentally you rotate the cube so that each face is facing you when you list out the vertices. Same holds true for any shape you are trying to generate.

Texture coordinates describe how far into a texture a vertex would be if flattened and overlaid on top of it. In the case of the cube in this example, each face would take up the entire texture since the coordinates are from 0.0 - 1.0. You could also unfold the cube so look like a cross where all faces share the same texture. The texture coordinates for each vertex would then be some scaled down version to fit in the range of 0.0 - 1.0.

Say your texture is 100x100 ( normally you'd want a texture to be a power of 2, but this is example ) and your cube was unfolded instead of each face having it's own texture. Again, the cube laid out to look like a cross, the top 2 vertices might be the bottom edge of the top face. Assuming the mesh is stretched to go from top to bottom of the texture and the mesh is centers horizontally.

Code: Select all

   _
 _|_|_
|_|_|_|
  |_|
  |_|
As you can see, there are 6 faces and 14 vertices.
Starting from the top of the ascii diagram the faces might be:
top
left, front, right
bottom
back

So, the texture coordinates might be something like:
top face:
/*top edge*/ ( .40f, .00f ), ( .60f, .00f ) // pixel position in 100x100 texture ( 39, 0 )
/*bottom edge*/ ( .40f, .25f ), ( .60f, .25f ) // pixel position in 100x100 texture ( 39, 25 )

left face:
/*top edge*/ ( .20f, .25f ), ( .40f, .25f ) // pixel position in 100x100 texture ( 19, 24 ), ( 39, 24 )
/*bottom edge*/ ( .20f, .50f ), ( .40f, .50f ) // pixel position in 100x100 texture ( 19, 49 ), ( 39, 49 )

front face:
/*top edge*/ ( .40f, .25f ), ( .60f, .25f ) // pixel position in 100x100 texture ( 39, 24 ), ( 59, 24 )
/*bottom edge*/ ( .40f, .50f ), ( .60f, .50f ) // pixel position in 100x100 texture ( 39, 49 ), ( 59, 49 )

right face:
/*top edge*/ ( .60f, .25f ), ( .80f, .25f ) // pixel position in 100x100 texture ( 59, 24 ), ( 79, 24 )
/*bottom edge*/ ( .60f, .50f ), ( .80f, .50f ) // pixel position in 100x100 texture ( 59, 49 ), ( 79, 49 )

bottom face:
/*top edge*/ ( .40f, .50f ), ( .60f, .50f ) // pixel position in 100x100 texture ( 39, 49 ), ( 59, 49 )
/*bottom edge*/ ( .40f, .75f ), ( .60f, .75f ) // pixel position in 100x100 texture ( 39, 74 ), ( 59, 74 )

back face:
/*top edge*/ ( .40f, .75f ), ( .60f, .75f ) // pixel position in 100x100 texture ( 39, 74 ), ( 59, 74 )
/*bottom edge*/ ( .40f, 1.0f ), ( .60f, 1.0f ) // pixel position in 100x100 texture ( 39, 99 ), ( 59, 99 )

Here instead of using the range 1-100 or 0-100, I used 0-99 because it makes indexing easier, but the way chili does it is 0-100 and just clamps the upper value to to the range 0-99 so any TC that is < 0 ends up getting index 0 and any TC that is >= 1.0 gets index 99.
Thanks for explain. I made a graph to see if I'm understand this concept. The attachment is graph
Texture Mapping.png
(129.39 KiB) Not downloaded yet
If there's any mistake, please point out and help me correct it.

The cube center is (0,0,0) and the length is 1. Also, I made net of cube upside down cross. Say the top-left is the first vertex (0 on the net), DX uses clockwise winding order, so the order (the number of net) is like the graph shows. (Is it correct?)
The texture is upside down on the net (square 9687) of front face, so the position of TC is like what it shows on the net.
The number 2 vertex of the cube is the number 0 of the net, so the first vertex is (-0.5, 0.5, 0.5), next is (0.5,0.5,0.5) and so on.

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

Re: 3D Fundamentals Texture Mapping Geometry Question

Post by albinopapa » September 26th, 2020, 8:03 pm

Okay, as far as numbering the vertices clockwise or counter clockwise, I meant how you describe triangles not necessarily the list of vertices of the mesh. Plus, your vertices in the UV map ( what you're calling the net ) don't line up with the vertex positions in the cube diagram on the right.

For instance, you have vertex 0 on the cube as the bottom left of what I will assume is the front face. So that vertex needs to correspond to what would be the front face of the UV map. I'm not entirely sure which square represents the front face on the uv map in your diagram. If it's like in my example, just upside down, then you'd just have to rotate all the tc's I wrote.

Your texture coordinates still are ( 0, 0 ) and ( 0, 1 ) for examples. If the UV map is to be on a single texture, then you will need to calculate a value between 0 and 1 for the U and the V ( X and Y ).

Let's keep it simple and say you wanted to just draw a single 2D square ( a sprite for instance ). Now if this square has it's own texture, then you'd want the texture coordinates to go from ( 0, 0 ) in the top left to ( 1, 1 ) at the bottom right.

Now let's say that this square's texture is part of a larger image, where the texture of the square is just a portion of the larger image. This larger image is sometimes or often called a "texture atlas". If the part of the image representing the texture for this sprite is in the top corner and takes up a quarter of the image, then the texture coordinates for the sprite would be something like:

top left: ( 0, 0 )
top right: ( .5, 0 )
bottom left: ( 0, .5 )
bottom right: ( .5, .5 )

As you can see, we defined texture coordinates that only take up the top quadrant of the larger image going from top left at ( 0, 0 ) to the center ( .5, .5 ).

Now, if you take that information and apply it to having 6 squares representing the 6 faces of the cube all getting their texture data from a single image, it should be obvious that each square can't have a full range going from 0.0-1.0, but instead only takes up fractions of the entire image.

All that being said, chili does have each face's texture coordinates going from 0-1, but I believe he loads 6 colors or 6 textures and giving each face an index in which he uses in the pixel shader to determine which face gets which color or texture.

Using a texture atlas saves on memory transfers. You put all your textures into a single image, have your texture coordinates align with the sections of that image, now you only load that texture atlas instead of multiple textures. The rest takes care of itself.
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

WilsonHuang
Posts: 44
Joined: February 13th, 2019, 3:23 am

Re: 3D Fundamentals Texture Mapping Geometry Question

Post by WilsonHuang » September 28th, 2020, 4:08 am

I finally figure out how this work by drawing texture on the cube face by face using my own texture! Please ignore my previous post.
Here is how I work:
Say we have a stickman texture with green head, white body, blue right hand, and red left hand
Stickman.png
Stickman.png (2.4 KiB) Viewed 3767 times
We also have a unfold cube with numbered vertices and named faces
Unfold Cube.png
(34 KiB) Not downloaded yet
We want to paint front face as same direction as the texture facing us
The code will be:

Code: Select all

vertices.emplace_back(-side, -side, -side); // 0
texturePos.emplace_back(0.0f, 1.0f);
vertices.emplace_back(side, -side, -side); // 1
texturePos.emplace_back(1.0f, 1.0f);
vertices.emplace_back(-side, side, -side); // 2
texturePos.emplace_back(0.0f, 0.0f);
vertices.emplace_back(side, side, -side); // 3
texturePos.emplace_back(1.0f, 0.0f);

The drawing order of vertices
{
	0,2,1, 2,3,1
}
We will paint right face next.
We want the stickman shake hands around the cube. The hand shook each other has same color.
positions.png
(31.65 KiB) Not downloaded yet
The right face code will be:

Code: Select all

//We need create 3 vertices to made right face  
vertices.emplace_back(side, side, -side); // 4
texturePos.emplace_back(1.0f, 0.0f);
vertices.emplace_back(side, side, side); // 5
texturePos.emplace_back(0.0f, 0.0f);
vertices.emplace_back(side, -side, side); // 6
texturePos.emplace_back(0.0f, 1.0f);

The drawing order of vertices
{
	0,2,1, 2,3,1,
	6,1,4, 4,5,6
}
We can use same way to draw back and left face

Code: Select all

//Back
vertices.emplace_back(side, side, side); // 7
texturePos.emplace_back(0.0f, 0.0f);
vertices.emplace_back(-side, side, side); // 8
texturePos.emplace_back(1.0f, 0.0f);
vertices.emplace_back(-side, -side, side); // 9
texturePos.emplace_back(1.0f, 1.0f);

//Left
vertices.emplace_back(-side, side, side); // 10
texturePos.emplace_back(1.0f, 0.0f);
vertices.emplace_back(-side, side, -side); // 11
texturePos.emplace_back(0.0f, 0.0f);

The drawing order of vertices
{
	0,2,1, 2,3,1,
	6,1,4, 4,5,6,
	6,7,8, 6,8,9,
	9,10,11, 9,11,0
}
Now we have 4 faces. For the top face, we want the stickman upside down and mirror left-right when facing us.
The vertices we created now for top face doesn't match the requirement. So we need create 2 more vertices to made top face

Code: Select all

vertices.emplace_back(-side, side, side);  // 12
texturePos.emplace_back(1.0f, 1.0f);
vertices.emplace_back(side, side, side);  // 13
texturePos.emplace_back(0.0f, 1.0f);
vertices.emplace_back(-side, side, -side); // 14
texturePos.emplace_back(1.0f, 0.0f);
vertices.emplace_back(side, side, -side);   // 15
texturePos.emplace_back(0.0f, 0.0f);

The drawing order of vertices
{
	0,2,1, 2,3,1,
	6,1,4, 4,5,6,
	6,7,8, 6,8,9,
	9,10,11, 9,11,0,
	12,13,14, 13,15,14
}
We want stickman upside down when we face the bottom. We only need to create 2 vertices to create bottom face.

Code: Select all

vertices.emplace_back(-side, -side, side);  // 16
texturePos.emplace_back(0.0f, 0.0f);
vertices.emplace_back(side, -side, side);   // 17
texturePos.emplace_back(1.0f, 0.0f);

The drawing order of vertices
{
	0,2,1, 2,3,1,
	6,1,4, 4,5,6,
	6,7,8, 6,8,9,
	9,10,11, 9,11,0,
	12,13,14, 13,15,14,
	16,0,17, 0,1,17
}		
That's it. We paint the texture to the cube with 18 vertices.
I think the key concept is that the number of vertices we need depends how we paint the texture on the surface.

Post Reply