Skip to content

Commit

Permalink
Merge pull request #35 from GazzolaLab/exp/director
Browse files Browse the repository at this point in the history
Exp/director
  • Loading branch information
Rohar10 authored Oct 29, 2024
2 parents 1c11e33 + 509c73a commit 55ec38f
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 28 deletions.
104 changes: 79 additions & 25 deletions examples/pose_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,115 @@


def angle_to_color(angle: float) -> np.ndarray:
# Normalize angle to 0-360 range
"""
Convert angle to RGB color value
Parameters
----------
angle : float
The angle in degrees
Returns
-------
np.ndarray
The RGBA color value
"""

# Reset angle range to 0-360 degrees
angle = angle % 360

# Convert angle to radians
rad = np.radians(angle)

# Calculate RGB values
if angle < 120:
r = np.cos(rad) / 2 + 0.5
g = np.sin(rad) / 2 + 0.5
b = 0
rad = 3 * rad / 2
r = 0.5 + np.sin(rad) / 2
g = 0.5 - np.sin(rad) / 2
b = 0.5 - np.sin(rad) / 2
elif angle < 240:
r = 0
g = np.cos(rad - 2 * np.pi / 3) / 2 + 0.5
b = np.sin(rad - 2 * np.pi / 3) / 2 + 0.5
rad = rad - 2 * np.pi / 3
rad = 3 * rad / 2
r = 0.5 - np.sin(rad) / 2
g = 0.5 + np.sin(rad) / 2
b = 0.5 - np.sin(rad) / 2
else:
r = np.sin(rad - 4 * np.pi / 3) / 2 + 0.5
g = 0
b = np.cos(rad - 4 * np.pi / 3) / 2 + 0.5
rad = rad - 2 * np.pi / 3 * 2
rad = 3 * rad / 2
r = 0.5 - np.sin(rad) / 2
g = 0.5 - np.sin(rad) / 2
b = 0.5 + np.sin(rad) / 2

# Return RGBA numpy array
return np.array([r, g, b, 1.0])


def main(filename: str = "pose_demo"):

# initial values for frame rate and total time
frame_rate = 60
total_time = 5

# clear all mesh objects
# calculates total number of frames in the visualization
total_frames = frame_rate * total_time

# clears all mesh objects
bsr.clear_mesh_objects()

# Task 1
# create a pose, i.e. position and director, using Pose class
# start circling around (CCW) the origin on a unit circle trajectory
# the moving direction is the tangent of the circle, which should be d2
# the z axis should be d3, and d1 = d2 cross d3
# the pose should be updated every frame, and will go around a circle with period 1 second
# initializes pose instance
pose_object = Pose(
positions=np.array([1, 0, 0]),
directors=np.eye(3),
thickness_ratio=0.1,
)

# creates an array of angles from 0 to 360 degrees
angles = np.linspace(0, 360, total_frames)

# Set frame start
bsr.frame_manager.set_frame_start()

# iterates through each angle
for angle in angles:

# defines path of of motion for positions of pose object
positions = [np.cos(np.radians(angle)), np.sin(np.radians(angle)), 0.0]

# defines directors of pose object
d2 = [-np.sin(np.radians(angle)), np.cos(np.radians(angle)), 0.0]
d3 = [0, 0, 1]
d1 = np.cross(d2, d3)
directors = np.column_stack((d1, d2, d3))

# updates positions and directors of pose object at each keyframe
pose_object.update_states(
positions=np.array(positions),
directors=directors,
)

# converts angle to rgb color value at each frame
color = angle_to_color(angle)

# updates pose object's colors
pose_object.update_material(color=color)

# Task 2
# the color of the pose should change based on the angle
# use the angle_to_color function defined above to compute the color code
# the angle is in degrees, and the function returns a numpy array of RGBA values
# the color of the pose can be updated throught pose.update_material(color=...)
# sets and updates keyframes
pose_object.set_keyframe(bsr.frame_manager.frame_current)

# Set the final keyframe number
bsr.frame_manager.set_frame_end()
if bsr.frame_manager.frame_current == total_frames - 1:
# Set the final keyframe
bsr.frame_manager.set_frame_end()
else:
# updates frame
bsr.frame_manager.update()

# Set the frame rate
bsr.frame_manager.set_frame_rate(fps=frame_rate)

# Set the view distance
bsr.set_view_distance(distance=5)

# Deslect all objects
# Deselect all objects
bsr.deselect_all()

# Select the camera object
Expand Down
8 changes: 5 additions & 3 deletions src/bsr/geometry/primitives/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def update_material(self, **kwargs: dict[str, Any]) -> None:
assert np.all(color >= 0) and np.all(
color <= 1
), "Keyword argument color should be in the range of [0, 1]."
self._material.diffuse_color = tuple(color)
self.material.diffuse_color = tuple(color)

def _create_sphere(self) -> bpy.types.Object:
"""
Expand All @@ -215,6 +215,7 @@ def set_keyframe(self, keyframe: int) -> None:
keyframe : int
"""
self.object.keyframe_insert(data_path="location", frame=keyframe)
self.material.keyframe_insert(data_path="diffuse_color", frame=keyframe)


class Cylinder(KeyFrameControlMixin):
Expand All @@ -227,7 +228,7 @@ class Cylinder(KeyFrameControlMixin):
position_1 : NDArray
The first endpoint position of the cylinder object. (3D)
position_2 : NDArray
The second enspoint position of the cylinder object. (3D)
The second endpoint position of the cylinder object. (3D)
radius : float
The radius of the cylinder object.
"""
Expand Down Expand Up @@ -366,7 +367,7 @@ def update_material(self, **kwargs: dict[str, Any]) -> None:
assert np.all(color >= 0) and np.all(
color <= 1
), "Values of the keyword argument `color` should be in the range of [0, 1]."
self._material.diffuse_color = tuple(color)
self.material.diffuse_color = tuple(color)

def _create_cylinder(
self,
Expand All @@ -392,6 +393,7 @@ def set_keyframe(self, keyframe: int) -> None:
self.object.keyframe_insert(data_path="location", frame=keyframe)
self.object.keyframe_insert(data_path="rotation_euler", frame=keyframe)
self.object.keyframe_insert(data_path="scale", frame=keyframe)
self.material.keyframe_insert(data_path="diffuse_color", frame=keyframe)


# TODO: Will be implemented in the future
Expand Down

0 comments on commit 55ec38f

Please sign in to comment.