এক ভেক্টর থেকে অন্য ভেক্টরে ঘূর্ণন প্রতিনিধিত্ব করে কোয়ার্টারিয়ন সন্ধান করা


105

আমার দুটি ভেক্টর রয়েছে আপনার এবং ভি। আপনি কি ইউটার থেকে ভি পর্যন্ত ঘূর্ণনকে উপস্থাপন করে কোয়ার্টেরন খুঁজে পাওয়ার কোনও উপায় খুঁজে পাবেন?

উত্তর:


115
Quaternion q;
vector a = crossproduct(v1, v2);
q.xyz = a;
q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2);

কিউ স্বাভাবিক করতে ভুলবেন না

রিচার্ড একটি অনন্য ঘূর্ণন না হওয়া সম্পর্কে সঠিক, কিন্তু উপরেরটি "সংক্ষিপ্ত আর্ক" দিতে হবে যা সম্ভবত আপনার প্রয়োজন।


30
সচেতন থাকুন যে এটি সমান্তরাল ভেক্টরগুলির ক্ষেত্রে পরিচালনা করে না (উভয় একই দিকে বা বিপরীত দিক নির্দেশ করে)। crossproductএই ক্ষেত্রে বৈধ হবে না, সুতরাং আপনাকে প্রথমে যথাক্রমে পরীক্ষা করতে হবে dot(v1, v2) > 0.999999এবং dot(v1, v2) < -0.999999যথাক্রমে সমান্তরাল ভেক্টরগুলির জন্য একটি পরিচয় কোট প্রদান করতে হবে, বা বিপরীত ভেক্টরগুলির জন্য 180 ডিগ্রি ঘূর্ণন (কোনও অক্ষ সম্পর্কে) ফেরত দিতে হবে।
sinisterchipmunk

11
এই একটি ভাল বাস্তবায়ন খুঁজে পাওয়া যেতে পারে ogre3d সোর্স কোড
জোয়াও Portela

4
@ সিনিস্টারচিপমুনক আসলে, যদি ভি 1 = ভি 2 হয় তবে ক্রস প্রোডাক্ট (0,0,0) হবে এবং ডাব্লু ইতিবাচক হবে, যা পরিচয়কে স্বাভাবিক করে তোলে। গেমদেব.নাট / টপিক / to অনুসারে এটি v1 = -v2 এবং তাদের কাছাকাছি অঞ্চলেও ঠিক কাজ করা উচিত।
jpa

3
কেউ কীভাবে এই কৌশলটি কাজ করতে পেল? এক জন্য, sqrt((v1.Length ^ 2) * (v2.Length ^ 2))সরল v1.Length * v2.Length। বুদ্ধিমান ফলাফল তৈরি করতে আমি এর কোনও প্রকার পেতে পারি না।
জোসেফ থমসন

2
হ্যাঁ, এটি কাজ করে। উত্স কোড দেখুন । L61 হ্যান্ডেলগুলি দেখায় যদি ভেক্টরগুলি বিপরীত দিকের মুখোমুখি হয় (পিআই ফেরান, অন্যথায় এটি @ জেপিএর মন্তব্য অনুসারে পরিচয় ফেরত চাই)। L67 সমান্তরাল ভেক্টরগুলি পরিচালনা করে: গাণিতিকভাবে অপ্রয়োজনীয়, তবে দ্রুত। L72 হ'ল পোলারিস 878 এর উত্তর, ধরে নেওয়া উভয় ভেক্টরই একক দৈর্ঘ্যের (স্কয়ারটি এড়ানো)। আরও দেখুন ইউনিট পরীক্ষা
sinisterchipmunk

63

হাফ-ওয়ে ভেক্টর সলিউশন

আমি সমাধানটি নিয়ে এসেছি যেটি আমি বিশ্বাস করি যে ইম্ব্রনডির উপস্থাপনের চেষ্টা করছিলেন (তবে একটি ছোট্ট ভুল হলেও, সম্ভবত এটি কারণেই সিনসিস্টিপমুনক এটি যাচাই করতে সমস্যা হয়েছিল)।

প্রদত্ত যে আমরা এমন একটি অক্ষের চারপাশে ঘূর্ণন প্রতিনিধিত্ব করে একটি চৌবাচ্চা তৈরি করতে পারি:

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)));
}

12
+1: দুর্দান্ত! এটি একটি কবজ হিসাবে কাজ করে। গ্রহণযোগ্য উত্তর হওয়া উচিত।
রেজিন

1
কোয়ার্টারিয়ন সিনট্যাক্সিস কিছু উদাহরণ (কোয়ার্টেরিয়ন (xyz, ডাব্লু) এবং কোয়ার্টেরিয়ন (ডাব্লু, এক্সআইজেড)) এ স্যুইচ করা হয়। এও মনে হয় যে শেষ কোডটিতে ব্লক রেডিয়েনস এবং ডিগ্রিগুলি কোণ প্রকাশ করার জন্য মিশ্রিত হয় (180 বনাম k_cos_theta + কে)।
গিলারমো ব্লাস্কো

