- Home /
Create a leaf with it's natural motion acting upon gravity?
Hello Devs,
I am trying to create a leaf where you drop it and it falls acting upon gravity. It has to be a real leaf or should I say I am trying to create something very similar to a simulator. I was thinking about a configurable joint across the leaf. But I am not sure though. As for as the physics is concerned, I was going to add a rigidbody and bring down the mass, angular drag to minimum depending upon the play testing. Plus I was also about to bring the overall Gravity to -2 from -9.81.
For the future I was planning upon adding 1.Fire 2.Wind 3.Water to give more realism. If a part of the leaf gets a hit by a branch then it should detach itself from it's parent.
Hassle : My question is, as being a lone dev I would like to know how should I approach this problem. I do not have a good leaf model either. I would also prefer to buy some assets on the asset store (last option), if I have to.
Kindly help me as of how to approach.
regards,
Karsnen.
PS if you also mean you literally don't have any good artwork for a leaf, just buy some for 10 or 15 dollars. How else could you get it other than buying it? The whole modern world - every aspect of everything from manufacturing to entertainment - works on the basis of buying and selling 3D models and 3D textures, there is an infinite variety available! Just turn on the internet
Answer by Fattie · Jun 09, 2012 at 08:58 AM
"or should I say I am trying to create something very similar to a simulator"
I love that sentence!
do not, ever, change gravity. Never.
make absolutely sure your leaf has real-world sizes and real-world masses. you'll need an accurate scale to go out and weigh some leaves
it is all about air flow. you are going to have to model, in some way, airflow. likely you can simply add an upwards force - probably randomized every about 1.7 seconds I'd say - on a script on the object
you mention hinges, are you implying you want the leaf to bend in the middle, ie the leaf has two parts? i would not do this, just leave it as one objet
it is a pain in the arse to make rocking movements, like a boat on water. or like, err, a leaf in air. one very simple approach is make a little thingy that applies force at each of the two ends (ie, as in point 3) and also do "something" in the middle such as: add an invisible rod a couple inches long that hangs down, and stick a small weight on the end. It will sort of balance it and rock it.
Now you're simulating - you're a real game programmer! Enjoy!
Don't forget to WORK TIDILY. It is a hallmark of good simulation programming that you always for example carefully calculate your own mass (very likely some bastard has changed the mass of some component while tweaking it), for example attach this to everything antigravityFixer.js
#pragma strict
function Awake()
{
GetComponent(ConstantForce).force =
Physics.gravity * giveTotalMass() * -1.0;
}
function giveTotalMass():float
{
// all rigidbodies here and below, sum the mass!!!
var tm:float = 0.0;
for (var rb : Rigidbody in
transform.parent.GetComponentsInChildren(Rigidbody))
tm += rb.mass;
return tm;
}
and then you might see code like this kicking around...
function Awake()
{
if ( GetComponent(antigravityFixer) )
massOfObject = GetComponent(antigravityFixer).giveTotalMass();
getJoystickForceHere.localPosition = Vector3.zero; // just in case
}
function FixedUpdate()
{
pushMeBaby = getJoystickForceHere.localPosition * 1.5;
rigidbody.AddForce( pushMeBaby * massOfObject );
blah blah...
}
Hope it helps in some way!
Really the best solution here is, someone probably has a really good "leaf rig" already that they don't mind giving away.
Personally if I was doing this... You see in point 5 it describes "two" places with random air-blasts upwards. I'd make a little sled that randomizes the position and number of those "air blast areas" and then have a little trivial evolutionary algorithm that runs for a day looking for some simple metrics, like, "does not flip over often" or "doesn't just boringly never move" or "slowly heads downwards overall".
That being said, you can very likely get a great result just by guessing two good spots for "little air blasts"
Again - there's surely someone who already has a decent leaf-rig they don't mind giving away, making all this chat useless.
Also ... it's worth noting that an unbelievably simple way to do this is:
MAKE AN ANIMATION...
just make a long animation of a leaf with a nice natural jiggle on it (get the famous scene with the ticket from the movie polar express for reference). Just randomly play sections of the animations as it falls!
Total work time, 10 minutes.
Worth remembering there is very often "an incredibly simpler solution that is better anyway" :)
Wow. Fattie - Thanks man. That was a comprehensive answer. I am right now working like the way you have told. But again, I have one doubt.
Why do you recommend not to change the value of gravity? Is there any specific optimization values?
Because with what I tried and what I saw on the internet, it says that only scaling on the object differs the gravitational force and not the mass of the object. $$anonymous$$oreover, I also see you script has altered the Gravity. Is it okay I change the drag through scripts, if needed (at certain instances).
Thank you.
Add to add upon that, Unity also recommends not to change the masses of rigidbodies within 100 times.
http://unity3d.com/support/documentation/Components/class-Rigidbody.html At $$anonymous$$ass Explanation.
I hope that if I add in objects in the future I might have to add objects which might have 100 times difference.
Note! never change gravity !!! nothing works once you change gravity. it always leads to trouble. EVERYTHING about physX is built from the ground up to use real masses, real size, and real gravity.
regarding that script, it does not change gravity: very simply, it adds a force in opposition to gravity!!!
thanks for the "tick" by the way!!!!!!!!!
Do not hesitate to ask ANYTHING else you may need. Anything big or small.
@fattie I do not have plan of changing the gravity at Edit -> Project Settings ->Physics -> Gravity.
If thats what you meant by gravity. I A$$anonymous$$ NOT CHANGING THAT.
But the drag, mass on the rigidbody?
Thanks by the way.
Answer by bjennings76 · Nov 20, 2016 at 10:35 AM
I realize this post is quite old, but I recently needed to create my own script for a non-particle falling sheet of paper and @fattie's answer helped me a lot. In addition to the 'puff' idea, I also added a slide force based on the slope of the paper that worked out quite well for my purposes.
Here's my script in case it helps anyone else.
Note: This script assumes the paper is thinnest on the Y axis (as if the default orientation is laying flat on a table).
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[RequireComponent(typeof(BoxCollider), typeof(Rigidbody), typeof(ConstantForce))]
public class FeatherFall : MonoBehaviour {
[SerializeField, Range(0.01f, 1f)] private float m_FloatForce = 0.8f;
[SerializeField, Range(0.01f, 1f)] private float m_SlidePower = 0.2f;
[SerializeField, Range(0.01f, 1f)] private float m_PuffPower = 0.05f;
[SerializeField, Range(0.01f, 1f)] private float m_PuffDelayMin = 0.2f;
[SerializeField, Range(0.01f, 1f)] private float m_PuffDelayMax = 0.3f;
private Rigidbody m_Rigidbody;
private BoxCollider m_Collider;
private Vector3 m_AntigravityForce;
private float m_LastTime;
private float m_Delay;
private Vector3[] m_EdgePoints;
private Vector3 m_SlideVector;
private Vector3 m_LastPuffPosition;
private Vector3 m_LastPuffPower;
private void Start() {
m_Rigidbody = GetComponent<Rigidbody>();
m_Collider = GetComponent<BoxCollider>();
m_AntigravityForce = GetAntigravityForce();
GetComponent<ConstantForce>().force = m_AntigravityForce*m_FloatForce;
Vector3 center = m_Collider.center;
Vector3 size = m_Collider.size/2;
m_EdgePoints = new[] {
new Vector3( 0, 0, -size.z) + center, //bottom
new Vector3( 0, 0, size.z) + center, //top
new Vector3(-size.x, 0, 0) + center, //left
new Vector3( size.x, 0, 0) + center, //right
new Vector3(-size.x, 0, -size.z) + center, //bottom left
new Vector3( size.x, 0, -size.z) + center, //bottom right
new Vector3(-size.x, 0, size.z) + center, //top left
new Vector3( size.x, 0, size.z) + center //top right
};
}
private void Update() {
UpdateSlide();
UpdatePuffs();
}
private void UpdateSlide() {
Vector3 normal = transform.up;
m_SlideVector.x = normal.x*normal.y;
m_SlideVector.z = normal.z*normal.y;
m_SlideVector.y = -(normal.x*normal.x) - normal.z*normal.z;
m_Rigidbody.AddForce(m_SlideVector.normalized*m_SlidePower);
}
private void UpdatePuffs() {
if (m_LastTime + m_Delay < Time.time) {
Puff();
}
}
private void Puff() {
float downwardVelocity = -m_Rigidbody.velocity.y;
if (downwardVelocity > 0.001f) {
m_LastTime = Time.time;
m_Delay = Random.Range(m_PuffDelayMin, m_PuffDelayMax);
Vector3 puffPosition = GetPuffPosition();
m_LastPuffPower = m_AntigravityForce*m_PuffPower*downwardVelocity;
m_LastPuffPosition = transform.InverseTransformPoint(puffPosition);
m_Rigidbody.AddForceAtPosition(m_LastPuffPower, puffPosition, ForceMode.Impulse);
}
}
private Vector3 GetPuffPosition() {
Vector3 worldOffset = m_Collider.bounds.center;
List<Vector3> worldEdges = m_EdgePoints.Select<Vector3, Vector3>(transform.TransformPoint).ToList();
List<Vector3> validEdges = worldEdges.Where(v => v.y <= worldOffset.y).ToList();
if (validEdges.Count == 0) {
validEdges = worldEdges;
}
int edgeIndex = Random.Range(0, validEdges.Count - 1);
return validEdges[edgeIndex];
}
private Vector3 GetAntigravityForce() {
float totalMass = transform.GetComponentsInChildren<Rigidbody>().Sum(rb => rb.mass);
return Physics.gravity*totalMass*-1f;
}
private void OnDrawGizmos() {
if (m_EdgePoints == null) {
return;
}
// Slide Vector
Debug.DrawRay(transform.position, m_SlideVector, Color.blue);
// Last Puff Vector
Vector3 puffPosition = transform.TransformPoint(m_LastPuffPosition);
Color puffColor = Color.white;
float timeSinceLast = Time.time - m_LastTime;
puffColor.a = 1 - timeSinceLast/m_Delay;
Debug.DrawRay(puffPosition, m_LastPuffPower*10, puffColor);
foreach (Vector3 edgePoint in m_EdgePoints) {
Vector3 edgePosition = transform.TransformPoint(edgePoint);
Gizmos.color = Color.white;
Gizmos.DrawSphere(edgePosition, 0.01f);
}
}
}
Your answer
Follow this Question
Related Questions
ConfigurableJoint Anchors and nested RigidBodies 2 Answers
Why is my object tilting when moving? 2 Answers
Calculate Distance using WheelColliders 3 Answers
How to test for a collision with a Terrain 1 Answer
Creating a SIMPLE car. 1 Answer