Skip to content

Commit

Permalink
[gui] Add get_view_matrix() and get_projection_matrix() APIs for came…
Browse files Browse the repository at this point in the history
…ra (#5345)

* Add 2 new functions(get camera view/proj matrix) to Camera Class

* expose 2 new functions(get camera view/proj matrix) to PyCamera

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* [gui] Add 2 new functions(get camera view/projection matrix) to Camera Class

* [gui] expose 2 new functions(get camera view/projection matrix) of PyCamera Class

* add a test for getting the view/projection matrix of camera

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* expose 2 new functions(get camera view/proj matrix) to PyCamera

* Update taichi/python/export_ggui.cpp

Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>

* Update taichi/python/export_ggui.cpp

Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>

* Update taichi/python/export_ggui.cpp

Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>

* Update taichi/python/export_ggui.cpp

Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>

* Update taichi/python/export_ggui.cpp

Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add test for get the view/projection matrix of camera

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: YuZhang <YuCrazing@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 7, 2022
1 parent ef9cfaa commit c374dfe
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
22 changes: 22 additions & 0 deletions python/taichi/ui/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,28 @@ def z_far(self, z_far):
"""
self.ptr.z_far(z_far)

def get_view_matrix(self):
"""Get the view matrix(in row major) of the camera.
Example::
>>> camera.get_view_matrix()
"""
return self.ptr.get_view_matrix()

def get_projection_matrix(self, aspect):
"""Get the projection matrix(in row major) of the camera.
Args:
aspect (:mod:`taichi.types.primitive_types`): \
aspect ratio of the camera
Example::
>>> camera.get_projection_matrix(1080/720)
"""
return self.ptr.get_projection_matrix(aspect)

def track_user_inputs(self,
window,
movement_speed=1.0,
Expand Down
26 changes: 25 additions & 1 deletion taichi/python/export_ggui.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <vector>
#include "pybind11/pybind11.h"
#include <pybind11/numpy.h>
#include "pybind11/stl.h"

#include "taichi/common/interface.h"
Expand Down Expand Up @@ -34,6 +35,21 @@ pybind11::tuple vec3_to_tuple(glm::vec3 v) {
return pybind11::make_tuple(v.x, v.y, v.z);
}

// Here we convert the 2d-array to numpy array using pybind. Refs:
// https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html?highlight=array_t#vectorizing-functions
// https://stackoverflow.com/questions/44659924/returning-numpy-arrays-via-pybind11
py::array_t<float> mat4_to_nparray(glm::mat4 mat) {
// Here we must explicitly pass args using py::detail::any_container<ssize_t>.
// Refs:
// https://stackoverflow.com/questions/54055530/error-no-matching-function-for-call-to-pybind11buffer-infobuffer-info
return py::array_t<float>(
py::detail::any_container<ssize_t>({4, 4}), // shape (rows, cols)
py::detail::any_container<ssize_t>(
{sizeof(float) * 4, sizeof(float)}), // strides in bytes
glm::value_ptr(mat), // buffer pointer
nullptr);
}

struct PyGui {
GuiBase *gui; // not owned
void begin(std::string name, float x, float y, float width, float height) {
Expand Down Expand Up @@ -99,6 +115,12 @@ struct PyCamera {
void z_far(float z_far_) {
camera.z_far = z_far_;
}
py::array_t<float> get_view_matrix() {
return mat4_to_nparray(camera.get_view_matrix());
}
py::array_t<float> get_projection_matrix(float aspect_ratio) {
return mat4_to_nparray(camera.get_projection_matrix(aspect_ratio));
}
};

struct PyScene {
Expand Down Expand Up @@ -368,7 +390,9 @@ void export_ggui(py::module &m) {
.def("top", &PyCamera::top)
.def("bottom", &PyCamera::bottom)
.def("z_near", &PyCamera::z_near)
.def("z_far", &PyCamera::z_far);
.def("z_far", &PyCamera::z_far)
.def("get_view_matrix", &PyCamera::get_view_matrix)
.def("get_projection_matrix", &PyCamera::get_projection_matrix);

py::class_<Event>(m, "Event")
.def_property("key", &Event::get_key, &Event::set_key);
Expand Down
23 changes: 23 additions & 0 deletions tests/python/test_ggui.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,26 @@ def render():
@test_utils.test(arch=supported_archs)
def test_exit_without_showing():
window = ti.ui.Window("Taichi", (256, 256), show_window=False)


@test_utils.test(arch=supported_archs)
def test_get_camera_view_and_projection_matrix():
scene = ti.ui.Scene()
camera = ti.ui.make_camera()
camera.position(0, 0, 3)
camera.lookat(0, 0, 0)

scene.set_camera(camera)

view_matrix = camera.get_view_matrix()
projection_matrix = camera.get_projection_matrix(1080 / 720)

for i in range(4):
assert (abs(view_matrix[i, i] - 1) <= 1e-5)
assert (abs(view_matrix[3, 2] + 3) <= 1e-5)

assert (abs(projection_matrix[0, 0] - 1.6094756) <= 1e-5)
assert (abs(projection_matrix[1, 1] - 2.4142134) <= 1e-5)
assert (abs(projection_matrix[2, 2] - 1.0001000e-4) <= 1e-5)
assert (abs(projection_matrix[2, 3] + 1.0000000) <= 1e-5)
assert (abs(projection_matrix[3, 2] - 1.0001000e-1) <= 1e-5)

0 comments on commit c374dfe

Please sign in to comment.