EDIT अस्वीकरण : इस उत्तर में सुविधा के लिए w == 0 वाले वैक्टरों को वैक्टर कहा जाता है और w == 1 के साथ बिंदुओं को कहा जाता है। यद्यपि FxIII ने बताया, यह गणितीय रूप से सही शब्दावली नहीं है। हालांकि, चूंकि उत्तर का बिंदु शब्दावली नहीं है, लेकिन दोनों प्रकार के वैक्टरों को अलग करने की आवश्यकता है, मैं इसे चिपकाऊंगा। व्यावहारिक कारण से इस सम्मेलन का व्यापक रूप से खेल-विकास में उपयोग किया जाता है।
'W' घटक के बिना वैक्टर और बिंदुओं के बीच अंतर करना संभव नहीं है। यह अंक के लिए 1 और वैक्टर के लिए 0 है।
यदि वैक्टर को 4x4 affine परिवर्तन-मैट्रिक्स से गुणा किया जाता है जिसमें इसकी अंतिम पंक्ति / स्तंभ में अनुवाद है, तो वेक्टर का भी अनुवाद किया जाएगा, जो कि गलत है, केवल बिंदुओं का अनुवाद किया जाना चाहिए। एक वेक्टर के 'w' घटक में शून्य इस बात का ध्यान रखता है।
मैट्रिक्स-वेक्टर गुणा के इस हिस्से को हाइलाइट करना इसे और अधिक स्पष्ट करता है:
r.x = ... + a._14 * v.w;
r.y = ... + a._24 * v.w;
r.z = ... + a._34 * v.w;
r.w = ... + a._44 * v.w;
a._14, a._24 and a._34 is the translational part of the affine matrix.
Without a 'w' component one has to set it implicitly to 0 (vector) or to 1 (point)
यानी सदिश का अनुवाद करना गलत होगा, उदाहरण के लिए एक रोटेशन अक्ष, परिणाम बस गलत है, यह 4 वें घटक शून्य होने से आप अभी भी उसी मैट्रिक्स का उपयोग कर सकते हैं जो रोटेशन अक्ष को बदलने के लिए बिंदुओं को बदल देता है और परिणाम मान्य होगा और इसकी लंबाई को तब तक संरक्षित किया जाता है जब तक कि मैट्रिक्स में कोई पैमाना न हो। यह वह व्यवहार है जो आप वैक्टर के लिए चाहते हैं। 4 वें घटक के बिना आपको एक अंतर्निहित 4 पैरामीटर के साथ 2 मैट्रिसेस (या 2 अलग-अलग गुणा फ़ंक्शंस बनाने होंगे और अंक और वैक्टर के लिए 2 अलग-अलग फ़ंक्शन कॉल करने होंगे।
आधुनिक सीपीयू (SSE, Altivec, SPUs) के वेक्टर रजिस्टरों का उपयोग करने के लिए आपको वैसे भी 4x 32 बिट फ़्लोट पास करना होगा (इसका 128 बिट रजिस्टर), साथ ही आपको संरेखण का ध्यान रखना होगा, आमतौर पर 16 बाइट्स। तो आपके पास वैसे भी चौथे घटक के लिए स्थान सुरक्षित करने का मौका नहीं है।
संपादित करें:
प्रश्न का उत्तर मूल रूप से है
- या तो डब्ल्यू-घटक को स्टोर करें: पदों के लिए 1 और वैक्टर के लिए 0
- या विभिन्न मैट्रिक्स-वेक्टर गुणन कार्यों को कॉल करें और दोनों कार्यों में से किसी एक को चुनकर 'w' घटक को स्पष्ट रूप से पास करें
उनमें से किसी एक को चुनना होगा, यह केवल {x, y, z} को स्टोर करना संभव नहीं है और अभी भी केवल एक मैट्रिक्स-वेक्टर गुणन फ़ंक्शन का उपयोग करें। उदाहरण के लिए XNA अपने वेक्टर 3 वर्ग में 2 ट्रांसफ़ॉर्म फ़ंक्शंस के द्वारा बाद के दृष्टिकोण का उपयोग करता है , जिसे कहा जाता है Transform
औरTransformNormal
यहां एक कोड उदाहरण है जो दोनों दृष्टिकोणों को दिखाता है और 2 संभावित तरीकों में से 1 में दोनों प्रकार के वैक्टर को अलग करने की आवश्यकता को दर्शाता है। हम एक खेल-इकाई को एक मैट्रिक्स के साथ बदलकर दुनिया में एक स्थिति और एक नज़र-दिशा में ले जाएंगे। यदि हम 'w' घटक का उपयोग नहीं करते हैं, तो हम एक ही मैट्रिक्स-वेक्टर गुणा का उपयोग नहीं कर सकते हैं, क्योंकि यह उदाहरण प्रदर्शित करता है। यदि हम इसे वैसे भी करते हैं, तो हमें रूपांतरित look_dir
वेक्टर के लिए एक गलत उत्तर मिलेगा :
#include <cstdio>
#include <cmath>
struct vector3
{
vector3() {}
vector3(float _x, float _y, float _z) { x = _x; y = _y; z = _z; }
float x, y, z;
};
struct vector4
{
vector4() {}
vector4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
float x, y, z, w;
};
struct matrix
{
// convenience column accessors
vector4& operator[](int col) { return cols[col]; }
const vector4& operator[](int col) const { return cols[col]; }
vector4 cols[4];
};
// since we transform a vector that stores the 'w' component,
// we just need this one matrix-vector multiplication
vector4 operator*( const matrix &m, const vector4 &v )
{
vector4 ret;
ret.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x;
ret.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y;
ret.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + v.w * m[3].z;
ret.w = v.x * m[0].w + v.y * m[1].w + v.z * m[2].w + v.w * m[3].w;
return ret;
}
// if we don't store 'w' in the vector we need 2 different transform functions
// this to transform points (w==1), i.e. positions
vector3 TransformV3( const matrix &m, const vector3 &v )
{
vector3 ret;
ret.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + 1.0f * m[3].x;
ret.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + 1.0f * m[3].y;
ret.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + 1.0f * m[3].z;
return ret;
}
// and this one is to transform vectors (w==0), like a direction-vector
vector3 TransformNormalV3( const matrix &m, const vector3 &v )
{
vector3 ret;
ret.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + 0.0f * m[3].x;
ret.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + 0.0f * m[3].y;
ret.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + 0.0f * m[3].z;
return ret;
}
// some helpers to output the results
void PrintV4(const char *msg, const vector4 &p ) { printf("%-15s: %10.6f %10.6f %10.6f %10.6f\n", msg, p.x, p.y, p.z, p.w ); }
void PrintV3(const char *msg, const vector3 &p ) { printf("%-15s: %10.6f %10.6f %10.6f\n", msg, p.x, p.y, p.z); }
#define STORE_W 1
int main()
{
// suppose we have a "position" of an entity and its
// look direction "look_dir" which is a unit vector
// we will move this entity in the world
// the entity will be moved in the world by a translation
// in x+5 and a rotation of 90 degrees around the y-axis
// let's create that matrix first
// the rotation angle, 90 degrees in radians
float a = 1.570796326794896619f;
matrix moveEntity;
moveEntity[0] = vector4( cos(a), 0.0f, sin(a), 0.0f);
moveEntity[1] = vector4( 0.0f, 1.0f, 0.0f, 0.0f);
moveEntity[2] = vector4(-sin(a), 0.0f, cos(a), 0.0f);
moveEntity[3] = vector4( 5.0f, 0.0f, 0.0f, 1.0f);
#if STORE_W
vector4 position(0.0f, 0.0f, 0.0f, 1.0f);
// entity is looking towards the positive x-axis
vector4 look_dir(1.0f, 0.0f, 0.0f, 0.0f);
// move the entity using the matrix
// we can use the same function for the matrix-vector multiplication to transform
// the position and the unit vector since we store 'w' in the vector
position = moveEntity * position;
look_dir = moveEntity * look_dir;
PrintV4("position", position);
PrintV4("look_dir", look_dir);
#else
vector3 position(0.0f, 0.0f, 0.0f);
// entity is looking towards the positive x-axis
vector3 look_dir(1.0f, 0.0f, 0.0f);
// move the entity using the matrix
// we have to call 2 different transform functions one to transform the position
// and the other one to transform the unit-vector since we don't
// store 'w' in the vector
position = TransformV3(moveEntity, position);
look_dir = TransformNormalV3(moveEntity, look_dir);
PrintV3("position", position);
PrintV3("look_dir", look_dir);
#endif
return 0;
}
प्रारंभिक इकाई स्थिति:
position : 0.000000 0.000000 0.000000 1.000000
look_dir : 1.000000 0.000000 0.000000 0.000000
अब x + 5 के अनुवाद के साथ एक परिवर्तन और y- अक्ष के चारों ओर 90 डिग्री का एक घुमाव इस इकाई पर लागू होगा। सुधार के बाद सही उत्तर है:
position : 5.000000 0.000000 0.000000 1.000000
look_dir : 0.000000 0.000000 1.000000 0.000000
हम केवल सही उत्तर प्राप्त करेंगे यदि हम ऊपर दिए गए तरीकों में से किसी एक में w == 0 के साथ वैक्टर और w == 1 के साथ विभेद करते हैं।
r.x = ... + a._14*v.w;
r.y = ... + a._24*v.w;
r.z = ... + a._34*v.w;
r.w = ... + a._44*v.w;
विवरण के लिए मेरा उत्तर देखें