public virtual void BuildTree() { if (RandomSeed == 0) { rnd = new Random(); } else { rnd = new Random(RandomSeed); } particles.Clear(); Particle3D trunk = new Particle3D() { Location = InitialPosition, Direction = new Vector3D(0, 1, 0), Life = maxLife, MaxLife = maxLife, Color = trunkColor, Behaviour = TrunkBehaviour }; particles.Add(trunk); }
/// <summary> /// Describes what happens in a trunk particle /// </summary> /// <param name="trunk">The trunk particle</param> private void TrunkBehaviour(Particle3D trunk) { int depth = 1; // stimulate branching where life is low if (stimulateBranchingAtEndOfLife) { BranchingBehaviour((float)LineairScaleTo((((float)trunk.MaxLife - trunk.Life) / (float)trunk.MaxLife), 0.0f, 1f) * branchingPercent, trunk, depth); } else { BranchingBehaviour(branchingPercent, trunk, depth); } // leaves behaviour LeavesBehaviour(trunk); // zigzag the tree a little TrunkNudgeBehaviour(trunk); // make the tree thicker TrunkThickingBehaviour(trunk); // make the trunk split sometimes TrunkSplittingBehaviour(trunk); }
protected virtual void OnPixelSet(Particle3D p) { //bmp.SetPixel((int)p.Location.X, pic.Height - 1 - (int)p.Location.Y, p.Color); PixelSetHandler temp = PixelSet; if (temp != null) { temp((int)p.OldLocation.X, (int)p.OldLocation.Y, (int)p.OldLocation.Z, (int)p.Location.X, (int)p.Location.Y, (int)p.Location.Z, p.Color); } //} }
/// <summary> /// Nudge the tree to create a zig-zag effect (so that the tree isn't dead straight) /// </summary> /// <param name="trunk">A trunk particle</param> private void TrunkNudgeBehaviour(Particle3D trunk) { // subtle x nudgings if (rnd.NextDouble() < zigzagTrunkPercentage) { trunk.Direction = trunk.Direction.RotateZ(LineairScaleTo(rnd.NextDouble(), -zigzagTrunkStrength, zigzagTrunkStrength)) .RotateY(rnd.Next(0, 2 * Math.PI)); } //if (trunk.Direction.Y < 1) //{ // trunk.Direction.Y += 0.1f; //} //if (trunk.Direction.Y > 1) // trunk.Direction.Y = 1; }
/// <summary> /// Describes the behaviour of spawning leaves on branches /// </summary> /// <param name="b"></param> private void LeavesBehaviour(Particle3D b) { if (b.Life < leavesPercentage * b.MaxLife) { // create leaves for (int i = 0; i < leavesNrSpawned; i++) { Particle3D l = new Particle3D() { Direction = new Vector3D(rnd.Next(-1f, 1f), rnd.Next(-1f, 1f), rnd.Next(-1f, 1f)), Location = b.Location, Color = leavesColor, Life = leafLife, MaxLife = leafLife }; particles.Add(l); } } }
/// <summary> /// Describes the branching and general behaviour of a branch /// </summary> /// <param name="branchingPercent"></param> /// <param name="branch"></param> /// <param name="depth"></param> private void BranchingBehaviour(float branchingPercent, Particle3D t, int depth) { if (rnd.NextDouble() < branchingPercent)//* (Math.Pow(0.5f, depth))) { // 90 * 2 ^ depth-1 // [-90, 90] degrees => depth =1 // [-45, 45] degrees => depth = 2 // [-22.5, double narrower = (Math.Pow(branchNarrowing, depth)); // branch in a random direction but decrease the range based on the depth of the recursion // still branch in a random direction around the Y axis Vector3D initialDirection = t.Direction.RotateZ(rnd.Next(-Math.PI * narrower, Math.PI * narrower)) .RotateY(rnd.Next(0, Math.PI * 2)); Particle3D branch = new Particle3D() { Location = t.Location, Direction = initialDirection, MaxLife = (int)(t.Life * branchSizeDecrease), Life = (int)(t.Life * branchSizeDecrease), Color = branchColor, }; branch.Behaviour = b => { LeavesBehaviour(b); BranchingBehaviour(branchingPercent, b, depth + 1); // weight behaviour if (applyWeightOnBranches) { b.Direction = new Vector3D(initialDirection.X, initialDirection.Y * LineairScaleTo((double)b.Life / (double)branch.MaxLife, -1f, 1f), initialDirection.Z);// +(2 * (((double)b.Life / (double)maxLife)) - 1); } }; particles.Add(branch); } }
/// <summary> /// Make the trunk of the tree bigger /// </summary> /// <param name="trunk"></param> private void TrunkThickingBehaviour(Particle3D trunk) { // thicking int maxTrunkLife = (int)(((float)trunk.Life / (float)trunk.MaxLife) * (thickHeightRatio * trunk.MaxLife)); double piTimes2 = (2 * Math.PI); var trunkRotatedOnZ = trunk.Direction.RotateZ(-Math.PI / 2); // spawn particles in every possible direction int nrSpawn = 720; for (int i = 0; i < nrSpawn; i++) { Particle3D t1 = new Particle3D() { Location = trunk.Location, Direction = trunkRotatedOnZ.RotateY((i / (float)nrSpawn) * piTimes2) .RotateZ((i / (float)nrSpawn) * piTimes2), Life = maxTrunkLife, MaxLife = maxTrunkLife, Color = trunk.Color }; particles.Add(t1); } //Particle3D t2 = new Particle3D() //{ // Location = trunk.Location, // Direction = trunk.Direction.RotateZ(Math.PI / 2), // Life = maxTrunkLife, // MaxLife = maxTrunkLife, // Color = trunk.Color //}; //particles.Add(t2); }
/// <summary> /// Describes how a trunk splits /// </summary> /// <param name="trunk">The trunk particle</param> private void TrunkSplittingBehaviour(Particle3D trunk) { // trunk split if (rnd.NextDouble() < trunkSplitPercentage) { Vector3D newDirection = trunk.Direction.RotateZ(rnd.Next(-Math.PI, Math.PI)) .RotateY(rnd.Next(0, 2 * Math.PI)); Particle3D secondTrunk = new Particle3D() { Location = trunk.Location, Direction = newDirection, Color = trunk.Color, Life = (int)(trunk.Life * trunkSplitSpawnLifeDecrease), MaxLife = (int)(trunk.Life * trunkSplitSpawnLifeDecrease), Behaviour = trunk.Behaviour }; particles.Add(secondTrunk); if (secondTrunk.Direction.Y < 0) { secondTrunk.Direction.Y *= -1; } trunk.Life = (int)(trunk.Life * trunkSplitOrigLifeDecrease); // TODO trunk.Direction = new Vector3D(-newDirection.X, newDirection.Y, newDirection.Z); //trunk.Direction.Rotate(-Math.PI / 2 * rnd.NextDouble()); if (trunk.Direction.Y < 0) { trunk.Direction.Y *= -1; } } }