当前位置:网站首页>Audio and video development journey (63) - animation and rendering of Lottie source code analysis

Audio and video development journey (63) - animation and rendering of Lottie source code analysis

2022-06-23 04:34:00 Audio and video development journey

Catalog

  1. Animation and drawing process
  2. LayerView Trees
  3. ShapeLayer Analysis of
  4. Lottie Pros and cons and rLottie、PAG Introduction to
  5. Information
  6. Harvest

In the last article, we learned to analyze Lottie Of json The analysis part . This is the animation and rendering part of our analysis .

The focus of the analysis : How to organize multiple layers layer The relationship between , Control the drawing and animation of different layers .

One 、 Animation and drawing process

We go through the entrance API function (LottieDrawable#setComposition、LottieDrawable#playAnimation) To analyze .

1.1 LottieDrawable#setComposition technological process

public boolean setComposition(LottieComposition composition) {

    //......
    clearComposition();
    this.composition = composition;
    // Build layers layer compositionlayer It works a little bit first andoid View In the tree ViewGroup, It can contain other View and ViewGroup
    // complete CompositionLayer and ContentGroup The initialization   There are mainly two inside TransformKeyframeAnimation
    buildCompositionLayer();  
  
    // Trigger notifyUpdate, Then trigger Layer Of progress Recalculation and draw The callback ( Of course, the progress is 0, It will not trigger after various judgments composition Of drawlayer)
    animator.setComposition(composition);

    // Set the progress of the current animation 
    setProgress(animator.getAnimatedFraction());

   ......

   }

You can see setComposition The main call buildCompositionLayer and animator.setComposition To carry out CompositionLayer And others Layer(json Corresponding layers Field ) as well as ContentGroup、TransformKeyframeAnimation Equal initialization . Lottie Most used in animation Layer yes CompositionLayer、ShapeLayer as well as ImageLayer.

reflection : So what is ContentGroup、TransformKeyframeAnimation、 They and layer What is the relationship between ?( I will try to analyze and solve it later )

1.2 LottieDrawable#playAnimation technological process

   1. LottieDrawable.playAnimation
   2. LottieValueAnimator.playAnimation
   3. LottieValueAnimator.setFrame
   4. BaseLottieAnimator.notifyUpdate
   5. Then trigger the callback (LottieDrawable.progressUpdateListener)AnimatorUpdateListener.onAnimationUpdate
   6. CompositionLayer.setProgress --》 Calculate the current progress, Then set the progress of each layer in reverse order  BaseLayer.setProgress
       6.1(transform.setProgress(progress))TransformKeyframeAnimation.setProgress  Set the progress of matrix transformation ( The zoom 、 transparency 、 Displacement, etc. )--》 Need to focus on analysis 
       6.2  animations.get(i).setProgress(progress);  Traverse the settings for each animation Progress 
   7. BaseKeyframeAnimation.notifyListeners  Callback to listener 
   8. BaseLayer.onValueChanged (invalidateSelf()) Trigger page redrawing ,--》 namely LottieDrawable.draw(android.graphics.Canvas, android.graphics.Matrix)
   9. compositionLayer.draw(canvas, matrix, alpha)   namely  BaseLayer.draw --》 This is also a key method 
   10. drawLayer(canvas, matrix, alpha);  namely  BaseLayer.drawLayer This method is an abstract method , various layer Concrete realization 
         10.1  We use ImageLayer For example  ( The key analysis ) ImageLayer.drawLayer  First, through BaseKeyframeAnimation.getValue()  This uses the previous animation changes progress Value , Get the current... According to the differentiator Bitmap
         10.2  And then use canvas To draw , Complete the transformation of the picture 

LottieValueAnimator yes ValueAnimator Subclasses of , And implemented Choreographer.FrameCallback Interface . Through the progress transformation callback of attribute animation and VSYNC The signal doframe Callback to notify Layer Calculate the progress and value , And inform LottieDrawble To redraw , So as to achieve json in layers That is, all kinds of Layer Animation and drawing of layers .

But the concrete drawing still has Canvas To achieve , Can pass ImageLayer Of drawLayer

public void drawLayer(@NonNull Canvas canvas, Matrix parentMatrix, int parentAlpha) {
    Bitmap bitmap = getBitmap();
    if (bitmap == null || bitmap.isRecycled()) {
      return;
    }
    float density = Utils.dpScale();

    paint.setAlpha(parentAlpha);
    if (colorFilterAnimation != null) {
      paint.setColorFilter(colorFilterAnimation.getValue());
    }
    // Save the current state of the canvas 
    canvas.save();
    // Yes matrix Apply the transformation to canvas All objects on 
    canvas.concat(parentMatrix);
    //src Used to set to draw bitmap Region , That is, whether to cut 
    src.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
    //dst It's used to set up canvas The display area on the canvas . Here you can see that the width and height of the display will be scaled according to the pixel density 
    dst.set(0, 0, (int) (bitmap.getWidth() * density), (int) (bitmap.getHeight() * density));
    // first Rect(src)  Represents the... To be drawn bitmap  Area , You can cut the picture , If it's empty null The whole picture is displayed . the second  Rect(dst)  It's pictures in Canvas The area displayed in the canvas , That is to say bitmap  Draw somewhere on the screen 
   //  Through dynamic change dst, Can achieve   Move 、 Zoom and so on , And scaling according to the pixel density of the screen , By changing src  Handle the drawn pictures , It can also achieve many interesting effects , such as   Show part of , Or gradually expand 
    canvas.drawBitmap(bitmap, src, dst, paint);
    // Restore previously saved canvas state , and sava One-to-one correspondence 
    canvas.restore();
  }

as for ShapeLayer and CompositionLayer It's a little complicated , Now we will analyze it separately .

reflection : If there are multiple layers , How to ensure the association between multiple layers ( It's like ViewTree equally , How to manage the relationship between them and the order of drawing ).

Two 、LayerView Trees

Lottie There are all kinds of Layer:

So what is the relationship between them ? How to manage and control hierarchies ?

CompositionLayer Construction

  public CompositionLayer(LottieDrawable lottieDrawable, Layer layerModel, List<Layer> layerModels,
      LottieComposition composition) {

   // Mainly TransformKeyframeAnimation The initialization 
    super(lottieDrawable, layerModel);
LongSparseArray<BaseLayer> layerMap =
        new LongSparseArray<>(composition.getLayers().size());

    BaseLayer mattedLayer = null;
    // according to layers size , Produce each in reverse order Layer
    for (int i = layerModels.size() - 1; i >= 0; i--) {
      Layer lm = layerModels.get(i);
      // This is an engineering method , according to layerType The structure corresponds to Layer
      BaseLayer layer = BaseLayer.forModel(this, lm,   lottieDrawable, composition);
      if (layer == null) {
        continue;
      }
      layerMap.put(layer.getLayerModel().getId(), layer);
      ......
     }

    
    for (int i = 0; i < layerMap.size(); i++) {
      long key = layerMap.keyAt(i);
      BaseLayer layerView = layerMap.get(key);
      if (layerView == null) {
        continue;
      }
     //  determine layer Father son relationship between 
      BaseLayer parentLayer =   layerMap.get(layerView.getLayerModel().getParentId());
      if (parentLayer != null) {
        layerView.setParentLayer(parentLayer);
      }
    }

}

Factory method :BaseLayer#forModel

static BaseLayer forModel(
      CompositionLayer compositionLayer, Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
    // Corresponding json in  object->layers->ty
    switch (layerModel.getLayerType()) {
        // outline / Form layer    This is the second one lottie The types used in animation are basically the most 
      case SHAPE:
        return new ShapeLayer(drawable, layerModel, compositionLayer);
        // Composite layer , amount to ViewTree Of ViewGroup Role 
      case PRE_COMP:
        return new CompositionLayer(drawable, layerModel,
            composition.getPrecomps(layerModel.getRefId()), composition);
        // Fill the layer 
      case SOLID:
        return new SolidLayer(drawable, layerModel);
        // Picture layers    This is also very common , Especially when making some template effects 
      case IMAGE:
        return new ImageLayer(drawable, layerModel);
        // Empty layer , Can be used for other layers parent
      case NULL:
        return new NullLayer(drawable, layerModel);
        // Text layer 
      case TEXT:
        return new TextLayer(drawable, layerModel);
      case UNKNOWN:
      default:
        // Do nothing
        Logger.warning("Unknown layer type " + layerModel.getLayerType());
        return null;
    }
  }

We see above layerView.setParentLayer(parentLayer); So this ParentLayer What's the use ? It is mainly used to determine the boundary of each layer and draw

 // BaseLayer#buildParentLayerListIfNeeded
 // This method determines the current layer boundary getBounds And call when drawing this layer draw
  private void buildParentLayerListIfNeeded() {
    if (parentLayers != null) {
      return;
    }
    // If the layer has a parent layer , Innovation 
    if (parentLayer == null) {
      parentLayers = Collections.emptyList();
      return;
    }

    // Of this layer LayerViewTree
    parentLayers = new ArrayList<>();
    BaseLayer layer = parentLayer;
    // Recursively find the parent layer of this layer 、 Grandfather layer 、 Great ancestor layer and so on 
    while (layer != null) {
      parentLayers.add(layer);
      layer = layer.parentLayer;
    }
  }

BaseLayer#getBounds

 public void getBounds(
      RectF outBounds, Matrix parentMatrix, boolean applyParents) {
    rect.set(0, 0, 0, 0);
    // Determine the layer LayerViewTree:parentLayers
    buildParentLayerListIfNeeded();
    // Matrix transformation of sublayer , Based on the matrix transformation of the parent layer 
    boundsMatrix.set(parentMatrix);

    if (applyParents) {
      // Recursively call the parent layer amount matrix transformation , Do matrix multiplication 
      if (parentLayers != null) {
        for (int i = parentLayers.size() - 1; i >= 0; i--) {
          boundsMatrix.preConcat(parentLayers.get(i).transform.getMatrix());
        }
      } else if (parentLayer != null) {
        boundsMatrix.preConcat(parentLayer.transform.getMatrix());
      }
    }

    // Finally, multiply by the matrix transformation of the current layer , To determine the final boundary matrix 
    boundsMatrix.preConcat(transform.getMatrix());
  }

BaseLayer#draw and BaseLayer#getBounds The same matrix treatment .

adopt parentid Establish the layer LayerViewTree, Re measure and draw according to LayerView Determine your own bound and draw.

3、 ... and 、ShapeLayer Analysis of

The reason why ShapeLayer Take it out alone and say , It's because he's in lottie It is very important in animation , adopt ShapeLayer It's a vector graph, not bitmap To draw a subclass of layers . Specify attributes such as color and lineweight , use Path To define the figure to be drawn .

public class ShapeLayer extends BaseLayer {
  ......
  
 // This ContentGroup What is it ? You can see ShapeLayer Of drawLayer and getBound It's all through contentGroup Acting .
  private final ContentGroup contentGroup;
  

  ShapeLayer(LottieDrawable lottieDrawable, Layer layerModel, CompositionLayer compositionLayer) {
    ......
    //ContentGroup structure 
    contentGroup = new ContentGroup(lottieDrawable, this, shapeGroup);
    contentGroup.setContents(Collections.<Content>emptyList(), Collections.<Content>emptyList());
  }

  @Override void drawLayer(@NonNull Canvas canvas, Matrix parentMatrix, int parentAlpha) {
    // Called contentGroup Of draw
    contentGroup.draw(canvas, parentMatrix, parentAlpha);
  }

  @Override public void getBounds(RectF outBounds, Matrix parentMatrix, boolean applyParents) {
    ......
    contentGroup.getBounds(outBounds, boundsMatrix, applyParents);
  }
  ......
}

ContentGroup What is it ? You can see ShapeLayer Of drawLayer and getBound It's all through contentGroup Acting . Let's take a look at ContentGroup Of draw The implementation of the

public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha){

    // Traversal call content, If it is DrawingContent Is to draw, What is... Over there DrawingContent Na 
    for (int i = contents.size() - 1; i >= 0; i--) {
      Object content = contents.get(i);
      if (content instanceof DrawingContent) {
        ((DrawingContent) content).draw(canvas, matrix, childAlpha);
      }
    }

}

Traversal call content, If it is DrawingContent Is to draw, Which? content yes DrawingContent Na ?

We use FillContent For example , Let's see draw The implementation of the

public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha) {
    ......
    // Get the color   Transparency, etc.   Set brush paint The color of the 
    int color = ((ColorKeyframeAnimation) this.colorAnimation).getIntValue();
    int alpha = (int) ((parentAlpha / 255f * opacityAnimation.getValue() / 100f) * 255);
    paint.setColor((clamp(alpha, 0, 255) << 24) | (color & 0xFFFFFF));

    // Set up colorFilter
    if (colorFilterAnimation != null) {
      paint.setColorFilter(colorFilterAnimation.getValue());
    }

    ......
    // Set up path route 
    path.reset();
    for (int i = 0; i < paths.size(); i++) {
      path.addPath(paths.get(i).getPath(), parentMatrix);
    }

    // use cavas drawpath
    canvas.drawPath(path, paint);

  }

Sure ShapeContent Of DrawingContent through Canvas To carry out draw Of .

Lottie That's all for the animation and rendering analysis of , About BaseKeyframeAnimation The main implementation Layer and DrawingContent Interpolation calculation of animation in , No detailed analysis , If you need to see it again .

reflection : Can we pass through OpenGL ES To render ?

5、 ... and 、Lottie Pros and cons and PAG Simple comparison of

Lottie The advantages and disadvantages of

 advantage :
 Cross-platform support ( Although each end implements a set of )
 Good performance 
 It can be distributed through configuration “json And material ” updated .

 Shortcomings :
Lottie Interaction and editing are not supported 
Lottie Compressed bitmaps are not supported , If you use png Equal bitmap , Need to be on your own tiny And other compression platforms for image compression 、 Reduce package volume .
Lottie There is mask、matters  when , It needs to be done first saveLayer, Call again drawLayer return .
saveLayer It's a time-consuming operation , It needs to be allocated first 、 Draw a offscreen The buffer , This increases the rendering time 

PAG The advantages and disadvantages of

PAG It is an animation component that Tencent just opened source yesterday , except lottie The advantages of ,
  Support more AE Special effects ,
  Support text and sequence frames ,
  Support template editing ,
  Use secondary value files instead of json, File size and parsing performance will be better 
  Rendering level :Lottie The implementation of the rendering layer depends on the platform side interface , Different platforms may vary .PAG Render layers use C++ Realization , All platforms share the same set of implementations , The platform side simply encapsulates interface calls , Provide rendering environment , The rendering effect is consistent .


PAG Deficiency , Rendering is based on google Open source skia 2d To achieve . Increased package size .4.0 The version of will be improved , Get rid of skia 2d. Realize simple rendering encapsulation by yourself ( I guess so opengl perhaps metal 、vulkan).

rlottie Brief introduction

[Samsung-rlottie](https://github.com/Samsung/rlottie)

rLottie  And  lottie  Workflow consistency , stay  SDK  The implementation is different ,rLottie  No platform specific implementation is used , It's unity  C++ Realization , Material support  lottie  Of  json  file , Vector rendering performance is good , But lack of platform encapsulation , Supported by  AE  Incomplete characteristics , Also does not support text 、 Sequence frame, etc 

 This has not yet analyzed its source code implementation . Take time to analyze and learn .

6、 ... and 、 Information

  1. Lottie Implementation of ideas and source code analysis
  2. Lottie Analysis of animation principle
  3. reveal Lottie Advantages, disadvantages and principles of animation
  4. lottie-android Framework use and source code analysis
  5. Lottie Animation library Android End source code analysis
  6. Tencent open source PAG
  7. Samsung-rlottie
  8. Compare from the decoding and rendering level PAG And lottie

7、 ... and 、 Harvest

Through the study and analysis of this article

  1. Combed lottie Animation and rendering process
  2. LayerView The concept and understanding of tree , Make clear lottie How to manage differences layer The relationship between
  3. It focuses on CompositionLayer、BaseLayer、ImageLayer and ShapeLayer, among ShapeLayer Contain, ContentGroup
  4. A simple comparison lottie、PAG、rlottie

Thanks for reading Welcome to the official account “ The journey of audio and video development ”, Learn and grow together . Welcome to exchange

原网站

版权声明
本文为[Audio and video development journey]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/01/202201161142309760.html