আমি কীভাবে একটি মাউস ক্লিককে রশ্মিতে রূপান্তর করতে পারি?


18

আমার একটি দৃষ্টিকোণ প্রক্ষেপণ আছে। যখন ব্যবহারকারী স্ক্রিনে ক্লিক করেন, তখন আমি মাউস পয়েন্ট থেকে প্রজেক্টের কাছাকাছি এবং দূরবর্তী বিমানগুলির মধ্যে রশ্মিটি গণনা করতে চাই, তাই আমি আমার বিশ্বের সাথে কিছু রে ছেদ কোডটি করতে পারি।

আমি আমার নিজস্ব ম্যাট্রিক্স এবং ভেক্টর এবং রে ক্লাস ব্যবহার করছি এবং তারা সকলেই প্রত্যাশা অনুযায়ী কাজ করে।

যাইহোক, আমি যখন রশ্মিকে বিশ্ব স্থানাঙ্কে রূপান্তরিত করি তখন আমার সর্বদা 0,0,0 হিসাবে শেষ হয় এবং তাই আমার রশ্মি মাউস ক্লিক থেকে অবজেক্ট স্পেসের কেন্দ্রে যায় না, বরং এটির মাধ্যমে। (কাছাকাছি এবং দূরের এক্স এবং y স্থানাঙ্কগুলি অভিন্ন, তারা কেবল z স্থানাঙ্কে পৃথক যেখানে তারা একে অপরের নেতিবাচক)

GLint vp[4];
glGetIntegerv(GL_VIEWPORT,vp);
matrix_t mv, p;
glGetFloatv(GL_MODELVIEW_MATRIX,mv.f);
glGetFloatv(GL_PROJECTION_MATRIX,p.f);
const matrix_t inv = (mv*p).inverse();
const float
    unit_x = (2.0f*((float)(x-vp[0])/(vp[2]-vp[0])))-1.0f,
    unit_y = 1.0f-(2.0f*((float)(y-vp[1])/(vp[3]-vp[1])));
const vec_t near(vec_t(unit_x,unit_y,-1)*inv);
const vec_t far(vec_t(unit_x,unit_y,1)*inv);
ray = ray_t(near,far-near);

আমার কী ভুল হয়েছে? (আপনি কীভাবে মাউস-পয়েন্টটি আনপোজড করবেন?)


কৌতূহলের মাত্র বাইরে, এমন কোনও কারণ আছে যা আপনি অন্তর্নির্মিত GL_SELECTION মোডটি ব্যবহার করছেন না? (তথ্য এখানে)
রিকিট

@ রিকেট এটি অবহেলা করা হয় না? জানি না, তবে বেশ নিশ্চিত।
নোটাবিন

X এবং y পিক্সেল হয়? সমস্যাটি হবে ...
নোটবেইন

এবং আপনি ম্যাট্রিক্স 4 দ্বারা ভিস 3 গুন করছেন। এটি ভাল নয় ... আপনি ভিসিটিটি (1 ম, দ্বিতীয়, 3 র্থ, চতুর্থ) করার সময় কোন সংখ্যা 4 র্থ অবস্থানে চলে যাবে?
নোটবেইন

@ নোটবেইন বাহ, আমার ধারণা এটি ছিল, আমার কোনও ধারণা ছিল না। এই আলোচনাটি ভাল এবং একটি বিকল্প সরবরাহ করে যা আমাকে সন্ধান করতে হবে এবং এখন আমি সত্যিই এই প্রশ্নের উত্তরের উত্তর আশা করছি।
রিকিট

উত্তর:


14

আমাকে সম্প্রতি একটি ওয়েবজিএল অ্যাপ্লিকেশনের জন্য এটি সমাধান করতে হয়েছিল। আমি সম্পূর্ণ উত্স কোডটি সংযুক্ত করেছি, তবে এটি আপনার পক্ষে ব্যাটের ডানদিকে কাজ করে না তবে এখানে কিছু ডিবাগিং টিপস রয়েছে:

  1. আপনার গেমটিতে আপনার অপ্রজেক্ট পদ্ধতিটি ডিবাগ করবেন না। যদি সম্ভব হয় তবে ইউনিট-টেস্ট স্টাইলের পরীক্ষাগুলি লেখার চেষ্টা করুন যাতে কী ভুল হচ্ছে তা আলাদা করা সহজ হয়।
  2. কাছাকাছি এবং দূরবর্তী উভয় ক্লিপিং প্লেনগুলির জন্য আউটপুট রশ্মি মুদ্রণ করতে ভুলবেন না।
  3. মনে রাখবেন ম্যাট্রিক্স গণিতটি পরিবর্তনশীল নয়। একটি এক্স সি! = সি x এ। আপনার গণিতটি ডাবল পরীক্ষা করুন।

