{ "cells": [ { "cell_type": "markdown", "id": "95b8d692-46ba-4d7c-beb8-c7b2ecdbe883", "metadata": {}, "source": [ "# Blender" ] }, { "cell_type": "markdown", "id": "cffb7e10-1aa1-46d9-8eac-7fa9fab3daae", "metadata": {}, "source": [ "## Rotation formalisms" ] }, { "attachments": {}, "cell_type": "markdown", "id": "df40f778-f020-4026-a5c8-2ede7957a2c2", "metadata": {}, "source": [ "See [Rotation formalisms in three dimensions](https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions). Blender's user interface only allows for rotations to be entered as as Quaternions, Euler rotations, or an Euler axis-angle. If you have a rotation in some other form, how do you enter it in Blender? See [Rotation — SciPy Manual](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html#scipy.spatial.transform.Rotation):" ] }, { "cell_type": "code", "execution_count": 10, "id": "d4248180-dbdc-4f1c-8cc0-89ea294e6676", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from scipy.spatial.transform import Rotation as R\n", "\n", "def show_rot(rot: R):\n", " print('Matrix:')\n", " display(rot.as_matrix())\n", " print('\\nBlender \"Quaternion\":')\n", " display(rot.as_quat(canonical=True, scalar_first=True))\n", " print('\\nBlender \"XYZ Euler\":')\n", " with np.printoptions(precision=3, suppress=True):\n", " display(rot.as_euler('xyz', degrees=True))\n", " print('\\nBlender \"Axis Angle\":')\n", " rot_vec = rot.as_rotvec(degrees=True)\n", " norm = np.linalg.norm(rot_vec)\n", " display(norm, rot_vec / norm)" ] }, { "cell_type": "code", "execution_count": 11, "id": "8e632615-e826-48b4-b88b-d921eee33ef0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Matrix:\n" ] }, { "data": { "text/plain": [ "array([[ 0., 0., 1.],\n", " [-1., 0., 0.],\n", " [ 0., -1., 0.]])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Quaternion\":\n" ] }, { "data": { "text/plain": [ "array([ 0.5, -0.5, 0.5, -0.5])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"XYZ Euler\":\n" ] }, { "data": { "text/plain": [ "array([-90., 0., -90.])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Axis Angle\":\n" ] }, { "data": { "text/plain": [ "np.float64(119.99999999999999)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "array([-0.57735027, 0.57735027, -0.57735027])" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_rot(R.from_matrix([\n", "[ 0.000, 0.000, 1.000],\n", "[-1.000, 0.000, 0.000],\n", "[ 0.000, -1.000, 0.000],]))" ] }, { "cell_type": "code", "execution_count": 12, "id": "f9e8120f-a6cc-4600-a575-18fa784f4c6f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Matrix:\n" ] }, { "data": { "text/plain": [ "array([[ 5.29999071e-01, 1.50000013e-07, -8.47998222e-01],\n", " [ 8.47998222e-01, 8.31371382e-08, 5.29999071e-01],\n", " [ 1.50000013e-07, -1.00000000e+00, -8.31371382e-08]])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Quaternion\":\n" ] }, { "data": { "text/plain": [ "array([ 0.61846566, -0.61846566, -0.34278313, 0.34278301])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"XYZ Euler\":\n" ] }, { "data": { "text/plain": [ "array([-90. , -0. , 57.995])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Axis Angle\":\n" ] }, { "data": { "text/plain": [ "np.float64(103.591650166481)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "array([-0.7870404 , -0.43621528, 0.43621513])" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_rot(R.from_matrix([\n", "[ 0.52999894, 0., -0.847998, ],\n", "[ 0.8479983 , 0., 0.52999894, ],\n", "[ 0. , -1., 0. ],]))" ] }, { "cell_type": "code", "execution_count": 13, "id": "d65d3481-2753-4ff0-be25-fb991548c20c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Matrix:\n" ] }, { "data": { "text/plain": [ "array([[-2.77555756e-17, -6.42962682e-01, -7.65897506e-01],\n", " [ 0.00000000e+00, -7.65897506e-01, 6.42962682e-01],\n", " [-1.00000000e+00, 0.00000000e+00, -2.77555756e-17]])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Quaternion\":\n" ] }, { "data": { "text/plain": [ "array([ 0.2419207 , -0.66443538, 0.2419207 , 0.66443538])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"XYZ Euler\":\n" ] }, { "data": { "text/plain": [ "array([-139.987, 90. , 0. ])" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Blender \"Axis Angle\":\n" ] }, { "data": { "text/plain": [ "np.float64(152.00014158445592)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "array([-0.68477595, 0.24932669, 0.68477595])" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "show_rot(R.from_matrix([\n", "[ 0.000, -0.643, -0.766],\n", "[ 0.000, -0.766, 0.643],\n", "[-1.000, 0.000, 0.000],]))" ] }, { "cell_type": "markdown", "id": "7f4269d8-0a90-4a53-8b2e-1b940ec8fbc4", "metadata": {}, "source": [ "You may see a warning about Gimbal lock. Many Blender tutorials try to explain Gimbal lock, but the best references still seem to be [Euler (gimbal lock) Explained - YouTube](https://www.youtube.com/watch?v=zc8b2Jo7mno) and [Gimbal lock - Wikipedia](https://en.wikipedia.org/wiki/Gimbal_lock). See also [Rotation Modes - Blender 4.5 LTS Manual](https://docs.blender.org/manual/en/latest/advanced/appendices/rotations.html)." ] }, { "cell_type": "markdown", "id": "2bb2fea7-61d9-4d6c-aab8-7b72e4290ff5", "metadata": {}, "source": [ "In Eigen, quaternion-vector multiplication is [just multiplication](https://stackoverflow.com/a/52239772/622049). In Eigen the coeffs command [produces XYZW](https://eigen.tuxfamily.org/dox/classEigen_1_1QuaternionBase.html#a193e79f616335a0067e3e784c7cf85fa), but internally the data is XYZW. If you [install the Eigen pretty printers](https://stackoverflow.com/a/25088214/622049), it's explicit:\n", "```\n", "$1 = Eigen::Quaternion (data ptr: 0x7fffffffd7d0) = {[x] = 0, [y] = 0.7071067811865841, [z] = 0, [w] = 0.70710678118651094}\n", "```" ] }, { "cell_type": "markdown", "id": "f7751666-a438-40e4-87db-b6cb8fda5c18", "metadata": {}, "source": [ "## Edit preferences (`Ctrl`+`,`)" ] }, { "cell_type": "markdown", "id": "e587e5fa-82b9-4a55-8e59-c0e1379b54b5", "metadata": {}, "source": [ "You have to close all Blender windows to save it after you change your preferences. Otherwise if Blender or your computer crashes, you lose your setup." ] }, { "cell_type": "markdown", "id": "b006627d-2b98-4cdf-bd75-c7fa6f1c1ba7", "metadata": {}, "source": [ "There's no up (or bottom) in space. There's also no up or bottom in a group like [SO(3)](https://en.wikipedia.org/wiki/3D_rotation_group). See [Rotate view around vertical Y-axis - Blender Stack Exchange](https://blender.stackexchange.com/questions/36049/rotate-view-around-vertical-y-axis/45127#45127) to get off the planet and make it easier to work with point clouds in ECEF, or models not following Blender's definition of Earth's up being in the Z-direction. If you're doing that, you'll probably also want the change in [interface - How to roll the viewport?](https://blender.stackexchange.com/questions/15049/how-to-roll-the-viewport). I prefer 0.04 to the 0.02 suggested there. You can also add Ctrl+MouseWheel for coarse control (0.24). The net effect of these changes is to make your user interface much more similar to CloudCompare, which is more oriented towards data from the real world." ] }, { "cell_type": "markdown", "id": "48f490d6-ece7-4db3-98b8-337408c9be1d", "metadata": {}, "source": [ "Change the default navigation mode to fly mode rather than walk mode. Add a keyboard shortcut to enter fly mode of `Shift`-`F` (`view3d.navigate`). With this shortcut, your fingers are already on the keys you need for fly mode." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.8" } }, "nbformat": 4, "nbformat_minor": 5 }