[ Pobierz całość w formacie PDF ]
.bn-1, any vector v is a linear combination of the set of the vectors ifthe following equation can be satisfied:where k0.kn-1are scalars.That is, if you want to get to v, you can start at the origin and walk along any or all ofthe vectors some amount and reach v.You can say the set of b vectors is linearly independent if no single b vector is a linearcombination of the others.The point3 StructureIt is always useful to design a class to encapsulate a generic 3D point.The class name I use is point3.Unlike most of the other classes you have seen so far, the intent of the point3 structure is to act as amathematical primitive like float or int.The 3 suffix denotes the dimension of the point.I'll also define 2Dand 4D versions of points, which are named point2 and point4, respectively.Listing 5.1: The point3 structure (defined in point3.h)struct point3{union{struct{float x,y,z; // 3 real components of the vector};float v[3]; // Array access useful in for loops};171 // Default constructorpoint3(){}// Construct a point with 3 given inputspoint3( float X, float Y, floatZ):x(X), y(Y), z(Z){}//.more will go in here.};This class uses a union in conjunction with a nameless struct.If you've never encountered unionsbefore, a union is used to name components that share memory.So, in the above code, the y variableand the v[1] variable represent the same piece of memory; when one of them changes, both of themchange.A nameless struct is used to let you define the x, y, and z components as one atomic unit(since I don't want them to each be referring to the same piece of memory).This way you can use thefamiliar x,y,z notation for most of the code, but maintain the ability to index into an array for iteration.AsideThe non-default constructor uses initialization lists.C++ classes should use thesewhenever possible.They clarify the intent of the code to the compiler, which lets it doits job better (it has a better chance to inline the code, and the code will end up beingconsiderably more efficient, especially for complex structures).Finally, you may wonder why I'm choosing floats (32 bits/4 bytes) instead of doubles (64 bits/8 bytes) orlong doubles (80 bits/10 bytes).Well, I could just implement the point as a template class, but there aretoo many other interactions with other classes to complicate the code that much.Using it as a templatein a way defeats the concept of using the point as a generic primitive, especially since there is a spaceof only three types I would use.Doubles and long doubles are slower than floats, about twice as slow for things like divides (19 versus39 cycles), and on top of that they require twice the space.The added precision really isn't importantunless you really need a wide range of precision.Within a few years worlds will be big enough andmodel resolution will be fine enough that you may need to employ larger floating-point resolutions to getthe job done.Until then I'd suggest sticking with traditional floats.Basic point3 Functions172 The point3 structure is pretty lame right now.All it can do is construct structures! To spice it up, I'll addsome member functions to help perform some basic operations on 3D points, and explain what they areused for.AssignSetting a point to a certain value is a common task.It could be done explicitly in three lines, setting thex, y, and z values separately.However, for simplicity's sake, it's easier to set them all at once, with asingle function call.This is also better than just creating a new variable on the stack with a point3constructor; it's more efficient to reuse stack variables whenever possible.The code to do this appearsin Listing 5.2.Listing 5.2: point3::Assign// Reassign a point without making a temporary structureinline void point3::Assign( float X, float Y, float Z ){x=X;y=Y;z=Z;}Mag and MagSquaredThe function Mag uses the 3D version of the Pythagorean theorem mentioned previously to calculatethe length of the point structure (the distance from the point to the origin).The code appears in Listing5.3.Listing 5.3: point3::Maginline float point3::Mag() const{return (float)sqrt( x*x + y*y + z*z );}173 Sometimes you want the squared distance (for example, when calculating the attenuation factor for apoint-source light).Rather than computing the expensive square root and squaring it, you can avoid thecost and simply make an extra function to do it for you, which appears in Listing 5.4.Listing 5.4: point3::MagSquaredinline float point3::MagSquared() const{return ( x*x + y*y + z*z );}NormalizeNormalize takes a point structure and makes it a unit-length vector pointing in the same direction.Thecode appears in Listing 5.5.Listing 5.5: point3::Normalizeinline void point3::Normalize(){float InvertedMagnitude=1/Mag();x*=InvertedMagnitude;y*=InvertedMagnitude;z*=InvertedMagnitude;}DistDist is a static function that calculates the distance between two point structures.Conceptually, it findsthe vector that connects them (which is the vector b a) and computes its length.The code appears inListing 5.6.Listing 5.6: point3::Distinline static float point3::Dist( const point3 &a, const point3 &b )174 {point3 distVec( b.x - a.x, b.y - a.y, b.z - a.z );return distVec.Mag();}point3 OperatorsNow that there is a basic primitive I can use, like other primitives (e.g [ Pobierz całość w formacie PDF ]
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • agnieszka90.opx.pl