এছাড়াও, উপরের কিছু মন্তব্যে জবাব দেওয়ার জন্য, আপনি প্রায় কখনওই ওপেনগিএলের নির্বাচন করা API ব্যবহার করতে চান না। এটি আপনাকে বিদ্যমান আইটেমগুলি বাছাই করতে সহায়তা করে, যেমন আপনি যদি একটি মেনু তৈরি করেন তবে এটি 3D মডেল সম্পাদনার মতো বেশিরভাগ বাস্তব-বিশ্বের পরিস্থিতি সম্পাদন করতে ব্যর্থ হয়। যেখানে ক্লিকের ফলাফল হিসাবে আপনাকে জ্যামিতি যুক্ত করতে হবে।

এখানে আমার বাস্তবায়ন। এখানে ম্যাজিক কিছুই চলছে না। কেবল জাভাস্ক্রিপ্ট এবং গুগলের বন্ধ লাইব্রেরি।

gluUnProject

/**
 * Port of gluUnProject. Unprojects a 2D screen coordinate into the model-view
 * coordinates.
 * @param {Number} winX The window point for the x value.
 * @param {Number} winY The window point for the y value.
 * @param {Number} winZ The window point for the z value. This should range
 *    between 0 and 1. 0 meaning the near clipping plane and 1 for the far.
 * @param {goog.math.Matrix} modelViewMatrix The model-view matrix.
 * @param {goog.math.Matrix} projectMatrix The projection matrix.
 * @param {Array.<Number>} view the viewport coordinate array.
 * @param {Array.<Number>} objPos the model point result.
 * @return {Boolean} Whether or not the unprojection was successful.
 */
octorok.math.Matrix.gluUnProject = function(winX, winY, winZ,
                        modelViewMatrix, projectionMatrix,
                        viewPort, objPos) {
  // Compute the inverse of the perspective x model-view matrix.
  /** @type {goog.math.Matrix} */
  var transformMatrix =
    projectionMatrix.multiply(modelViewMatrix).getInverse();

  // Transformation of normalized coordinates (-1 to 1).
  /** @type {Array.<Number>} */
  var inVector = [
    (winX - viewPort[0]) / viewPort[2] * 2.0 - 1.0,
    (winY - viewPort[1]) / viewPort[3] * 2.0 - 1.0,
    2.0 * winZ - 1.0,
    1.0 ];

  // Now transform that vector into object coordinates.
  /** @type {goog.math.Matrix} */
  // Flip 1x4 to 4x1. (Alternately use different matrix ctor.
  var inMatrix = new goog.math.Matrix([ inVector ]).getTranspose();
  /** @type {goog.math.Matrix} */
  var resultMtx = transformMatrix.multiply(inMatrix);
  /** @type {Array.<Number>} */
  var resultArr = [
    resultMtx.getValueAt(0, 0),
    resultMtx.getValueAt(1, 0),
    resultMtx.getValueAt(2, 0),
    resultMtx.getValueAt(3, 0) ];

  if (resultArr[3] == 0.0) {
    return false;
  }

  // Invert to normalize x, y, and z values.
  resultArr[3] = 1.0 / resultArr[3];

  objPos[0] = resultArr[0] * resultArr[3];
  objPos[1] = resultArr[1] * resultArr[3];
  objPos[2] = resultArr[2] * resultArr[3];

  return true;
};

