DÜZENLEME Feragatname : Bu cevapta kolaylık olması için w == 0 olan vektörlere vektör denir ve w == 1 ile vektörlere nokta denir. FxIII'nin işaret ettiği gibi, bu matematiksel olarak doğru bir terminoloji değildir. Bununla birlikte, cevabın noktası terminoloji değil, her iki vektör türünü de ayırt etme ihtiyacı olduğundan, buna bağlı kalacağım. Pratik bir nedenle, bu sözleşme oyun geliştirmede yaygın olarak kullanılmaktadır.
'W' bileşeni olmadan vektörler ve noktalar arasında ayrım yapmak mümkün değildir. Puanlar için 1 ve vektörler için 0'dır.
Vektörler, son satırında / sütununda çevirisi olan bir 4x4 afin dönüşüm-matrisi ile çarpılırsa, vektör de çevrilir, bu yanlıştır, sadece noktalar çevrilmelidir. Bir vektörün 'w' bileşenindeki sıfır, bununla ilgilenir.
Matris-vektör çarpımının bu bölümünü vurgulamak daha açık hale getirir:
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)
Yani bir vektörü, örneğin bir dönme eksenini çevirmek yanlış olur, sonuç sadece yanlıştır, 4. bileşen sıfırına sahip olmakla birlikte, dönüş eksenini dönüştürmek için noktaları dönüştüren aynı matrisi kullanabilirsiniz ve sonuç geçerli olacaktır. ve uzunluğu matriste ölçek olmadığı sürece korunur. Vektörler için istediğiniz davranış budur. 4. bileşen olmadan 2 matris (veya örtük bir 4. parametre ile 2 farklı çarpma işlevi) oluşturmanız ve noktalar ve vektörler için 2 farklı işlev çağrısı yapmanız gerekir.
Modern CPU'ların (SSE, Altivec, SPU) vektör kayıtlarını kullanmak için yine de 4x 32 bit şamandıra (128 bitlik bir kayıt) geçmeniz gerekir, ayrıca hizalamaya dikkat etmeniz gerekir, genellikle 16 bayt. Böylece 4. bileşen için alan güvenliğini sağlama şansınız yok.
DÜZENLEME:
Sorunun cevabı temelde
- W bileşenini depolayın: konumlar için 1 ve vektörler için 0
- Veya farklı matris-vektör çarpma işlevlerini çağırın ve iki işlevden birini seçerek 'w' bileşenini dolaylı olarak geçirin
Bunlardan birini seçmek gerekir, sadece {x, y, z} depolamak ve hala sadece bir matris-vektör çarpma fonksiyonu kullanmak mümkün değildir. Örneğin XNA, Vector3 sınıfında Transform
veTransformNormal
Aşağıda, her iki yaklaşımı da gösteren ve her iki vektör türünü de 2 olası yoldan 1'inde ayırt etme ihtiyacını gösteren bir kod örneği verilmiştir. Bir oyun varlığını bir pozisyon ve bakış yönüne sahip bir matrisle dönüştürerek hareket ettireceğiz. 'W' bileşenini kullanmazsak, bu örnekte gösterildiği gibi artık aynı matris-vektör çarpımını kullanamayız. Yine de yaparsak, dönüştürülmüş look_dir
vektör için yanlış bir cevap alırız :
#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;
}
İlk Varlık durumu:
position : 0.000000 0.000000 0.000000 1.000000
look_dir : 1.000000 0.000000 0.000000 0.000000
Şimdi bu varlığa x + 5 çevrimli bir dönüşüm ve y ekseni etrafında 90 derecelik bir dönüş uygulanacaktır. Dönüşümden sonra doğru cevap:
position : 5.000000 0.000000 0.000000 1.000000
look_dir : 0.000000 0.000000 1.000000 0.000000
Doğru yanıtı ancak vektörleri w == 0 ve konumlarını w == 1 ile yukarıda belirtilen yollardan birinde ayırırsak alırız.
r.x = ... + a._14*v.w;
r.y = ... + a._24*v.w;
r.z = ... + a._34*v.w;
r.w = ... + a._44*v.w;
ayrıntılar için cevabım bak