Keep constant number of visible circles in 3D anim

2020-08-25 08:23发布

问题:

I have created a 3D animation with a perspective projection of white circles moving randomly in a fake 3D space projected on a 2D computer screen (GIF 1).

Since I need to keep the same number of visible circles, every time a circle disappears from the frame, I have to create a new visible one within the frame. To do so, I have written this piece of code:

  • First I created initial coordinates and the two angles of movements (spherical coordinates):

    for circle in circles:
    
        circle.position.xy = np.random.uniform(-25, 25, size=2)
        z = np.random.uniform(near_z, far_z)
    
        circle.position.z = z
        circle.position.x *= z/-50
        circle.position.y *= z/-50
    
        circle.theta_deg = np.random.rand(1) * 360
        circle.phi_deg = np.random.rand(1) * 360
    
        theta_rad = circle.theta_deg * np.pi / 180
        phi_rad = circle.phi_deg* np.pi / 180
    
    
        circle.dx = speed * np.sin(-phi_rad - theta_rad) / frameRate
        circle.dy = -speed * np.cos(phi_rad + theta_rad) / frameRate
        circle.dz = -speed * np.cos(theta_rad) / frameRate
    
    • Then, in the loop that plays the animation, and updates the position of each circle, I have put this condition following the same answer that was provided to the same kind of issue here:

      max_dist = max(abs(circle.position.x),abs(circle.position.y))
      limit_dist = 25 * abs((circle.position.z-near_z) / far_z)
      
      z_rel = np.random.uniform(near_z,far_z)
      
      if max_dist > limit_dist: 
          circle.position.x = np.random.uniform(-25, 25) * z_rel/far_z
          circle.position.y = np.random.uniform(-25, 25) * z_rel/far_z
      

I got a weird result as shown in GIF 2

What is wrong with my condition and how can I detect a circle that disappears from the frame and recreate one inside the frame?

Following the suggestion of @Fabian N. (answer below), I have reset the z-coordinates along with the x and y coordinates as follows:

    max_dist   = max(abs(circle.position.x), abs(circle.position.y))        # Find maximum distance of a circle to the center of the view:
    limit_dist = 25 * abs((circle.position.z-near_z) / far_z)


    if circle.position.z <= near_z or max_dist > limit_dist:

        z_rel = np.random.uniform(near_z,far_z) 
        circle.position.z = z_rel + near_z

        circle.position.x = np.random.uniform(-25, 25) * z_rel/far_z
        circle.position.y = np.random.uniform(-25, 25) * z_rel/far_z

And I got this result:

回答1:

Based on the code you posted I can only see two points of interest without actually running it
(could you add some glue code around the code you posted to make it runnable as a standalone example?)

  1. You are only resetting the x and y position in the if condition, you need to reset z too, otherwise, they will fly behind the camera or vanish in the distance
  2. the if-condition from the question you linked has another part: sphere.position.z >= camera_z which would translate for your code into circle.position.z <= near_z to actually detect spheres flying behind the camera

Both can't really explain what's happening in your second gif...


On second thought: the jumping circles in gif 2 could just be circles that get instantly reset each frame because they aren't properly reset as their z-coordinate stays the same.



回答2:

In the code that you've added, you are resetting the z parameter differently than the way you initialized it.

In the first part of your code, you use

z = np.random.uniform(near_z, far_z)
circle.position.z = z
circle.position.x *= z/-50
circle.position.y *= z/-50

while in the for loop you use

z_rel = np.random.uniform(near_z,far_z)
circle.position.z = z_rel + near_z
circle.position.x = np.random.uniform(-25, 25) * z_rel/far_z
circle.position.y = np.random.uniform(-25, 25) * z_rel/far_z

These do not seem to be equivalent. Perhaps you should use the same parameters for both.

You should also check the way that you update your x and y positions, especially your parameters dx and dy, as these may be getting so big that your circles fly out of the screen immediately