ฉันเพิ่งต้องแก้ปัญหานี้ด้วยตัวเองสำหรับแอปพลิเคชัน WebGL ฉันได้แนบซอร์สโค้ดที่สมบูรณ์ แต่ในกรณีที่มันไม่ทำงานทันทีสำหรับคุณที่นี่มีเคล็ดลับการแก้ไขข้อบกพร่องบางอย่าง:
- อย่าแก้ปัญหาวิธีการ unproject ของคุณในเกมของคุณ ถ้าเป็นไปได้ให้ลองเขียนการทดสอบรูปแบบการทดสอบหน่วยเพื่อให้ง่ายต่อการแยกสิ่งที่ผิดพลาดออกไป
- ตรวจสอบให้แน่ใจว่าได้พิมพ์รังสีเอาท์พุตสำหรับระนาบการตัดทั้งใกล้และไกล
- จำไว้ว่าคณิตศาสตร์เมทริกซ์นั้นไม่ใช่การสลับสับเปลี่ยน A x C! = C x A. ตรวจสอบคณิตศาสตร์ของคุณอีกครั้ง
นอกจากนี้ในการตอบกลับความคิดเห็นด้านบนคุณแทบไม่เคยต้องการใช้ API การเลือกของ OpenGL เลย ที่ช่วยให้คุณเลือกรายการที่มีอยู่เช่นถ้าคุณกำลังสร้างเมนูอย่างไรก็ตามมันล้มเหลวในการดำเนินการสถานการณ์จริงส่วนใหญ่เช่นการแก้ไขแบบจำลอง 3 มิติ ตำแหน่งที่คุณต้องการเพิ่มรูปทรงเรขาคณิตอันเป็นผลมาจากการคลิก
นี่คือการดำเนินการของฉัน ไม่มีอะไรวิเศษเกิดขึ้นที่นี่ เพียงแค่ JavaScript และห้องสมุดปิดของ Google
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 + ')');
};
};