Amerio.Stephane Posted July 17, 2024 Posted July 17, 2024 Hi, I need to position a calibration sight for the player. This would be a small dot/sphere, located *relative* to the camera with an azimuth and elevation angle. Looks simple enough, just using a Visualizer solid sphere would do the trick, but I can't correctly write the transform matrix. I know I have to multiply somehow the player world transform, azimuth rotation around the vertical axis and elevation rotation around the right hand, but whatever the order I try, it's never right. Please be my light in this math tunnel!
aezakku Posted July 18, 2024 Posted July 18, 2024 I'm not sure i correctly understood the problem, but here is some functions that might help you. using namespace Unigine; using namespace Math; dvec3 get_relative_point(PlayerPtr p, float azimuth, float elevation, float distance) { auto t = p->getWorldTransform() * rotateX(-90.0); quat rot = quat(elevation, 0, -azimuth); t = t * dmat4(rotate(rot)); dvec3 v = dvec3_forward * Scalar(distance); v = t * v; return v; } dvec3 get_absolute_point(PlayerPtr player, float azimuth, float elevation, float distance) { quat rot = quat(elevation, 0, azimuth); auto p = player->getWorldPosition(); auto t = translate(p) * dmat4(rotate(rot)); auto v = dvec3_forward * Scalar(distance); v = t * v; return v; } int AppWorldLogic::update() { auto p = Unigine::Game::getPlayer(); float azimuth = 10.0f; float elevation = 5.0f; auto p1 = get_relative_point(p, azimuth, elevation, 5); Visualizer::setEnabled(true); Visualizer::renderSolidSphere(0.1f, translate(p1), vec4_blue); auto p2 = get_absolute_point(p, azimuth, elevation, 5); Visualizer::renderSolidSphere(0.1f, translate(p2), vec4_red); return 1; } Quote azimuth rotation around the vertical axis and elevation rotation around the right hand i'm not sure that i understood your problem correctly
Amerio.Stephane Posted July 18, 2024 Author Posted July 18, 2024 (edited) Hi, I think we're almost there. Indeed, I was missing a crucial point with the camera basic orientation. Yet, with your code, the sphere is not excatly at the correct coordinate (with the get_relative_point). Here is my code slghtly adapted and the result: ConsoleVariableVec2 goniometer_steps{ "goniometer_steps", "\tGoniometer steps (azimuth,elevation)", false, {10,10} }; ConsoleVariableVec2 goniometer_target{ "goniometer_target", "\tGoniometer target position (azimuth,elevation)", false, {40,20} }; Vec3 get_relative_point(Mat4 transform, float azimuth, float elevation, float distance) { auto t = transform * rotateX(-90.0); quat rot = quat(elevation, 0, -azimuth); t = t * dmat4(rotate(rot)); dvec3 v = dvec3_forward * Scalar(distance); v = t * v; return v; } void AppSystemLogic::goniometer() { const double distance = 10; double step_azim = goniometer_steps.get().x; double step_elev = goniometer_steps.get().y; double target_azim = goniometer_target.get().x; double target_elev = goniometer_target.get().y; auto mat = p->getWorldTransform(); auto d = -mat.getAxisZ() * .1; Mat4 m = translate(d); // Azimuth rings (red) Mat4 my = rotateY(90.); Visualizer::renderCircle(distance, mat * my, vec4_white, 0, false); for (int i = 1; i * step_azim <= 90; ++i) { Mat4 m0 = rotateY(i * step_azim); Visualizer::renderCircle(distance, mat * my * m0, vec4_red, 0, false); Mat4 m1 = rotateY(i * -step_azim); Visualizer::renderCircle(distance, mat * my * m1, vec4_red, 0, false); } // Elevation rings (green) Mat4 mx = rotateX(90.); Visualizer::renderCircle(distance, mat * mx, vec4_white, 0, false); for (int j = 1; j * step_elev <= 90; ++j) { Mat4 m0 = rotateX(j * step_elev); Visualizer::renderCircle(distance, mat * mx * m0, vec4_green, 0, false); Mat4 m1 = rotateX(j * -step_elev); Visualizer::renderCircle(distance, mat * mx * m1, vec4_green, 0, false); } // Calibration Target (white) auto p1 = get_relative_point(mat, target_azim, target_elev, distance); Visualizer::renderSolidSphere(0.1f, translate(p1), vec4_white, 0, false); } As you can see, the dot is not exactly on the azimuth=40, elevation=20 grid point. What am I misunderstanding? Edited July 18, 2024 by Amerio.Stephane typo
aezakku Posted July 18, 2024 Posted July 18, 2024 Yes, we had a problem with calculation of rotation, here is the correct one: dvec3 get_relative_point(Mat4 p, float azimuth, float elevation, float distance) { auto t = p; auto rot = composeRotationZXY(vec3(elevation, 0, -azimuth)); t = t * dmat4(rot); dvec3 v = dvec3_forward * static_cast<Scalar>(distance); v = t * v; return v; } My assumption is that you are using incorrect grid, here is what i think is correct one to use in this problem: int AppWorldLogic::update() { const auto p = Game::getPlayer(); constexpr float target_azim = 40.0f; constexpr float target_elev = 20.0f; const dmat4 transform = p->getWorldTransform() * rotateX(-90.0); constexpr float distance = 10.; constexpr float step_azim = 10.; constexpr float step_elev = 10.; for (int i = 0; static_cast<float>(i) * step_azim <= 90; ++i) { const float angle = static_cast<float>(i) * step_azim; Visualizer::renderSector(distance, 180.f, transform * Mat4(rotateY(90.f) * rotateX(angle)), vec4_blue); Visualizer::renderSector(distance, 180.f, transform * Mat4(rotateY(90.f) * rotateX(-angle)), vec4_blue); } for (int j = 1; static_cast<float>(j) * step_elev <= 90; ++j) { const float angle = static_cast<float>(j) * static_cast<float>(step_elev) * static_cast<float>(j + 1); const float z = Math::sin(angle * Consts::DEG2RAD) * distance; const float r = Math::cos(angle * Consts::DEG2RAD) * distance; Visualizer::renderCircle(r, transform * Mat4(translate(vec3(0, 0, z))), vec4_red); Visualizer::renderCircle(r, transform * Mat4(translate(vec3(0, 0, -z))), vec4_red); } const dvec3 p1 = get_relative_point(transform, target_azim, target_elev, distance); Visualizer::renderSolidSphere(0.1f, translate(p1), vec4_white, 0, false); return 1; } Here is the result: 2
Amerio.Stephane Posted July 18, 2024 Author Posted July 18, 2024 Indeed, my lines were all wrong! Thanks a lot for the correct code and the insight in the math lib! 2
Recommended Posts