Play animation but preserve style settings?

I wanted to animate my klein bagel to spin around.

I’ve written this script to create a series of scenes to accomplish this in a reasonably smooth playing way. However, as soon as I click on the first scene to play the animation, the style changes back to the default and the original style cannot be recovered.

How to resolve this so I can preserve the original style settings when playing an anim?

Here is my script so far

class FooRotation
  
  def self.capture_render_opts(model)
    render_options = model.rendering_options
    local_ops = Hash.new
    
    render_options.each { |key,val|
      print("key: #{key}, val: #{val}")
      local_ops[key] = val
    }
    return local_ops
  end
  
  def self.clear_scenes(model)
    scenes = model.pages
    
    scenes.to_a.each do |scene|
      scenes.erase(scene)
    end
  end
  
  def self.create_scenes(model, view, num_scenes, orbit_radius, orbit_height, orbit_speed)
    (0..num_scenes-1).each do |i|
      # compute camera position 
      angle_degrees = i * orbit_speed
      angle_radians = angle_degrees.degrees
      x = orbit_radius * Math.cos(angle_radians)
      y = orbit_radius * Math.sin(angle_radians)
      camera_position = [x,y,orbit_height]
      target_position = [0,0,0]
      
      # set camera position and target
      camera = view.camera
      camera.perspective = true
      camera.set(camera_position, target_position, [0,0,1])
      
      # create a new scene and update it
      scene = model.pages.add("Scene #{i+1}")
      scene.use_camera = true
      scene.transition_time = 0.2
      
      view.refresh
      
      sleep(1)
    end
  end # method create_scenes
end # end class FooRotation

# these are all the render options of the desired look of the model
# render option: BackgroundColor: Color(255, 255, 255, 255)
# render option: BandColor: Color(  0,   0,   0, 127)
# render option: ConstructionColor: Color(  0,   0,   0, 255)
# render option: DepthQueWidth: 4
# render option: DisplayColorByLayer: false
# render option: DisplayDims: true
# render option: DisplayFog: false
# render option: DisplayInstanceAxes: false
# render option: DisplaySectionCuts: true
# render option: DisplaySectionPlanes: false
# render option: DisplaySketchAxes: false
# render option: DisplayText: true
# render option: DisplayWatermarks: true
# render option: DrawBackEdges: false
# render option: DrawDepthQue: false
# render option: DrawGround: false
# render option: DrawHidden: false
# render option: DrawHorizon: true
# render option: DrawLineEnds: false
# render option: DrawProfilesOnly: false
# render option: DrawSilhouettes: false
# render option: DrawUnderground: true
# render option: EdgeColorMode: 0
# render option: EdgeDisplayMode: 0
# render option: EdgeType: 0
# render option: ExtendLines: false
# render option: FaceBackColor: Color(164, 178, 187, 255)
# render option: FaceColorMode: 0
# render option: FaceFrontColor: Color(255, 255, 255, 255)
# render option: FogColor: Color(255, 255, 255, 255)
# render option: FogEndDist: -1.0
# render option: FogStartDist: -1.0
# render option: FogUseBkColor: true
# render option: ForegroundColor: Color(  0,   0,   0, 255)
# render option: GroundColor: Color(255, 255, 255, 255)
# render option: GroundTransparency: 23
# render option: HideConstructionGeometry: false
# render option: HighlightColor: Color(  0,   1, 255, 255)
# render option: HorizonColor: Color(  0,   0,   0,   0)
# render option: InactiveFade: 0.25
# render option: InactiveHidden: false
# render option: InstanceFade: 0.5
# render option: InstanceHidden: false
# render option: JitterEdges: false
# render option: LineEndWidth: 9
# render option: LineExtension: 3
# render option: LockedColor: Color(255,   0,   0, 255)
# render option: MaterialTransparency: true
# render option: ModelTransparency: false
# render option: RenderMode: 2
# render option: SectionActiveColor: Color(255, 135,   0, 255)
# render option: SectionCutDrawEdges: true
# render option: SectionCutWidth: 3
# render option: SectionDefaultCutColor: Color(  0,   0,   0, 255)
# render option: SectionInactiveColor: Color(112, 105,  97, 255)
# render option: ShowViewName: true
# render option: SilhouetteWidth: 2
# render option: SkyColor: Color(255, 255, 255, 255)
# render option: Texture: true
# render option: TransparencySort: 0

model = Sketchup.active_model
view = model.active_view

model.start_operation('capture_render_opts', true)
  print("capture render opts")

  local_ops = FooRotation.capture_render_opts(model)

model.commit_operation

model.start_operation('erase_previous_scenes', true)
  print("clear scenes")

  FooRotation.clear_scenes(model)

model.commit_operation

model.start_operation('create_scenes', true)

  print("create scenes")

  num_scenes = 180
  orbit_radius = 1200.0
  orbit_height = 180.0
  orbit_speed = 360.0 / num_scenes
  
  FooRotation.create_scenes(model, view, num_scenes, orbit_radius, orbit_height, orbit_speed)
  
