Sign in to follow this  

Face normals for pyramid

This topic is 408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Recently, I learned about face normals, and i'm a bit confused. I need to use them for a directional light, but I've been having trouble calculating them. I would appreciate if someone types the code out for calculating them and explains it.

 

This is my code for generating a pyramid:  

GeneratePyramid(float baseWidth, float baseDepth, float apexHeight, MeshData& meshData) {

	float halfWidth = baseWidth * 0.5f;
	float halfDepth = baseDepth * 0.5f;

	Vertex v[5];

	/*
	        v[2]
	         /\\ 
	        /  \\
	v[4]   /    \\  v[3]
	v[0]  /______\/  v[1]

	*/



	v[0] = Vertex(-halfWidth, 0, -halfDepth);
	v[1] = Vertex(halfWidth, 0, -halfDepth);
	v[2] = Vertex(0, apexHeight, 0); // apex
	v[3] = Vertex(halfWidth, 0, halfDepth);
	v[4] = Vertex(-halfWidth, 0, halfDepth);

	meshData.vertices.assign(&v[0], &v[5]);

	unsigned int i[18] = {
		0, 2, 1,
		1, 2, 3,
		3, 2, 4,
		4, 2, 0,
		0, 1, 4,
		1, 3, 4

	};

	meshData.indices.assign(&i[0], &i[18]);
} 

the struct MeshData is simply defined as: 

struct MeshData {
		std::vector<Vertex> vertices;
		std::vector<unsigned int> indices;
}; 

and the Vertex struct is defined as: 

struct Vertex {
		Vertex() {};
		Vertex(float x, float y, float z);

		XMFLOAT3 pos;
}; 

I would like GeneratePyramid() to also calculate the normals. Should I add an "XMFLOAT3 normal" member to the Vertex struct? And if so, how would I use that to calculate them in GeneratePyramid()?
 

Thanks in advance! 

 

Extra:

I read that you don't need vertex normals for pyramids since it has sharp edges, but I would also like to know how you would calculate them.

 

 

Share this post


Link to post
Share on other sites

You could probably find a tutorial for calculating both face and vertex normals with a quick search, luckily it is a fairly easy process. Call each triangle vertex A, B and C for simplicity sake here, you create two vectors edge1 and edge2 by doing edge1 = B-A and edge2 = C-A (a vector that points from A to B and one that points from A to C). Once you have those two you work out the cross product of them, normalize it and that is then your face normal. Do that for each triangle. It really is a simple process. If you find that the normal faces inwards instead of outwards then swap around edge1 and edge2 in the cross product.

 

Vertex normals are a fair bit more work, first you need to have already calculated face normals, then you need a way of knowing which faces are attached to each vertex. Then for every vertex you work out a weighted average of all the normals of the faces attached to that vertex and normalise it. Something like:

 

for each vertex

   normal = zero;

   for each attached face

      normal += face.normal * face.surfaceArea // You probably want bigger faces to contribute more

   Normalize(normal);

 

You should probably check the normal isn't zero at the end. There are other methods for averaging the face normals but I find surface area is a good choice (of course you then need to work out the surface area). Whatever you choose you should try to have smaller faces contributing less than larger ones or it ends up looking odd.

 

