bool GraphicsManager::project(float x, float y, float z, float &sX, float &sY, float &sZ) { // This is our projection matrix Common::TransformationMatrix proj(_projection); // Generate the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); // Apply camera orientation model.rotate(-cOrient[0], 1.0f, 0.0f, 0.0f); model.rotate( cOrient[1], 0.0f, 1.0f, 0.0f); model.rotate(-cOrient[2], 0.0f, 0.0f, 1.0f); // Apply camera position model.translate(-cPos[0], -cPos[1], cPos[2]); Common::Vector3 coords(x, y, z); // Multiply them Common::Vector3 v(proj * model * coords); // Projection divide if (v._w == 0.0f) return false; float divider = 1.0f / v._w; v *= divider; // Viewport coordinates float view[4]; view[0] = 0.0f; view[1] = 0.0f; view[2] = _width; view[3] = _height; sX = view[0] + view[2] * (v._x + 1.0f) / 2.0f; sY = view[1] + view[3] * (v._y + 1.0f) / 2.0f; sZ = (v._z + 1.0f) / 2.0f; sX -= view[2] / 2.0f; sY -= view[3] / 2.0f; return true; }
bool GraphicsManager::unproject(float x, float y, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2) const { try { // Generate the inverse of the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); // Apply camera position model.translate(cPos[0], cPos[1], -cPos[2]); // Apply camera orientation model.rotate( cOrient[2], 0.0f, 0.0f, 1.0f); model.rotate(-cOrient[1], 0.0f, 1.0f, 0.0f); model.rotate( cOrient[0], 1.0f, 0.0f, 0.0f); // Multiply with the inverse of our projection matrix model *= _projectionInv; // Coordinates at the near and far clipping planes Common::Vector3 coordsNear, coordsFar; if (_projectType == kProjectTypePerspective) { /* With a perspective projection, the viewport runs from -1.0 to 0.0 * on the x and y axes, and the clipping planes are at 0.0 and 1.0. */ const float view[4] = { 0.0f, 0.0f, (float) _width, (float) _height }; const float zNear = 0.0f; const float zFar = 1.0f; coordsNear._x = ((2 * (x - view[0])) / (view[2])) - 1.0f; coordsNear._y = ((2 * (y - view[1])) / (view[3])) - 1.0f; coordsNear._z = (2 * zNear) - 1.0f; coordsNear._w = 1.0f; coordsFar._x = ((2 * (x - view[0])) / (view[2])) - 1.0f; coordsFar._y = ((2 * (y - view[1])) / (view[3])) - 1.0f; coordsFar._z = (2 * zFar) - 1.0f; coordsFar._w = 1.0f; } else if (_projectType == kProjectTypeOrthogonal) { /* With an orthogonal projection, the viewport runs from 0.0 to width * on the x axis and from 0.0 to height on the y axis (which already * matches the coordinates we were given), and the clipping planes are * at -clipNear and -clipFar. */ coordsNear._x = x; coordsNear._y = y; coordsNear._z = -_clipNear; coordsNear._w = 1.0f; coordsFar._x = x; coordsFar._y = y; coordsFar._z = -_clipFar; coordsFar._w = 1.0f; } // Unproject Common::Vector3 oNear(model * coordsNear); Common::Vector3 oFar (model * coordsFar ); if ((oNear._w == 0.0f) || (oFar._w == 0.0f)) return false; // TODO: check for close to 0.0f, not exactly 0.0f. // And return the values oNear._w = 1.0f / oNear._w; x1 = oNear._x * oNear._w; y1 = oNear._y * oNear._w; z1 = oNear._z * oNear._w; oFar._w = 1.0f / oFar._w; x2 = oFar._x * oFar._w; y2 = oFar._y * oFar._w; z2 = oFar._z * oFar._w; } catch (Common::Exception &e) { Common::printException(e, "WARNING: "); return false; } catch (...) { return false; } return true; }
bool GraphicsManager::unproject(float x, float y, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2) const { try { // Generate the inverse of the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; CameraMan.lock(); memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); CameraMan.unlock(); // Apply camera position model.translate(cPos[0], cPos[1], -cPos[2]); // Apply camera orientation model.rotate( cOrient[2], 0.0, 0.0, 1.0); model.rotate(-cOrient[1], 0.0, 1.0, 0.0); model.rotate( cOrient[0], 1.0, 0.0, 0.0); // Multiply with the inverse of our projection matrix model *= _projectionInv; // Viewport coordinates float view[4]; view[0] = 0.0; view[1] = 0.0; view[2] = _screen->w; view[3] = _screen->h; float zNear = 0.0; float zFar = 1.0; // Generate a matrix for the coordinates at the near plane Common::Matrix coordsNear(4, 1); coordsNear(0, 0) = ((2 * (x - view[0])) / (view[2])) - 1.0; coordsNear(1, 0) = ((2 * (y - view[1])) / (view[3])) - 1.0; coordsNear(2, 0) = (2 * zNear) - 1.0; coordsNear(3, 0) = 1.0; // Generate a matrix for the coordinates at the far plane Common::Matrix coordsFar(4, 1); coordsFar(0, 0) = ((2 * (x - view[0])) / (view[2])) - 1.0; coordsFar(1, 0) = ((2 * (y - view[1])) / (view[3])) - 1.0; coordsFar(2, 0) = (2 * zFar) - 1.0; coordsFar(3, 0) = 1.0; // Unproject Common::Matrix oNear(model * coordsNear); Common::Matrix oFar (model * coordsFar ); if ((oNear(3, 0) == 0.0) || (oNear(3, 0) == 0.0)) return false; // And return the values oNear(3, 0) = 1.0 / oNear(3, 0); x1 = oNear(0, 0) * oNear(3, 0); y1 = oNear(1, 0) * oNear(3, 0); z1 = oNear(2, 0) * oNear(3, 0); oFar(3, 0) = 1.0 / oFar(3, 0); x2 = oFar(0, 0) * oFar(3, 0); y2 = oFar(1, 0) * oFar(3, 0); z2 = oFar(2, 0) * oFar(3, 0); } catch (Common::Exception &e) { Common::printException(e, "WARNING: "); return false; } catch (...) { return false; } return true; }
bool GraphicsManager::project(float x, float y, float z, float &sX, float &sY, float &sZ) { // This is our projection matrix Common::Matrix proj = _projection; // Generate the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; CameraMan.lock(); memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); CameraMan.unlock(); // Apply camera orientation model.rotate(-cOrient[0], 1.0, 0.0, 0.0); model.rotate( cOrient[1], 0.0, 1.0, 0.0); model.rotate(-cOrient[2], 0.0, 0.0, 1.0); // Apply camera position model.translate(-cPos[0], -cPos[1], cPos[2]); // Generate a matrix for the coordinates Common::Matrix coords(4, 1); coords(0, 0) = x; coords(1, 0) = y; coords(2, 0) = z; coords(3, 0) = 1.0; // Multiply them Common::Matrix v(proj * model * coords); // Projection divide if (v(3, 0) == 0.0) return false; v(0, 0) /= v(3, 0); v(1, 0) /= v(3, 0); v(2, 0) /= v(3, 0); // Viewport coordinates float view[4]; view[0] = 0.0; view[1] = 0.0; view[2] = _screen->w; view[3] = _screen->h; sX = view[0] + view[2] * (v(0, 0) + 1.0) / 2.0; sY = view[1] + view[3] * (v(1, 0) + 1.0) / 2.0; sZ = (v(2, 0) + 1.0) / 2.0; sX -= view[2] / 2.0; sY -= view[3] / 2.0; return true; }