model.commit_operation

Thank you for any thoughts
-j_jones

Messing with scenes is the hard way and when you animate between camera positions the path is a direct line between the eye positions. This causes camera surging toward and away from the target.

Instead of scenes, use the API’s abstract Animation class.

Then your choice is to rotate the camera around the target or rotate the target itself whilst the camera is stationary. (The latter will cause the model’s modified flag to be set true.)

The following example shows how to set up a rotational transformation and apply it to the camera:

You could just as easily apply the transform to the model object (but again, this modifies the model, which may require you to call Sketchup.undo afterward.)

1 Like

Wondering why someone would create a throw-away account just to respond to this question?

Thank you, I feel like I read the solution to the problem somewhere either here or on sketchucation but for the life of me can’t find it. There seems to be no way to preserve style settings programatically or otherwise for animating scenes. And yet I must have found a way to do it as clearly the background is non-default in these two examples:

.

I will add that I didn’t have any problem with surging camera, that the animation is nice and smooth really, though maybe with a tiny bit of jitter if you look closely

I will explore the Animation class. Though I didn’t really want to export frames and employ external software to do it. I just wanted to animate it on screen and capture the motion with GIPHY Capture as I did in the above two examples.

Thank you
-j_jones

p.s. seems like the forum editor is having some issues today, not sure why those links to the warehouse are rendering that way

The Animation class does not require that your code do either. My example does write image files of the viewport, but ignore this. Concentrate upon applying a transformation to the camera position whilst keeping the same camera target.

In fact, the API documentation’s example just shows moving the camera up a certain distance.

Yes this is what the class is for. You also avoid any changing style / rendering issues or modifying the geometry.

Off-topic: What does this refer to ?

1 Like

Imagine that you only have 4 scenes with the camera at N, W, S, and E. Switching to a top-down view and drawing the path between the camera eye points, you should be able to see that the camera will be closer to the geometry at NE, SE, SW and NW positions along the path. So, using the native animation feature as the camera moves around the model the subject will grow a bit larger 4 times throughout a single “spin”.

The more scenes the smaller and less noticeable the surging if the distance to the target remains the same. But creating hundreds of scenes just to have a smooth “spin” animation is inefficient and bloats the model.

The real issue is that the native scene animation feature is “hard-wired” to interpolate between the “from” scene’s and “to” scene’s style / rendering settings as well as the camera properties (eye, target & up.) (In addition, if any of the scenes are set to save section planes, the native animation will interpolate between the “from” scene’s active section and the “to” scene’s active section. This can be used to show moving sections.)

If all the animation scenes used the same style object we would not notice any rendering differences.

The correct solution for your case is to avoid native scene animation as it is not the correct solution.


There is a way to preserve and set styles via the rendering options, but it is unintuitive. I recently explained it here in this category.

ADD: We recently discussed changing style settings and creating a new style here:
How can update rendering_options of page? - #11 by DanRathbun

1 Like

I will need some time to absorb all this info, thank you!

The off-topic response was to a community moderated post by someone calling themselves ‘Alexmarfi’. Their details were just nonsense words. They had created the account earlier today and had a grand total of 1 view and 1 interaction which was with my post, evidently in a way that caused it to be hidden by the moderators.

I don’t know why anyone would do that. I don’t usually have troubles with people doing that sort of thing. I can’t see what about my original post would have inspired it. That’s all I meant by that.

1 Like

Oh okay. Probably a spambot just attempting to post the minimum to gain access rights for later spamming.

1 Like

This is embarassing :roll_eyes:, but preserving the style was just a matter of saving it with a particular name in the Styles editor.

After that, the style was preserved during animation playback.

1 Like

I think you might not have saved the initial style settings. Let’s create a style you want to display when playing the animation and select it before running the Ruby script to create the series of scenes.

By the way, if it’s just about spinning the camera, you might try this plugin: Curic Spin Camera | SketchUp Extension Warehouse

1 Like

Ok, here’s an example of pure sketchup animation captured with Giphy. I think Giphy ran out of patience, so there’s a jump at the end. It’s also very jittery, so I do want to learn better ways to achieve these things. I’ll be exploring all the info in this thread.

Thank you!
-j_jones

Is there a tutorial or good examples for using the Animation api class? I’m having a bit of trouble finding anything. This is a whole aspect of Sketchup programming that is new to me, including manipulating the camera, eye, etc…

Thanks for any info
-j_jones

I do not know of any (or I would have posted links in my Ruby Resources lists.)

The Animation class overview itself has a simple example.

Did you search this forum category?

The Camera class introduction has a snippet showing setting the view to a new camera.

But you would most likely use Camera#set to change the model.active_view camera “on the fly”.


This exercise is not very difficult at all. The camera’s up vector and target are likely to remain the same.

