View Single Post
Old 29th August 2005, 03:32 PM   #4
Andy
Administrator
Professional user
 
Andy's Avatar
 
Join Date: Jun 2003
Posts: 4,564
Default

You have the right concept.

Here's AC3D's internal code that calculates the normals.

Code:
	
	// get the crease angle in radians
	float rad_angle = cos(ob->crease_angle * M_PI / 180.0f);

...

		{
			// vertex index will hold a list of each surface that references the vertex
			// first, clear the lists
			for (List *p = ob->pointlist; p != NULL; p = p->next)
				{
				Vertex *v = (Vertex *)p->data;
				vertex_set_index(v, NULL);
				}

			// for each sv, add the surface to the list of surfaces in each vertex
			for (List *spp = ob->surfacelist; spp != NULL; spp = spp->next)
				{
				Surface *s = (Surface *)spp->data;
				
				for (List *svp = s->vertlist; svp != NULL; svp = svp->next)
					{
					SVertex *sv = (SVertex *)svp->data;

					list_add_item_head((List **)&(sv->v->index), s);
					}
				}


			for (List *sp = ob->surfacelist; sp != NULL; sp = sp->next)
				{
				Surface *s = (Surface *)sp->data;

				for (List *svp = s->vertlist; svp != NULL; svp = svp->next)
					{
					SVertex *sv = (SVertex *)svp->data;

					sv->normal = s->normal;

					if ((vertex_get_index(sv->v) == 0))
						{
						continue; // next please
						}

					// so, surface is shaded
					// fl is list of faces that refer to this vertex
					List *fl = (List *)vertex_get_index(sv->v);

					for (List *flp = fl; flp != NULL; flp = flp->next)
						{
						Surface *os = (Surface *)flp->data;

						// ignore if the same surface
						if (s != os)
							{	
							// even if the surface is flat, we still calculate the normals
							// the shading may change and this saves recalulating normals again

							// calc dot product of this surface plus attached
							float dot = (DOTPRODUCT(&s->normal, &os->normal));

							if (dot > rad_angle)
								{
								ADDPOINTS(&os->normal, &sv->normal);
								}
							}
						}

					normalize_point(&sv->normal);
					}
				}


			for (List *vp = ob->pointlist; vp != NULL; vp = vp->next)
				{
				Vertex *v = (Vertex *)vp->data;

				list_free((List **)&vertex_get_index(v));
						
				}



			}
Notes:

1) that the vertex_index stuff is internal and you'll need to use another way of storing the vertex info.

2) The surface flag for shading is used when drawing the model - if a surface is 'smooth', the vertex normals are used. If a surface is 'flat', the surface-normal is used for each vertex.

3) the above code calculates the all normals in an object (not just those changed recently). Some bits of internal code have been removed but I've hopefully left the important stuff. If the crease angle is 0 or 180, you can optimize a bit.
Andy is offline   Reply With Quote