ব্যবহার

  this.sys.event_mouseClicked = function(event) {
    // Relative x and y are computed via magic by SystemModule.
    // Should range from 0 .. viewport width/height.
    var winX = event.relativeX;
    var winY = event.relativeY;
    window.console.log('Camera at [' + me.camera.position_ + ']');
    window.console.log('Clicked [' + winX + ', ' + winY + ']');

    // viewportOriginX, viewportOriginY, viewportWidth, viewportHeight
    var viewPort = [0, 0, event.viewPortWidth, event.viewPortHeight];
    var objPos = [];  // out parameter.

    // The camera's model-view matrix is the result of gluLookAt.
    var modelViewMatrix = me.camera.getCameraMatrix();
    // The perspective matrix is the result of gluPerspective.
    var perspectiveMatrix = pMatrix.get();

    // Ray start
    var result1 = octorok.math.Matrix.gluUnProject(
      winX, winY, 0.0,
      modelViewMatrix, perspectiveMatrix,
      viewPort, objPos);
    window.console.log('Seg start: ' + objPos + ' (result:' + result1 + ')');

    // Ray end
    var result2 = octorok.math.Matrix.gluUnProject(
      winX, winY, 1.0,
      modelViewMatrix, perspectiveMatrix,
      viewPort, objPos);
    window.console.log('Seg end: ' + objPos + ' (result:' + result2 + ')');
  };
};

(রেজাল্টআর [3] == ০.০) যদি সত্যকে মূল্যায়ন করে তবে কোন ক্ষেত্রে?
হালসফার

3

আমি আপনার কোড নিয়ে কোনও সমস্যা দেখতে পাচ্ছি না। সুতরাং আমার কাছে কেবল কিছু পরামর্শ রয়েছে:

unit_x = (2.0f*((float)(x-vp[0])/(vp[2]-vp[0])))-1.0f,
unit_y = (2.0f*((float)(y-vp[1])/(vp[3]-vp[1])))-1.0f;

এবং ম্যাট্রিক্স মাল্টিপ্ল্লেকেশন এ পরিবর্তন করার চেষ্টা করছি (p*mv).inverse();। কেবলমাত্র গ্ল্যাম্যাট্রিকগুলি মেমরিতে পুষ্টিকরভাবে স্থানান্তরিত হয়। (এটি সম্ভবত একটি বড়, দুঃখিত)

আর একটি রাইস্টাস্টিং
আনপ্রজেক্টিং কেবল পিক্সেল থেকে কীভাবে রাই পাবেন তা নয়। এটি রাইস্টারের জন্য আমার কোড:

//works for right handed coordinates. So it is opengl friendly.
float mx = (float)((pixel.x - screenResolution.x * 0.5) * (1.0 / screenResolution.x) * camera.fovX * 0.5);
float my = (float)((pixel.y - screenResolution.y * 0.5) * (1.0 / screenResolution.x) * camera.fovX * 0.5);
float4 dx = cameraRight * mx;
float4 dy = cameraUp * my;

float3 dir = normalize(cameraDir + (dx + dy).xyz * 2.0);

আপনি ম্যাট্রিক্সের ভিউ থেকে ক্যামেরাআরাইট, আপ এবং দিকনির্দেশ পেতে পারেন (যা বেশিরভাগ শেডারে দরকারী) ওপেনগল এ ম্যাট্রিক্স দেখুন

রঙ পিকিং
রঙ পিকিং এমন কৌশল যা আপনি প্রতিটি ক্লিকযোগ্য অবজেক্টকে অন্য (কঠিন) রঙের সাথে রেন্ডার করেন এবং তারপরে ক্লিক পয়েন্টে রঙের মান পড়েন। এটি ওপেনগল-এ জিএল_এসইএলশন হিসাবে কাজ করেছে। তবে এটি এখন অবচয় করা হয়েছে। 1 টি অতিরিক্ত রেন্ডার পাস হিসাবে রঙ চয়ন করা কোড করা সহজ code

ফ্রেম বাফার ব্যবহার করুন এবং স্ক্রিন রেজোলিউশনের মতো একই রেজোলিউশনের সাথে টেক্সচারে রেন্ডার করুন, সরল শেডার ব্যবহার করুন যা কেবলমাত্র টুকরা শ্যাডারে রঙ ফিরে আসে। "রঙ পাস" এর পরে, ক্লিক পয়েন্ট x এবং y সহ একটি টেক্সচারের ঠিকানা থেকে মানটি পড়ুন। আপনি যে রঙটি পড়ছেন তা দিয়ে রঙ আবিষ্কার করুন। সহজ এবং বেশ দ্রুত।

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