Apparently you can workout the area of a triangle by halving the length of the cross product of the edges (which you do while calculating the face normal). [url=http://math.stackexchange.com/questions/738236/how-to-calculate-the-area-of-a-triangle-abc-when-given-three-position-vectors-a]source[/url]

 

It's worth noting that for your pyramid to have per vertex normals you would need to duplicated vertices, each triangle face would have it's own 3 vertices and the two for the base can share 4 vertices.

Edited by Nanoha

Share this post


Link to post
Share on other sites
Out in the real world, normals come from artists and the art tools.

Consider that normals can be whatever the artist wants them to be. They may have created something they want to appear smooth and round, with normals that continuously curve around edges, or they may have intended the same model to have facets and sharp corners at every intersection.

Even with the pyramid described, the lighting could be made to have sharp angles, or appear to bend around a curve at the edges. The program doesn't know the difference, all it sees is the points but not the intent. The modeler knows the intent and can give the normals that match.

Share this post


Link to post
Share on other sites

Thanks Nanoha, I followed your advice and made the face normal (I ended up making a Face struct that holds an array of 3 Vertex objects. Then, I made a std::vector of Face structs in my MeshData, and looped through the number of Faces and calculated the normal there).

 

Vertex normals are a fair bit more work, first you need to have already calculated face normals, then you need a way of knowing which faces are attached to each vertex

 

This may be a dumb question, but how would you determine which faces share which vertices? Is there a way other than looking at the actual vertex data? 

----

 

Out in the real world, normals come from artists and the art tools.


Consider that normals can be whatever the artist wants them to be. They may have created something they want to appear smooth and round, with normals that continuously curve around edges, or they may have intended the same model to have facets and sharp corners at every intersection.

Even with the pyramid described, the lighting could be made to have sharp angles, or appear to bend around a curve at the edges. The program doesn't know the difference, all it sees is the points but not the intent. The modeler knows the intent and can give the normals that match.

 

Then I can't wait to get out to the real world ;P I'm currently reading an introductory book to DirectX, and so far we're hard-coding all the vertices and indicies of the shapes we're making within the program. The book will eventually be teaching me how to load files from modeling programs, though. Doing this was mostly for the sake of learning how to calculate light, which required the normals. I understand what you're saying though, my wording was a bit off. I meant to say that the pyramid i'm trying to make doesn't need per vertex normals, not pyramids in general.

 

 

 

Share this post


Link to post
Share on other sites
This may be a dumb question, but how would you determine which faces share which vertices? Is there a way other than looking at the actual vertex data? 

 

That is a very good question and it is exactly as you say, you look at the data. At some point you need to do a bit of work to build up this information, you said you have made a Face struct, hopefully in that you also have details about the indices that make up that face (e.g. face 0 has indices 0, 2, 1). For each vertex, look through all those faces and if they contain the index of the vertex you are checking then that is an attached face. In your above code if I look at vertex 0 I can see that it is used by triangles 0, 3 and 4. Vertex 1 is used by 0, 1, 4 and 5. I'd use those respective face normals when calculating the vertex normal.

 

With the pyramid as it is though it won't have vertex normals as you expect it to have, it'll be some strange smooth looking thing, to have sharp edges you need to have more vertices. See my earlier point about having to duplicate vertices.

Edited by Nanoha

Share this post


Link to post
Share on other sites

With the pyramid as it is though it won't have vertex normals as you expect it to have, it'll be some strange smooth looking thing, to have sharp edges you need to have more vertices. See my earlier point about having to duplicate vertices.

 

 

Sorry, I'm a bit confused haha. If I were to duplicate my vertices and have each Face struct have 3 distinct vertices, and then calculated vertex normals for all the vertices, wouldn't that have the same effect as simply calculating the face normals? So for smooth shading, you would need vertices that are shared, and if you wish for hard edges for a shape like a pyramid or a cube, you would duplicate the vertices so they're distinct and they don't take the average? Is that why when you want sharp edges, you can just use face normals rather than calculating per vertex normals?

Share this post


Link to post
Share on other sites

 

With the pyramid as it is though it won't have vertex normals as you expect it to have, it'll be some strange smooth looking thing, to have sharp edges you need to have more vertices. See my earlier point about having to duplicate vertices.

 

 

Sorry, I'm a bit confused haha. If I were to duplicate my vertices and have each Face struct have 3 distinct vertices, and then calculated vertex normals for all the vertices, wouldn't that have the same effect as simply calculating the face normals? So for smooth shading, you would need vertices that are shared, and if you wish for hard edges for a shape like a pyramid or a cube, you would duplicate the vertices so they're distinct and they don't take the average? Is that why when you want sharp edges, you can just use face normals rather than calculating per vertex normals?

 

 

Yeah, that's a good summary. The only faces that would share vertices for a pyramid would be the base. Most of the time you will want to have per vertex normals but also have duplicates so you can have both smooth areas and hard edges. Think of something like a half sphere, all the top would be nice and smooth but then the flat side would have a hard edge.

Edited by Nanoha

Share this post


Link to post
Share on other sites

This topic is 408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this