Skip to content

Commit

Permalink
Port of the lookatRH function from glm to TensorFlow.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 267177124
  • Loading branch information
julienvalentin authored and Copybara-Service committed Sep 5, 2019
1 parent 379ee39 commit 49105aa
Show file tree
Hide file tree
Showing 6 changed files with 512 additions and 0 deletions.
1 change: 1 addition & 0 deletions tensorflow_graphics/rendering/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ py_library(
visibility = ["//visibility:public"],
deps = [
"//tensorflow_graphics/rendering/camera",
"//tensorflow_graphics/rendering/opengl",
"//tensorflow_graphics/rendering/reflectance",
"//tensorflow_graphics/util:export_api",
],
Expand Down
1 change: 1 addition & 0 deletions tensorflow_graphics/rendering/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from __future__ import print_function

from tensorflow_graphics.rendering import camera
from tensorflow_graphics.rendering import opengl
from tensorflow_graphics.rendering import reflectance
from tensorflow_graphics.util import export_api as _export_api

Expand Down
68 changes: 68 additions & 0 deletions tensorflow_graphics/rendering/opengl/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Math functionalities for tf-graphics.

# google internal package dependency 8)
# google internal package dependency 5

licenses(["notice"]) # Apache 2.0

package(default_visibility = ["//visibility:public"])

py_library(
name = "opengl",
srcs = [
"__init__.py",
],
srcs_version = "PY2AND3",
# google internal rule 1
visibility = ["//visibility:public"],
deps = [
":math",
"//tensorflow_graphics/util:export_api",
],
)

py_library(
name = "math",
srcs = ["math.py"],
srcs_version = "PY2AND3",
# google internal rule 1
deps = [
# google internal package dependency 1,
"//tensorflow_graphics/math:vector",
"//tensorflow_graphics/util:asserts",
"//tensorflow_graphics/util:export_api",
"//tensorflow_graphics/util:shape",
],
)

py_test(
name = "math_test",
srcs = ["tests/math_test.py"],
srcs_version = "PY2AND3",
# google internal rule 1
# google internal rule 2
# google internal rule 3
# google internal rule 4
# google internal rule 5
# google internal rule 6
deps = [
":math",
# google internal package dependency 2
# google internal package dependency 6
# google internal package dependency 1,
"//tensorflow_graphics/util:test_case",
],
)
23 changes: 23 additions & 0 deletions tensorflow_graphics/rendering/opengl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""OpenGL module."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from tensorflow_graphics.rendering.opengl import math
from tensorflow_graphics.util import export_api as _export_api

# API contains submodules of tensorflow_graphics.rendering.
__all__ = _export_api.get_modules()
163 changes: 163 additions & 0 deletions tensorflow_graphics/rendering/opengl/math.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module implements math routines used by OpenGL."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import math
import tensorflow as tf

from tensorflow_graphics.math import vector
from tensorflow_graphics.util import asserts
from tensorflow_graphics.util import export_api
from tensorflow_graphics.util import shape


def perspective_rh(vertical_field_of_view, aspect_ratio, near, far, name=None):
"""Generates the matrix for a right handed perspective-view frustum.
Note:
In the following, A1 to An are optional batch dimensions.
Args:
vertical_field_of_view: A tensor of shape `[A1, ..., An, C]`, where the last
dimension represents the vertical field of view of the frustum. Note that
values for `vertical_field_of_view` must be in the range ]0,pi[.
aspect_ratio: A tensor of shape `[A1, ..., An, C]`, where the last dimension
stores the width over height ratio of the frustum. Note that values for
`aspect_ratio` must be non-negative.
near: A tensor of shape `[A1, ..., An, C]`, where the last dimension
captures the distance between the viewer and the near clipping plane. Note
that values for `near` must be non-negative.
far: A tensor of shape `[A1, ..., An, C]`, where the last dimension
captures the distance between the viewer and the far clipping plane. Note
that values for `far` must be non-negative.
name: A name for this op. Defaults to 'perspective_rh'.
Raises:
InvalidArgumentError: if any input contains data not in the specified range
of valid values.
ValueError: if the all the inputs are not of the same shape.
Returns:
A tensor of shape `[A1, ..., An, C, 4, 4]`, containing matrices of right
handed perspective-view frustum.
"""
with tf.compat.v1.name_scope(
name, "perspective_rh",
[vertical_field_of_view, aspect_ratio, near, far]):
vertical_field_of_view = tf.convert_to_tensor(value=vertical_field_of_view)
aspect_ratio = tf.convert_to_tensor(value=aspect_ratio)
near = tf.convert_to_tensor(value=near)
far = tf.convert_to_tensor(value=far)

shape.compare_batch_dimensions(
tensors=(vertical_field_of_view, aspect_ratio, near, far),
last_axes=-1,
tensor_names=("vertical_field_of_view", "aspect_ratio", "near", "far"),
broadcast_compatible=False)

vertical_field_of_view = asserts.assert_all_in_range(
vertical_field_of_view, 0.0, math.pi, open_bounds=True)
aspect_ratio = asserts.assert_all_above(aspect_ratio, 0.0, open_bound=True)
near = asserts.assert_all_above(near, 0.0, open_bound=True)
far = asserts.assert_all_above(far, 0.0, open_bound=True)

tan_half_vertical_field_of_view = tf.tan(vertical_field_of_view * 0.5)
zero = tf.zeros_like(tan_half_vertical_field_of_view)
one = tf.ones_like(tan_half_vertical_field_of_view)

x = tf.stack(
(1.0 /
(aspect_ratio * tan_half_vertical_field_of_view), zero, zero, zero),
axis=-1)
y = tf.stack((zero, 1.0 / tan_half_vertical_field_of_view, zero, zero),
axis=-1)
z = tf.stack((zero, zero,
(far + near) / (near - far), 2.0 * far * near / (near - far)),
axis=-1)
w = tf.stack((zero, zero, -one, zero), axis=-1)

return tf.stack((x, y, z, w), axis=-2)


def look_at_right_handed(camera_position, look_at, up_vector, name=None):
"""Builds a right handed look at view matrix.
Note:
In the following, A1 to An are optional batch dimensions.
Args:
camera_position: A tensor of shape `[A1, ..., An, 3]`, where the last
dimension represents the 3D position of the camera.
look_at: A tensor of shape `[A1, ..., An, 3]`, with the last dimension
storing the position where the camera is looking at.
up_vector: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
defines the up vector of the camera.
name: A name for this op. Defaults to 'look_at_right_handed'.
Raises:
ValueError: if the all the inputs are not of the same shape, or if any input
of of an unsupported shape.
Returns:
A tensor of shape `[A1, ..., An, 4, 4]`, containing right handed look at
matrices.
"""
with tf.compat.v1.name_scope(name, "look_at_right_handed",
[camera_position, look_at, up_vector]):
camera_position = tf.convert_to_tensor(value=camera_position)
look_at = tf.convert_to_tensor(value=look_at)
up_vector = tf.convert_to_tensor(value=up_vector)

shape.check_static(
tensor=camera_position,
tensor_name="camera_position",
has_dim_equals=(-1, 3))
shape.check_static(
tensor=look_at, tensor_name="look_at", has_dim_equals=(-1, 3))
shape.check_static(
tensor=up_vector, tensor_name="up_vector", has_dim_equals=(-1, 3))
shape.compare_batch_dimensions(
tensors=(camera_position, look_at, up_vector),
last_axes=-2,
tensor_names=("camera_position", "look_at", "up_vector"),
broadcast_compatible=False)

z_axis = tf.linalg.l2_normalize(look_at - camera_position, axis=-1)
horizontal_axis = tf.linalg.l2_normalize(
tf.cross(z_axis, up_vector), axis=-1)
vertical_axis = tf.cross(horizontal_axis, z_axis)

batch_shape = tf.shape(horizontal_axis)[:-1]
zeros = tf.zeros(
shape=tf.concat((batch_shape, (3,)), axis=-1),
dtype=horizontal_axis.dtype)
one = tf.ones(
shape=tf.concat((batch_shape, (1,)), axis=-1),
dtype=horizontal_axis.dtype)
x = tf.concat(
(horizontal_axis, -vector.dot(horizontal_axis, camera_position)),
axis=-1)
y = tf.concat((vertical_axis, -vector.dot(vertical_axis, camera_position)),
axis=-1)
z = tf.concat((-z_axis, vector.dot(z_axis, camera_position)), axis=-1)
w = tf.concat((zeros, one), axis=-1)
return tf.stack((x, y, z, w), axis=-2)


# API contains all public functions and classes.
__all__ = export_api.get_functions_and_classes()

0 comments on commit 49105aa

Please sign in to comment.