Skip to content

Commit

Permalink
Merge branch 'main' into feat/documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
hanson-hschang committed Nov 6, 2024
2 parents fd0c892 + afdd564 commit 5fde6d4
Show file tree
Hide file tree
Showing 21 changed files with 275 additions and 185 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# image files
# rendered files
*.png
*.mov

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
6 changes: 3 additions & 3 deletions examples/br2/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ def update_states(
)

def set_keyframe(self, keyframe: int) -> None:
self.bending_actuation.set_keyframe(keyframe)
self.rotation_CW_actuation.set_keyframe(keyframe)
self.rotation_CCW_actuation.set_keyframe(keyframe)
self.bending_actuation.update_keyframe(keyframe)
self.rotation_CW_actuation.update_keyframe(keyframe)
self.rotation_CCW_actuation.update_keyframe(keyframe)


class BlenderBR2CallBack(BasicCallBackBaseClass):
Expand Down
54 changes: 26 additions & 28 deletions examples/camera_movement.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,40 @@ def main(
camera_orbiting_radius: float = 1.0,
):

# Create a new scene
# Clear all mesh objects in the new scene
bsr.clear_mesh_objects()

# Set the camera film background to transparent
bsr.camera.set_film_transparent()

# Set the render file path
bsr.camera.set_file_path(filename + "/frame")

# Set resolution
bsr.camera.set_resolution(1920, 1080)

# Set the camera look at location
bsr.camera.look_at = np.array([0.0, 0.0, 0.0])

# Set a frame at the origin
# Set a pose at the origin
_ = Pose(
positions=np.zeros(3),
directors=np.identity(3),
unit_length=0.25,
)

# Set the current frame number
bsr.frame_manager.frame_current = 0

# Set the initial keyframe number
bsr.frame_manager.set_frame_start()

# Set the camera orbiting keyframes
# Set the camera orbiting angles
angles = np.linspace(
0.0, 360.0, int(frame_rate * total_time), endpoint=False
)
for k, angle in enumerate(angles):

# Set the initial frame
frame_start = 0
bsr.frame_manager.frame_start = frame_start

for frame_current, angle in bsr.frame_manager.enumerate(
angles, frame_current_init=frame_start
):

# Set the camera location
bsr.camera.location = np.array(
Expand All @@ -49,35 +56,22 @@ def main(
]
)

# Update the keyframe
bsr.camera.set_keyframe(bsr.frame_manager.frame_current)

if k != len(angles) - 1:
# Update the keyframe number
bsr.frame_manager.update()
else:
# Set the final keyframe number
bsr.frame_manager.set_frame_end()
# Set and update the camera in current frame
bsr.camera.update_keyframe(frame_current)

# Set the frame rate
bsr.frame_manager.set_frame_rate(fps=frame_rate)
bsr.frame_manager.frame_rate = 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
bsr.camera.select()

# Set the render file path
bsr.camera.set_file_path("render/" + filename)

# set resolution
bsr.camera.set_resolution(1920, 1080)

# render the scene
# Render the scene
bsr.camera.render(
frames=np.arange(
bsr.frame_manager.frame_start, bsr.frame_manager.frame_end + 1
Expand All @@ -90,3 +84,7 @@ def main(

if __name__ == "__main__":
main()
print("\n\nTo convert the frames into a video, run the following command:")
print(
r"ffmpeg -threads 8 -r 60 -i camera_movement/frame_%03d.png -b:v 90M -c:v prores -pix_fmt yuva444p10le camera_movement.mov"
)
File renamed without changes.
120 changes: 70 additions & 50 deletions examples/pose_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,107 @@


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_demo5"):

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

# calculates total number of frames in the visualization
total_frames = frame_rate * total_time

# clears all mesh objects
def main(
filename: str = "pose_demo",
frame_rate: int = 60,
total_time: float = 5.0,
):
# Clear all mesh objects in the new scene
bsr.clear_mesh_objects()
bsr.frame_manager.set_frame_start()

# intializes pose instance and angle
pose_object = Pose(
positions=np.array([1, 0, 0]), directors=np.eye(3), thickness_ratio=0.1
# Initialize pose instance
pose = Pose(
positions=np.array([1, 0, 0]),
directors=np.eye(3),
thickness_ratio=0.1,
)

# Create an array of angles from 0 to 360 degrees
angles = np.linspace(
0.0, 360.0, int(frame_rate * total_time), endpoint=False
)
theta = 0

# iterates through each frame in total time duration
for frame in range(total_frames):
theta = 2 * np.pi * frame / total_frames
# Set the initial frame
frame_start = 0
bsr.frame_manager.frame_start = frame_start

# defines path of of motion for positions of pose object
new_positions = np.array([np.cos(theta), np.sin(theta), 0])
pose_object.positions = new_positions
for frame_current, angle in bsr.frame_manager.enumerate(
angles, frame_current_init=frame_start
):
# Define 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.array([-np.sin(theta), np.cos(theta), 0])
d3 = np.array([0, 0, 1])
# Define 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)
new_directors = np.column_stack((d1, d2, d3))
pose_object.directors = new_directors

# updates positions and directors of pose object at each keyframe
pose_object.update_states(new_positions, new_directors)
directors = np.column_stack((d1, d2, d3))

# converts angle to rgb color value at each frame
color = angle_to_color(np.degrees(theta))
# Update positions and directors of pose object at each keyframe
pose.update_states(
positions=np.array(positions),
directors=directors,
)

# updates pose object's colors
pose_object.update_material(color=color)
# Convert angle to rgb color value at each frame
color = angle_to_color(angle)

# sets and updates keyframes
pose_object.set_keyframe(frame)
bsr.frame_manager.update()
# Update pose object's colors
pose.update_material(color=color)

# Set the final keyframe number
bsr.frame_manager.set_frame_end()
# Set and update the pose in current frame
pose.update_keyframe(frame_current)

# Set the frame rate
bsr.frame_manager.set_frame_rate(fps=frame_rate)
bsr.frame_manager.frame_rate = 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
2 changes: 1 addition & 1 deletion examples/single_rigid_rod_spring_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def analytical_solution(t, y0: float, v0: float):
# update the rod
keyframe = int(time_index / simulation_ratio) + 1
rod.update_states(positions=positions, radii=radii)
rod.set_keyframe(keyframe)
rod.update_keyframe(keyframe)

bsr.save("single_rigid_rod_spring_action.blend")

Expand Down
19 changes: 15 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/bsr/_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def select(self) -> None:
"""
bpy.context.view_layer.objects.active = self._camera

def set_keyframe(self, keyframe: int) -> None:
def update_keyframe(self, keyframe: int) -> None:
"""
Sets a keyframe at the given frame.
Expand Down
2 changes: 1 addition & 1 deletion src/bsr/_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def location(self, location: np.ndarray) -> None:
"""
self._light.location = location

def set_keyframe(self, keyframe: int) -> None:
def update_keyframe(self, keyframe: int) -> None:
"""
Sets a keyframe at the given frame.
Expand Down
Loading

0 comments on commit 5fde6d4

Please sign in to comment.