সম্পাদনা অস্বীকৃতি : এই উত্তরের সুবিধার জন্য ডাব্লু == 0 সহ ভেক্টরকে ভেক্টর এবং ডাব্লু == 1 সহ পয়েন্ট বলা হয়। যদিও FxIII উল্লেখ করেছে, এটি কোনও গাণিতিকভাবে সঠিক পরিভাষা নয়। যাইহোক, যেহেতু উত্তরের বিন্দুটি পরিভাষা নয়, তবে উভয় প্রকারের ভেক্টরকে আলাদা করার প্রয়োজন, আমি এটির সাথে আঁকড়ে থাকব। ব্যবহারিক কারণে এই সম্মেলনটি গেম-বিকাশে ব্যাপকভাবে ব্যবহৃত হয়।
'ডাব্লু' উপাদান ছাড়া ভেক্টর এবং পয়েন্টগুলির মধ্যে পার্থক্য করা সম্ভব নয়। এটি পয়েন্টগুলির জন্য 1 এবং ভেক্টরগুলির জন্য 0।
যদি ভেক্টরগুলিকে 4x4 অ্যাফাইন ট্রান্সফর্মেশন-ম্যাট্রিক্স দিয়ে গুণ করা হয় যার শেষ সারি / কলামে একটি অনুবাদ রয়েছে, তবে ভেক্টরটিও অনুবাদ করা হবে, যা ভুল, কেবলমাত্র পয়েন্টগুলিই অনুবাদ করা উচিত। কোনও ভেক্টরের 'ডাব্লু' উপাদানটির শূন্য এটির যত্ন নেয়।
ম্যাট্রিক্স-ভেক্টর গুণনের এই অংশটি হাইলাইট করা এটিকে আরও স্পষ্ট করে তোলে:
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 তম উপাদান শূন্য থাকলে আপনি এখনও একই ম্যাট্রিক্স ব্যবহার করতে পারেন যা পয়েন্টগুলিকে রোটেশনের অক্ষকে রূপান্তর করতে পরিবর্তিত করে এবং ফলাফলটি বৈধ হবে এবং ম্যাট্রিক্সে কোনও স্কেল না থাকায় এর দৈর্ঘ্য সংরক্ষণ করা হয়। এটি ভেক্টরদের জন্য আপনি চান আচরণ। ৪ র্থ উপাদান ছাড়া আপনাকে ২ টি ম্যাট্রিক (অথবা একটি অন্তর্ভুক্ত চতুর্থ প্যারামিটার সহ 2 টি আলাদা গুণ গুণ) তৈরি করতে হবে এবং পয়েন্ট এবং ভেক্টরগুলির জন্য 2 টি পৃথক ফাংশন কল করতে হবে।
আধুনিক সিপিইউগুলির ভেক্টর রেজিস্টারগুলি ব্যবহারের জন্য (এসএসই, অ্যালটিভিক, এসপিইউ) আপনাকে যেভাবেই 4x 32 বিট ফ্লোটগুলি পাস করতে হবে (এটি একটি 128 বিট রেজিস্টার), এবং আপনাকে সাধারণত অ্যালাইনমেন্টের যত্ন নিতে হবে, সাধারণত 16 বাইট। সুতরাং আপনার কাছে যেভাবেই চতুর্থ উপাদানটির জন্য জায়গাটি নিরাপদ করার সুযোগ নেই।
সম্পাদনা:
প্রশ্নের উত্তরটি মূলত:
- হয় ডাব্লু-উপাদানটি সংরক্ষণ করুন: পজিশনের জন্য 1 এবং ভেক্টরগুলির জন্য 0
- অথবা বিভিন্ন ম্যাট্রিক্স-ভেক্টর গুণিত ফাংশন কল করুন এবং যেকোন একটি ফাংশন বেছে নিয়ে স্পষ্টভাবে 'ডাব্লু' উপাদানটি পাস করুন
তাদের অবশ্যই একটি বাছাই করতে হবে, কেবলমাত্র {x, y, z store সংরক্ষণ করা সম্ভব নয় এবং এখনও কেবলমাত্র একটি ম্যাট্রিক্স-ভেক্টর গুণিত ফাংশন ব্যবহার করতে পারে। উদাহরণস্বরূপ এক্সএনএ তার ভেক্টর 3 শ্রেণিতে 2 টি রূপান্তর ফাংশন রেখে ডাকা Transform
এবং পরে পরবর্তী পদ্ধতির ব্যবহার করেTransformNormal
এখানে একটি কোড উদাহরণ রয়েছে যা দুটি পদ্ধতির উভয়ই দেখায় এবং 2 টি সম্ভাব্য উপায়ে 1 তে উভয় ধরণের ভেক্টরকে পৃথক করার প্রয়োজনীয়তা প্রদর্শন করে। আমরা ম্যাট্রিক্স দিয়ে রূপান্তর করে বিশ্বের একটি অবস্থান এবং চেহারা-নির্দেশক একটি গেম-সত্তা স্থানান্তর করব। যদি আমরা 'ডাব্লু' উপাদানটি ব্যবহার না করি তবে আমরা একই ম্যাট্রিক্স-ভেক্টর গুণকে আর ব্যবহার করতে পারি না, যেমন এই উদাহরণটি দেখায়। আমরা যদি যাইহোক এটি করি তবে রূপান্তরিত 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
এখন এক্স + 5 এর অনুবাদ এবং Y- অক্ষের চারপাশে 90 ডিগ্রির একটি ঘূর্ণন সহ একটি রূপান্তর এই সত্তায় প্রয়োগ করা হবে। ট্রান্সফর্মেশনের পরে সঠিক উত্তরটি হ'ল:
position : 5.000000 0.000000 0.000000 1.000000
look_dir : 0.000000 0.000000 1.000000 0.000000
আমরা কেবলমাত্র সঠিক উত্তরটি পেয়ে যাব যদি আমরা উপরের উপস্থাপিত উপায়ে যে কোনও একটিতে ডাব্লু == 0 এবং পজিশনগুলি ডাব্লু == 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;
বিশদগুলির জন্য আমার উত্তরটি দেখুন