It is only the camera eye position that will change. Changing it is dead simple using a rotational transformation.
(Ie, a Geom::Point3d object can be transformed via Geom::Point3d#transform!.)

First you write an outline of the steps (called pseudocode,) breaking the challenge down into small chunks. Then solve each chunk. Often each chunk will become a method (aka a function.)

What is it specifically that has you stumped ?

1 Like

I did search the forums and also github looking for ideas. I finally gave in and asked chat-gpt for some help. I was able to piece this script together out of what it gave me.

class FooSinusoidalCameraAnimation
  
  def initialize(duration, radius, rotation_modifier, height_angle_modifier, distance_modifier)
    print("init: duration: #{duration}, radius: #{radius}, rotation_modifier: #{rotation_modifier}, height_angle_modifier: #{height_angle_modifier}, distance_modifier: #{distance_modifier}")
    @duration = duration # duration of animation in seconds
    @radius = radius # distance from origin
    @rotation_modifier = rotation_modifier
    @height_angle_modifier = height_angle_modifier
    @distance_modifier = distance_modifier
    @start_time = Time.now.to_f # was nil
    @camera = Sketchup.active_model.active_view.camera
    @eye = @camera.eye
    @target = [0,0,51] # ORIGIN
    @up = @camera.up
  end
    
  def nextFrame(view)
    elapsed_time = Time.now.to_f - @start_time
    if elapsed_time > @duration
      print("done animating")
      return false 
    end
    
    # calculate angle for frame
    angle_degrees = (elapsed_time / @duration) * (360.0 / @rotation_modifier)
    angle = angle_degrees.degrees
    
    twoPi = 2 * Math::PI

    height = Math.sin((elapsed_time / @duration) * twoPi * @height_angle_modifier) * @radius * @distance_modifier

    eye_x = @radius * Math.cos(angle)
    eye_y = @radius * Math.sin(angle)
    eye_z = height # * Math.sin(angle)

    new_eye = Geom::Point3d.new(eye_x, eye_y, eye_z)

    # update camera and look at origin
    @camera.set(new_eye, @target, @up)

    #view.show_frame
    #view.invalidate

    return true
  end # nextFrame
end

# affects how fast it goes around: smaller is faster, larger is slower but jittery!
rotation_modifier = 0.75 # 5.0 # 1.0 # 3.0 # 3.0 # 1.5 #3.0 slower but more jittery # 0.5 #faster
    
height_angle_modifier = 2.0 # height angle?
#0.5 # height swings more slowly
#5.0 # height swings back and forth like a swingset almost
# 1.0 # 0.5 # 1.0 #5 # 10000 #0.000001 # 100.0 # 0.2
distance_modifier = 3.0 # 0.1 
#10.0 radius flies out of sight quickly then returns repeat
# 3.0 flies away, does a jittery arabesque then returns 
#0.0001 # no effect!  
# 5.0 #flies far away then zooms back in 
# 0.5 # 1.0

duration = 30
radius = 150

def start_sinusoidal_camera_animation
  animation = FooSinusoidalCameraAnimation.new(duration, radius, rotation_modifier, 
    height_angle_modifier, distance_modifier)
  Sketchup.active_model.active_view.animation = animation
end

unless file_loaded?(__FILE__)
  UI.menu("Extensions").add_item("Start Sinusoidal Camera Animation") {
    print("starting the animation!")
    start_sinusoidal_camera_animation
  }
  file_loaded(__FILE__)
end

#animation = SinusoidalCameraAnimation.new(duration, radius, rotation_modifier, 
#  height_angle_modifier, distance_modifier)
#Sketchup.active_model.active_view.animation = animation

I would post a link to the skp file in 3dwarehouse, but those links don’t seem to work anymore…

thank you for all the clues!
-j_jones

CORRECTION: The camera’s up vector also needs to be transformed by the same transform as the eye point for each frame.

1 Like

I will contemplate this advice as it hasn’t all sunk in yet

Thank you
-j_jones

Did you learn basically how an animation object is done by having an AI bot do the groundwork?

It works as desired with view.show_frame commented out ?

And lastly, do you understand now how only the camera positioning is changing and has no effect upon the current style in use?


The only critique I’ll give the result is that the bots as usual do not write code for a shared Ruby ObjectSpace. Ie, all the code should be within an extension submodule of your unique top-level namespace module.

1 Like

I gave the class a weird name, but I’ll make a point to put things in a unique namespace module.

I will need to play around with this stuff more before I grok all the points you made.

-j_jones

The correction and previous comments are directed toward a simpler circling animation around a target at the same camera elevation.

Your result is more complex sinusoidal camera path which was not previously mentioned as desired. (It gives an interesting look at such a 3D piece of artwork as you’ve used for the target.)

The camera’s up vector must be perpendicular to the camera’s directional vector (indicated as a vector pointing between the camera eye point and the camera target point.) The camera can be rolled to one side or the other by adjusting the up vector. This “up” does not refer to the model environment, but to a vector controlling roll of the camera. Ie, if you were holding a physical camera in your hands, the up vector would be pointing from the center of the eyepoint “up” toward the top of the camera body.

1 Like

Yes, I did intend just a simple rotation at first, but then I went a little nuts with it.

Ok, I think I understood that. I will try adding that and see how it goes

-j_jones

1 Like