-
-
Save DanielHabib/2b56dd6d351ef781b7d8b71af026d347 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import dgs | |
| import numpy as np | |
| def create_circular_orb( | |
| output_path="circular_orb.dgs", | |
| duration=5.0, | |
| radius=1.0, # Radius of circular path | |
| orb_radius=0.12, # Radius of the orb itself (smaller for tighter look) | |
| num_segments=400, # Even more segments for ultra-smooth motion | |
| gaussians_per_segment=800 # Way more gaussians for ultra-solid appearance | |
| ): | |
| """ | |
| Create an orb moving in a circular path using linear motion gaussians. | |
| Circular motion is simulated by creating/destroying gaussians along the path. | |
| """ | |
| rng = np.random.default_rng(42) | |
| print(f"Creating circular orb motion...") | |
| print(f"Circle radius: {radius}") | |
| print(f"Orb radius: {orb_radius}") | |
| print(f"Segments: {num_segments}") | |
| print(f"Duration: {duration}s") | |
| all_positions = [] | |
| all_colors = [] | |
| all_velocities = [] | |
| all_tMeans = [] | |
| all_tStdevs = [] | |
| # Time per segment | |
| time_per_segment = duration / num_segments | |
| for seg_idx in range(num_segments): | |
| # Current angle on the circle | |
| angle = (seg_idx / num_segments) * 2 * np.pi | |
| # Center position of orb at this segment | |
| center_x = np.cos(angle) * radius | |
| center_y = np.sin(angle) * radius | |
| center_z = 0.0 | |
| # Velocity tangent to the circle (perpendicular to radius) | |
| # Tangent vector at this point | |
| tangent_x = -np.sin(angle) | |
| tangent_y = np.cos(angle) | |
| # Speed needed to travel one segment in the time available | |
| # Distance between adjacent points on circle | |
| next_angle = ((seg_idx + 1) / num_segments) * 2 * np.pi | |
| next_x = np.cos(next_angle) * radius | |
| next_y = np.sin(next_angle) * radius | |
| # Distance to travel | |
| segment_distance = np.sqrt((next_x - center_x)**2 + (next_y - center_y)**2) | |
| speed = segment_distance / time_per_segment | |
| # Velocity vector | |
| vel_x = tangent_x * speed | |
| vel_y = tangent_y * speed | |
| vel_z = 0.0 | |
| # Time when this segment appears | |
| segment_time = seg_idx * time_per_segment | |
| # Create gaussians forming a solid sphere (the orb) | |
| # Use surface-concentrated distribution for sharper edges | |
| for _ in range(gaussians_per_segment): | |
| # Generate random direction | |
| theta = rng.random() * 2 * np.pi | |
| phi = np.arccos(2 * rng.random() - 1) | |
| # Surface-concentrated radius distribution | |
| # Use power of 5 instead of 1/3 to concentrate near surface | |
| r = rng.random() ** 0.2 # High power = more concentrated at surface | |
| # Convert to Cartesian coordinates | |
| x = r * np.sin(phi) * np.cos(theta) | |
| y = r * np.sin(phi) * np.sin(theta) | |
| z = r * np.cos(phi) | |
| # Scale to orb radius | |
| offset_x = x * orb_radius | |
| offset_y = y * orb_radius | |
| offset_z = z * orb_radius | |
| # Position relative to orb center | |
| pos_x = center_x + offset_x | |
| pos_y = center_y + offset_y | |
| pos_z = center_z + offset_z | |
| all_positions.append([pos_x, pos_y, pos_z]) | |
| all_velocities.append([vel_x, vel_y, vel_z]) | |
| # Solid colored orb with subtle depth-based shading | |
| hue = (seg_idx / num_segments) * 0.2 + 0.45 # Smooth color cycle | |
| base_color = np.array([ | |
| np.sin(2 * np.pi * hue) * 0.5 + 0.5, | |
| np.sin(2 * np.pi * (hue + 0.33)) * 0.5 + 0.5, | |
| np.sin(2 * np.pi * (hue + 0.66)) * 0.5 + 0.5, | |
| ]) | |
| # Subtle brightness variation - brighter at center, slightly dimmer at edges | |
| distance_from_center = np.sqrt(x*x + y*y + z*z) | |
| brightness = 0.9 + 0.2 * (1.0 - distance_from_center) | |
| color = base_color * brightness | |
| all_colors.append(color) | |
| # Temporal properties - appear during this segment | |
| # Normalized time (0 to 1) | |
| t_mean = segment_time / duration | |
| all_tMeans.append(t_mean) | |
| # Visible for exactly 1 segment for ultra-sharp transitions | |
| t_std = (time_per_segment * 1.0) / duration | |
| all_tStdevs.append(t_std) | |
| total = len(all_positions) | |
| print(f"Total gaussians: {total}") | |
| # Convert to numpy arrays | |
| means = np.array(all_positions, dtype=np.float32) | |
| colors = np.array(all_colors, dtype=np.float32) | |
| velocities = np.array(all_velocities, dtype=np.float32) | |
| # Initialize gaussian arrays | |
| scales = np.zeros((total, 3), np.float32) | |
| rotations = np.zeros((total, 4), np.float32) | |
| opacities = np.ones((total, 1), np.float32) | |
| harmonics = np.zeros((total, 1, 3), np.float32) | |
| tMeans = np.zeros((total, 1), np.float32) | |
| tStdevs = np.zeros((total, 1), np.float32) | |
| print("Setting gaussian properties...") | |
| for i in range(total): | |
| # Get position to calculate orientation | |
| pos = means[i] | |
| seg_idx = i // gaussians_per_segment | |
| angle = (seg_idx / num_segments) * 2 * np.pi | |
| center_x = np.cos(angle) * radius | |
| center_y = np.sin(angle) * radius | |
| # Vector from orb center to this gaussian | |
| dx = pos[0] - center_x | |
| dy = pos[1] - center_y | |
| dz = pos[2] - 0.0 | |
| dist = np.sqrt(dx*dx + dy*dy + dz*dz) | |
| # Ultra-thin ellipsoidal gaussians - paper-thin discs oriented radially | |
| # Make them extremely flat in the radial direction for razor-sharp edges | |
| base_scale = 0.012 | |
| scale_tangent = base_scale # Larger in tangential directions | |
| scale_radial = base_scale * 0.08 # ULTRA thin in radial direction (paper-thin disc) | |
| scales[i] = np.log([scale_tangent, scale_tangent, scale_radial]) | |
| # Calculate rotation to orient gaussian radially | |
| # Point the thin axis (z) toward the center | |
| if dist > 0.001: | |
| # Normalize direction vector | |
| dx /= dist | |
| dy /= dist | |
| dz /= dist | |
| # Create rotation quaternion to align z-axis with radial direction | |
| # Using vector-to-vector rotation | |
| # Default is (0,0,1), want to rotate to (dx,dy,dz) | |
| # Cross product for rotation axis | |
| cross_x = -dy | |
| cross_y = dx | |
| cross_z = 0.0 | |
| cross_len = np.sqrt(cross_x*cross_x + cross_y*cross_y + cross_z*cross_z) | |
| # Dot product for rotation angle | |
| dot = dz # dot product with (0,0,1) | |
| if cross_len > 0.001: | |
| # Normalize rotation axis | |
| cross_x /= cross_len | |
| cross_y /= cross_len | |
| cross_z /= cross_len | |
| # Quaternion from axis-angle | |
| angle_rot = np.arccos(np.clip(dot, -1.0, 1.0)) | |
| half_angle = angle_rot / 2.0 | |
| sin_half = np.sin(half_angle) | |
| qx = cross_x * sin_half | |
| qy = cross_y * sin_half | |
| qz = cross_z * sin_half | |
| qw = np.cos(half_angle) | |
| rotations[i] = [qx, qy, qz, qw] | |
| elif dot < 0: | |
| # 180 degree rotation | |
| rotations[i] = [1.0, 0.0, 0.0, 0.0] | |
| else: | |
| # No rotation needed | |
| rotations[i] = [0.0, 0.0, 0.0, 1.0] | |
| else: | |
| # At center, no specific orientation | |
| rotations[i] = [0.0, 0.0, 0.0, 1.0] | |
| # Set color | |
| color = colors[i] | |
| harmonics[i, 0] = (color - 0.5) / 0.28209479177387814 | |
| # Temporal properties | |
| tMeans[i] = all_tMeans[i] | |
| tStdevs[i] = all_tStdevs[i] | |
| # High opacity for solid appearance | |
| opacities[i] = 1.0 | |
| print("Creating gaussians...") | |
| # Create gaussians | |
| gaussians = dgs.Gaussians( | |
| means, | |
| scales, | |
| rotations, | |
| opacities, | |
| harmonics, | |
| velocities, | |
| tMeans, | |
| tStdevs, | |
| ) | |
| metadata = dgs.Metadata(duration=duration) | |
| dgs.encode(gaussians, metadata, output_path) | |
| print(f"\nWrote {output_path}") | |
| print(f"Duration: {duration}s") | |
| print(f"Total gaussians: {total}") | |
| print(f"Segments: {num_segments}") | |
| print(f"Average gaussians per segment: {total / num_segments:.0f}") | |
| if __name__ == "__main__": | |
| create_circular_orb( | |
| output_path="circular_orb.dgs", | |
| duration=5.0, | |
| radius=1.0, | |
| orb_radius=0.12, | |
| num_segments=400, | |
| gaussians_per_segment=800 | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment