Grass like smoothing animation on beziercurve?

后端 未结 5 1790
终归单人心
终归单人心 2020-12-09 06:47

This is what I am trying to achieve--GRASS Animation(Desired animation)

This is where the project is standing currently --My hair animation

This is a more st

5条回答
  •  青春惊慌失措
    2020-12-09 07:39

    Update: I'm currently adjusting the code to produce the requested result and commenting it.

    (function() { // The code is encapsulated in a self invoking function  to isolate the scope
      "use strict";
    
       // The following lines creates shortcuts to the constructors of the Box2D types used
       var B2Vec2 = Box2D.Common.Math.b2Vec2,
          B2BodyDef = Box2D.Dynamics.b2BodyDef,
          B2Body = Box2D.Dynamics.b2Body,
          B2FixtureDef = Box2D.Dynamics.b2FixtureDef,
          B2Fixture = Box2D.Dynamics.b2Fixture,
          B2World = Box2D.Dynamics.b2World,
          B2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
          B2RevoluteJoint = Box2D.Dynamics.Joints.b2RevoluteJoint,
          B2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef;
    
      // This makes sure that there is a method to request a callback to update the graphics for next frame
      window.requestAnimationFrame =
        window.requestAnimationFrame || // According to the standard
        window.mozRequestAnimationFrame || // For mozilla
        window.webkitRequestAnimationFrame || // For webkit
        window.msRequestAnimationFrame || // For ie
        function (f) { window.setTimeout(function () { f(Date.now()); }, 1000/60); }; // If everthing else fails
    
      var world = new B2World(new B2Vec2(0, -10), true), // Create a world with gravity
          physicalObjects = [], // Maintain a list of the simulated objects
          windInput = 0, // The input for the wind in the current frame
          wind = 0, // The current wind (smoothing the input values + randomness)
          STRAW_COUNT = 10, // Number of straws
          GRASS_RESET_SPEED = 2, // How quick should the straw reset to its target angle
          POWER_MOUSE_WIND = 120, // How much does the mouse affect the wind
          POWER_RANDOM_WIND = 180; // How much does the randomness affect the wind
    
      // GrassPart is a prototype for a piece of a straw. It has the following properties
      //  position: the position of the piece
      //  density: the density of the piece
      //  target: the target angle of the piece
      //  statik: a boolean stating if the piece is static (i.e. does not move)
      function GrassPart(position, density, target, statik) {
        this.width = 0.05;
        this.height = 0.5;
        this.target = target;
    
        // To create a physical body in Box2D you have to setup a body definition
        // and create at least one fixture.
        var bdef = new B2BodyDef(), fdef = new B2FixtureDef();
        // In this example we specify if the body is static or not (the grass roots 
        // has to be static to keep the straw in its position), and its original
        // position.
        bdef.type = statik? B2Body.b2_staticBody : B2Body.b2_dynamicBody;
        bdef.position.SetV(position);
    
        // The fixture of the piece is a box with a given density. The negative group index
        // makes sure that the straws does not collide.
        fdef.shape = new B2PolygonShape();
        fdef.shape.SetAsBox(this.width/2, this.height/2);
        fdef.density = density;
        fdef.filter.groupIndex = -1;
    
        // The body and fixture is created and added to the world
        this.body = world.CreateBody(bdef);
        this.body.CreateFixture(fdef);
      }
    
      // This method is called for every frame of animation. It strives to reset the original
      // angle of the straw (the joint). The time parameter is unused here but contains the
      // current time.
      GrassPart.prototype.update = function (time) {
        if (this.joint) {
          this.joint.SetMotorSpeed(GRASS_RESET_SPEED*(this.target - this.joint.GetJointAngle()));
        }
      };
    
      // The link method is used to link the pieces of the straw together using a joint
      // other: the piece to link to
      // torque: the strength of the joint (stiffness)
      GrassPart.prototype.link = function(other, torque) {
        // This is all Box2D specific. Look it up in the manual.
        var jdef = new B2RevoluteJointDef();
        var p = this.body.GetWorldPoint(new B2Vec2(0, 0.5)); // Get the world coordinates of where the joint
        jdef.Initialize(this.body, other.body, p);
        jdef.maxMotorTorque = torque;
        jdef.motorSpeed = 0;
        jdef.enableMotor = true;
    
        // Add the joint to the world
        this.joint = world.CreateJoint(jdef);
      };
    
      // A prototype for a straw of grass
      // position: the position of the bottom of the root of the straw
      function Grass(position) {
        var pos = new B2Vec2(position.x, position.y);
        var angle = 1.2*Math.random() - 0.6; // Randomize the target angle
    
        // Create three pieces, the static root and to more, and place them in line.
        // The second parameter is the stiffness of the joints. It controls how the straw bends.
        // The third is the target angle and different angles are specified for the pieces.
        this.g1 = new GrassPart(pos, 1, angle/4, true); // This is the static root
        pos.Add(new B2Vec2(0, 1));
        this.g2 = new GrassPart(pos, 0.75, angle);
        pos.Add(new B2Vec2(0, 1));
        this.g3 = new GrassPart(pos, 0.5);
    
        // Link the pieces into a straw
        this.g1.link(this.g2, 20);
        this.g2.link(this.g3, 3);
    
        // Add the pieces to the list of simulate objects
        physicalObjects.push(this.g1);
        physicalObjects.push(this.g2);
        physicalObjects.push(this.g3);
      }
    
      Grass.prototype.draw = function (context) {
          var p = new B2Vec2(0, 0.5);
          var p1 = this.g1.body.GetWorldPoint(p);
          var p2 = this.g2.body.GetWorldPoint(p);
          var p3 = this.g3.body.GetWorldPoint(p);
    
          context.strokeStyle = 'grey';
          context.lineWidth = 0.4;
          context.lineCap = 'round';
    
          context.beginPath();
          context.moveTo(p1.x, p1.y);
          context.quadraticCurveTo(p2.x, p2.y, p3.x, p3.y);
          context.stroke();
      };
    
        var lastX, grass = [], context = document.getElementById('canvas').getContext('2d');
    
        function updateGraphics(time) {
          window.requestAnimationFrame(updateGraphics);
    
          wind = 0.95*wind + 0.05*(POWER_MOUSE_WIND*windInput + POWER_RANDOM_WIND*Math.random() - POWER_RANDOM_WIND/2);
          windInput = 0;
          world.SetGravity(new B2Vec2(wind, -10));
    
          physicalObjects.forEach(function(obj) { if (obj.update) obj.update(time); });
          world.Step(1/60, 8, 3);
          world.ClearForces();
    
          context.clearRect(0, 0, context.canvas.width, context.canvas.height);
          context.save();
          context.translate(context.canvas.width/2, context.canvas.height/2);
          context.scale(context.canvas.width/20, -context.canvas.width/20);
          grass.forEach(function (o) { o.draw(context); });
          context.restore();
        }
    
        document.getElementsByTagName('body')[0].addEventListener("mousemove", function (e) {
          windInput = Math.abs(lastX - e.x) < 200? 0.2*(e.x - lastX) : 0;
          lastX = e.x;
        });
    
        var W = 8;
        for (var i = 0; i < STRAW_COUNT; i++) {
          grass.push(new Grass(new B2Vec2(W*(i/(STRAW_COUNT-1))-W/2, -1)));
        }
    
        window.requestAnimationFrame(updateGraphics);
    })();
    

提交回复
热议问题