1
কোয়ার্টেরিয়ন (ফ্লোট, ভেক্টর 3) স্কেলার-ভেক্টর থেকে নির্মাণ করা হচ্ছে, যেখানে কোয়ার্টেরিয়ন (ভেক্টর 3, ফ্লোট) অক্ষ-কোণ থেকে তৈরি। সম্ভবত সম্ভাব্য বিভ্রান্তিকর, তবে আমি মনে করি এটি সঠিক। আপনি এখনও ভুল মনে হলে আমাকে সংশোধন করুন!
জোসেফ থমসন

এটা কাজ করেছে! ধন্যবাদ! তবে উপরের অপারেশনটি সম্পাদন করার জন্য আমি অন্য একটি অনুরূপ এবং সুস্পষ্ট ব্যাখ্যাযুক্ত লিঙ্কটি পেয়েছি । ভেবেছিলাম আমার রেকর্ডটির জন্য ভাগ করা উচিত;)
পাপী

1
@ জোসেফ থমসন হাফ-ওয়ে চতুর্ভূত সমাধানটি এখান থেকে এসেছে বলে মনে হচ্ছে ।
কিংবদন্তি 2 কে

6

উল্লিখিত সমস্যাটি যথাযথভাবে সংজ্ঞায়িত করা হয়নি: প্রদত্ত জোড়া ভেক্টরগুলির জন্য কোনও অনন্য ঘূর্ণন নেই। কেসটি বিবেচনা করুন, উদাহরণস্বরূপ, যেখানে ইউ = <1, 0, 0> এবং ভি = <0, 1, 0> । U থেকে v পর্যন্ত একটি ঘূর্ণন হ'ল z- অক্ষের চারপাশে পাই / 2 ঘূর্ণন হবে। U থেকে v এ অন্য ঘূর্ণন হ'ল ভেক্টর <1, 1, 0> এর চারপাশে পাই ঘোরানো হবে ।


1
আসলে সম্ভাব্য উত্তরগুলির অসীম সংখ্যা নেই? কারণ আপনি "থেকে" ভেক্টরকে "" থেকে "ভেক্টরের সাথে সারিবদ্ধ করার পরেও আপনি তার অক্ষের চারপাশে ফলাফলকে নির্দ্বিধায় স্পিন করতে পারেন? আপনি কি জানেন যে অতিরিক্ত কোন তথ্য সাধারণত এই পছন্দটি সীমাবদ্ধ করতে এবং সমস্যাটিকে ভাল সংজ্ঞায়িত করতে ব্যবহার করা যেতে পারে?
ডগ ম্যাকক্লেইন

5

শুদ্ধ চৌকোণ ব্যবহার করে ভেক্টরকে উপস্থাপন করবেন না কেন? আপনি যদি প্রথমে এগুলি স্বাভাবিক করেন তবে এটি আরও ভাল।
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


2
আমি হারিয়ে গেছি, কিউ 1 থেকে কি 2 এর ঘূর্ণন কি কিউ 2 = কি_রোট কিউ_1 কি_রোট 1 -1 হিসাবে গণনা করা হচ্ছে?
ইয়োটা

4

আমি কোয়ার্টেরিয়নে খুব একটা ভাল না। তবে আমি এটি নিয়ে কয়েক ঘন্টা লড়াই করেছি, এবং পোলারিস 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
sinisterchipmunk

এটি angleবিন্দু পণ্য থেকে এর মূল্য পাওয়ার পরে এটি মোটেও কার্যকর হবে বলে সম্ভাবনা নেই ।
সাম হোসেভার

কোয়ার্টারিয়ন () ফাংশনটি কোথায়?
জুন ওয়াং

3

উত্তরের কয়েকটি উত্তর ক্রস প্রোডাক্ট 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
ম্যাকসেম গ্যানেনকো

2 য় প্যারামিটার angleযা কোয়াটারিয়নের অক্ষ-কোণ উপস্থাপনার একটি অংশ, রেডিয়েন্সে পরিমাপ করা হয়।
শীতল শাহ

আপনাকে একটি ভেক্টর থেকে অন্য ভেক্টরে ঘুরতে কোয়ার্টারিয়ন পেতে বলা হয়েছিল। আপনার কোণ নেই, আপনাকে প্রথমে এটি গণনা করতে হবে। আপনার উত্তরটিতে কোণের গণনা থাকা উচিত। চিয়ার্স!
ম্যাকসিম গ্যানেনকো

এটি সি ++? ইউএক্স () কী?
জুন ওয়াং

হ্যাঁ, এটি সি ++। আপনি ইগেন লাইব্রেরি থেকে ভেক্টর ধরণের (যদি আপনি এটি ব্যবহার করে থাকেন)।
শীতল শাহ

2

অ্যালগরিদম দৃষ্টিকোণ থেকে, দ্রুততম সমাধানটি সিউডোকোডে দেখায়

 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
 }

নিশ্চিত হয়ে নিন যে আপনার ইউনিট চতুর্থাংশের প্রয়োজন (নিয়মিত, এটি অন্তরবৃত্তির জন্য প্রয়োজনীয়)।

দ্রষ্টব্য: ননুনিট কোয়ার্টেরিনগুলি ইউনিটের চেয়ে দ্রুত কিছু অপারেশন সহ ব্যবহার করা যেতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.