আমার দুটি ভেক্টর রয়েছে আপনার এবং ভি। আপনি কি ইউটার থেকে ভি পর্যন্ত ঘূর্ণনকে উপস্থাপন করে কোয়ার্টেরন খুঁজে পাওয়ার কোনও উপায় খুঁজে পাবেন?
আমার দুটি ভেক্টর রয়েছে আপনার এবং ভি। আপনি কি ইউটার থেকে ভি পর্যন্ত ঘূর্ণনকে উপস্থাপন করে কোয়ার্টেরন খুঁজে পাওয়ার কোনও উপায় খুঁজে পাবেন?
উত্তর:
Quaternion q;
vector a = crossproduct(v1, v2);
q.xyz = a;
q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2);
কিউ স্বাভাবিক করতে ভুলবেন না
রিচার্ড একটি অনন্য ঘূর্ণন না হওয়া সম্পর্কে সঠিক, কিন্তু উপরেরটি "সংক্ষিপ্ত আর্ক" দিতে হবে যা সম্ভবত আপনার প্রয়োজন।
sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
সরল v1.Length * v2.Length
। বুদ্ধিমান ফলাফল তৈরি করতে আমি এর কোনও প্রকার পেতে পারি না।
আমি সমাধানটি নিয়ে এসেছি যেটি আমি বিশ্বাস করি যে ইম্ব্রনডির উপস্থাপনের চেষ্টা করছিলেন (তবে একটি ছোট্ট ভুল হলেও, সম্ভবত এটি কারণেই সিনসিস্টিপমুনক এটি যাচাই করতে সমস্যা হয়েছিল)।
প্রদত্ত যে আমরা এমন একটি অক্ষের চারপাশে ঘূর্ণন প্রতিনিধিত্ব করে একটি চৌবাচ্চা তৈরি করতে পারি:
q.w == cos(angle / 2)
q.x == sin(angle / 2) * axis.x
q.y == sin(angle / 2) * axis.y
q.z == sin(angle / 2) * axis.z
এবং এটি দুটি সাধারণীকৃত ভেক্টরগুলির ডট এবং ক্রস পণ্য হ'ল:
dot == cos(theta)
cross.x == sin(theta) * perpendicular.x
cross.y == sin(theta) * perpendicular.y
cross.z == sin(theta) * perpendicular.z
লম্বা ভেক্টরের চারপাশে থেটা (ভেক্টরগুলির মধ্যে কোণ) দিয়ে ঘোরানোর মাধ্যমে আপনি ইউ থেকে ভি পর্যন্ত ঘূর্ণন হিসাবে দেখা যায় এটি দেখে মনে হচ্ছে যে আমরা সরাসরি বিন্দু এবং ক্রস পণ্যগুলির ফলাফল থেকে এমন ঘূর্ণন প্রতিনিধিত্ব করে একটি চৌম্বক তৈরি করতে পারি ; যাইহোক, এটি যেমন দাঁড়িয়েছে, থিটা = কোণ / 2 , যার অর্থ এটি করা দ্বিগুণ পছন্দসই ঘূর্ণন ঘটায়।
ওয়ান সমাধান মধ্যে একটি ভেক্টর মধ্যপথে গনা হয় তোমার দর্শন লগ করা এবং V এবং ডট এবং ক্রস পণ্য ব্যবহার U এবং মধ্যপথে একটি চার বস্তুর সমষ্টি একটি ঘূর্ণন প্রতিনিধিত্বমূলক গঠন করা ভেক্টর দুইবার মধ্যে কোণ তোমার দর্শন লগ করা এবং মধ্যপথে ভেক্টর, যা আমাদের সমস্ত পথে ভিতে নিয়ে যায় !
একটি বিশেষ কেস রয়েছে, যেখানে u == -v এবং একটি অনন্য অর্ধ-পথের ভেক্টর গণনা করা অসম্ভব হয়ে পড়ে। এটি হয়ে থাকে, অসীম অনেক "সবচেয়ে কম চাপ" ঘুর্ণন যা আমাদের কাছ থেকে নিতে পারেন দেওয়া তোমার দর্শন লগ করা থেকে বনাম , এবং আমরা কেবল কোনো ভেক্টর লম্ব প্রায় 180 ডিগ্রী দ্বারা আবর্তিত হবে তোমার দর্শন লগ করা (অথবা বনাম ) হিসেবে আমাদের বিশেষ-কেস সমাধান। এই স্বাভাবিকভাবে ক্রস পণ্য গ্রহণ করে সম্পন্ন করা হয় তোমার দর্শন লগ করা অন্য কোন ভেক্টর দিয়ে না সমান্তরাল তোমার দর্শন লগ করা ।
সিউডো কোড অনুসরণ করে (স্পষ্টতই, বাস্তবে বিশেষ ক্ষেত্রে ভাসমান পয়েন্টের ভুলগুলির জন্য অ্যাকাউন্ট করতে হবে - সম্ভবত একটি নিখুঁত মানের চেয়ে কিছু প্রান্তিকের বিরুদ্ধে ডট পণ্যগুলি পরীক্ষা করে)।
এছাড়াও খেয়াল করুন যে যখন ইউ == ভি (পরিচয় কোয়ার্টেরিয়ন তৈরি হয় - নিজের জন্য দেখুন এবং দেখুন) তখন কোনও বিশেষ ক্ষেত্রে নেই ।
// N.B. the arguments are _not_ axis and angle, but rather the
// raw scalar-vector components.
Quaternion(float w, Vector3 xyz);
Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
// It is important that the inputs are of equal length when
// calculating the half-way vector.
u = normalized(u);
v = normalized(v);
// Unfortunately, we have to check for when u == -v, as u + v
// in this case will be (0, 0, 0), which cannot be normalized.
if (u == -v)
{
// 180 degree rotation around any orthogonal vector
return Quaternion(0, normalized(orthogonal(u)));
}
Vector3 half = normalized(u + v);
return Quaternion(dot(u, half), cross(u, half));
}
orthogonal
ফাংশন দেওয়া ভেক্টর কোনো ভেক্টর লম্ব ফেরৎ। এই বাস্তবায়ন সর্বাধিক orthogonal বেস ভেক্টর সহ ক্রস পণ্য ব্যবহার করে।
Vector3 orthogonal(Vector3 v)
{
float x = abs(v.x);
float y = abs(v.y);
float z = abs(v.z);
Vector3 other = x < y ? (x < z ? X_AXIS : Z_AXIS) : (y < z ? Y_AXIS : Z_AXIS);
return cross(v, other);
}
এটি আসলে গৃহীত উত্তরের মধ্যে উপস্থাপিত সমাধান, এবং এটি অর্ধপথের ভেক্টর সমাধানের তুলনায় সামান্য দ্রুত বলে মনে হচ্ছে (আমার পরিমাপের দ্বারা faster 20% দ্রুত, যদিও এটির জন্য আমার শব্দটি গ্রহণ করবেন না)। আমার মতো অন্যরা যদি ব্যাখ্যাটিতে আগ্রহী হয় তবে আমি এটিকে এখানে যুক্ত করছি।
মূলত, আধ-রাস্তা ভেক্টর ব্যবহার করে একটি চৌম্বক গণনা করার পরিবর্তে, আপনি কোয়ার্টেরিয়ন গণনা করতে পারেন যার ফলস্বরূপ দ্বি প্রয়োজনীয় প্রয়োজনীয় ঘূর্ণন ঘটে (অন্যান্য সমাধানে বিস্তারিত হিসাবে), এবং সেই এবং শূন্য ডিগ্রির মধ্যবর্তী কোয়ার্টেরিয়নটি অর্ধ-পথটি সন্ধান করতে পারেন।
আমি আগে যেমন ব্যাখ্যা করেছি, প্রয়োজনীয় ঘূর্ণন দ্বিগুণের জন্য চৌম্বকটি হ'ল:
q.w == dot(u, v)
q.xyz == cross(u, v)
এবং শূন্য ঘূর্ণন জন্য quaternion হয়:
q.w == 1
q.xyz == (0, 0, 0)
হাফ-ওয়ে কোয়ার্টেরিয়নের গণনা করা সহজভাবে ভেক্টরগুলির মতো কোয়ার্টেরিনগুলি সংশ্লেষ করা এবং ফলাফলকে স্বাভাবিক করার বিষয়। তবে, যেমন ভেক্টরগুলির ক্ষেত্রে এটিও রয়েছে, কোয়ার্ট্রিয়নের অবশ্যই একই তাত্পর্য থাকতে হবে, অন্যথায় ফলাফলটি বৃহত্তর মাত্রার সাথে কোয়ার্টেরিয়ানের দিকে স্কিউ হবে।
একটি চার বস্তুর সমষ্টি ডট এবং দুই ভেক্টর ক্রস পণ্য থেকে নির্মাণ সেইসব পণ্যগুলির হিসাবে একই মাত্রার হবে: length(u) * length(v)
। এই ফ্যাক্টর দ্বারা চারটি উপাদানকে ভাগ করার পরিবর্তে, আমরা পরিবর্তে সনাক্তকরণের চতুর্থাংশকে স্কেল করতে পারি। এবং আপনি যদি ভাবছিলেন যে গৃহীত উত্তরটি আপাতদৃষ্টিতে ব্যবহার করে বিষয়গুলিকে জটিল sqrt(length(u) ^ 2 * length(v) ^ 2)
করে তোলে কেননা এটি একটি ভেক্টরের স্কোয়ার দৈর্ঘ্য দৈর্ঘ্যের চেয়ে দ্রুত গণনা করার ফলে আমরা একটি sqrt
গণনা সংরক্ষণ করতে পারি । ফলাফল হলো:
q.w = dot(u, v) + sqrt(length_2(u) * length_2(v))
q.xyz = cross(u, v)
এবং তারপরে ফলাফলটি স্বাভাবিক করুন। সিউডো কোডটি নিম্নলিখিত:
Quaternion get_rotation_between(Vector3 u, Vector3 v)
{
float k_cos_theta = dot(u, v);
float k = sqrt(length_2(u) * length_2(v));
if (k_cos_theta / k == -1)
{
// 180 degree rotation around any orthogonal vector
return Quaternion(0, normalized(orthogonal(u)));
}
return normalized(Quaternion(k_cos_theta + k, cross(u, v)));
}
উল্লিখিত সমস্যাটি যথাযথভাবে সংজ্ঞায়িত করা হয়নি: প্রদত্ত জোড়া ভেক্টরগুলির জন্য কোনও অনন্য ঘূর্ণন নেই। কেসটি বিবেচনা করুন, উদাহরণস্বরূপ, যেখানে ইউ = <1, 0, 0> এবং ভি = <0, 1, 0> । U থেকে v পর্যন্ত একটি ঘূর্ণন হ'ল z- অক্ষের চারপাশে পাই / 2 ঘূর্ণন হবে। U থেকে v এ অন্য ঘূর্ণন হ'ল ভেক্টর <1, 1, 0> এর চারপাশে পাই ঘোরানো হবে ।
শুদ্ধ চৌকোণ ব্যবহার করে ভেক্টরকে উপস্থাপন করবেন না কেন? আপনি যদি প্রথমে এগুলি স্বাভাবিক করেন তবে এটি আরও ভাল।
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q পচ = q 2
কিউ 1 -1
কিউ রোট = q 1 -1 কি 2 এর সাথে পূর্বে গুণ করুন
যেখানে q 1 -1 = q 1 conj / q আদর্শ
এটি "বাম বিভাগ" হিসাবে ভাবা যেতে পারে। ডান বিভাগ, যা আপনি চান তা নয়:
q পচা, ডান = q 2 -1 কি 1
আমি কোয়ার্টেরিয়নে খুব একটা ভাল না। তবে আমি এটি নিয়ে কয়েক ঘন্টা লড়াই করেছি, এবং পোলারিস 878 সমাধানের কাজটি করতে পারিনি। আমি ভি 1 এবং ভি 2 প্রাক-স্বাভাবিক করার চেষ্টা করেছি। সাধারণীকরণ q। Q.xyz স্বাভাবিক করা হচ্ছে। তবুও আমি তা পাই না। ফলাফল এখনও আমাকে সঠিক ফলাফল দেয় নি।
শেষ পর্যন্ত যদিও আমি একটি সমাধান পেয়েছি যা করেছিল। যদি এটি অন্য কাউকে সহায়তা করে তবে আমার ওয়ার্কিং (অজগর) কোডটি এখানে:
def diffVectors(v1, v2):
""" Get rotation Quaternion between 2 vectors """
v1.normalize(), v2.normalize()
v = v1+v2
v.normalize()
angle = v.dot(v2)
axis = v.cross(v2)
return Quaternion( angle, *axis )
একটি বিশেষ কেস তৈরি করা আবশ্যক যদি ভি 1 এবং ভি 2 প্যারালেল হয় যেমন ভি 1 == ভি 2 বা ভি 1 == -v2 (কিছুটা সহনশীলতার সাথে), যেখানে আমি বিশ্বাস করি সমাধানগুলি কোয়ার্টারিয়ন (1, 0,0,0) হওয়া উচিত (কোনও আবর্তন নেই) বা কোয়ার্টারিয়ন (0, * ভি 1) (180 ডিগ্রি ঘূর্ণন)
quat = diffVectors(v1, v2); assert quat * v1 == v2
।
angle
বিন্দু পণ্য থেকে এর মূল্য পাওয়ার পরে এটি মোটেও কার্যকর হবে বলে সম্ভাবনা নেই ।
উত্তরের কয়েকটি উত্তর ক্রস প্রোডাক্ট 0 হওয়ার সম্ভাবনা বিবেচনা করে বলে মনে হচ্ছে না নীচে স্নিপেটে কোণ-অক্ষের উপস্থাপনা ব্যবহার করা হয়েছে:
//v1, v2 are assumed to be normalized
Vector3 axis = v1.cross(v2);
if (axis == Vector3::Zero())
axis = up();
else
axis = axis.normalized();
return toQuaternion(axis, ang);
toQuaternion
নিম্নরূপ বাস্তবায়ন করা যেতে পারে:
static Quaternion toQuaternion(const Vector3& axis, float angle)
{
auto s = std::sin(angle / 2);
auto u = axis.normalized();
return Quaternion(std::cos(angle / 2), u.x() * s, u.y() * s, u.z() * s);
}
আপনি যদি ইগেন লাইব্রেরি ব্যবহার করেন তবে আপনি কেবল এটি করতে পারেন:
Quaternion::FromTwoVectors(from, to)
toQuaternion(axis, ang)
-> আপনি কী তা নির্দিষ্ট করে দিতে ভুলে গেছেনang
angle
যা কোয়াটারিয়নের অক্ষ-কোণ উপস্থাপনার একটি অংশ, রেডিয়েন্সে পরিমাপ করা হয়।
অ্যালগরিদম দৃষ্টিকোণ থেকে, দ্রুততম সমাধানটি সিউডোকোডে দেখায়
Quaternion shortest_arc(const vector3& v1, const vector3& v2 )
{
// input vectors NOT unit
Quaternion q( cross(v1, v2), dot(v1, v2) );
// reducing to half angle
q.w += q.magnitude(); // 4 multiplication instead of 6 and more numerical stable
// handling close to 180 degree case
//... code skipped
return q.normalized(); // normalize if you need UNIT quaternion
}
নিশ্চিত হয়ে নিন যে আপনার ইউনিট চতুর্থাংশের প্রয়োজন (নিয়মিত, এটি অন্তরবৃত্তির জন্য প্রয়োজনীয়)।
দ্রষ্টব্য: ননুনিট কোয়ার্টেরিনগুলি ইউনিটের চেয়ে দ্রুত কিছু অপারেশন সহ ব্যবহার করা যেতে পারে।
crossproduct
এই ক্ষেত্রে বৈধ হবে না, সুতরাং আপনাকে প্রথমে যথাক্রমে পরীক্ষা করতে হবেdot(v1, v2) > 0.999999
এবংdot(v1, v2) < -0.999999
যথাক্রমে সমান্তরাল ভেক্টরগুলির জন্য একটি পরিচয় কোট প্রদান করতে হবে, বা বিপরীত ভেক্টরগুলির জন্য 180 ডিগ্রি ঘূর্ণন (কোনও অক্ষ সম্পর্কে) ফেরত দিতে হবে।