Example #1
0
        private void Init(TreeSkeleton skeleton)
        {
            // Get branch transforms
            Matrix[] transforms = new Matrix[skeleton.Branches.Count];
            skeleton.CopyAbsoluteBranchTransformsTo(transforms);

            // Create the vertices and indices
            numlines    = skeleton.Branches.Count;
            numvertices = numlines * 2;
            VertexPositionColor[] vertices = new VertexPositionColor[numvertices];
            short[] indices = new short[numlines * 2];

            int vidx = 0;
            int iidx = 0;

            for (int i = 0; i < skeleton.Branches.Count; i++)
            {
                TreeBranch branch = skeleton.Branches[i];

                indices[iidx++] = (short)vidx;
                indices[iidx++] = (short)(vidx + 1);

                vertices[vidx++] = new VertexPositionColor(transforms[i].Translation, Color.White);
                vertices[vidx++] = new VertexPositionColor(Vector3.Transform(new Vector3(0, branch.Length, 0), transforms[i]), Color.White);
            }

            // Create buffers
            vbuffer = new VertexBuffer(device, VertexPositionColor.VertexDeclaration, numvertices, BufferUsage.None);
            vbuffer.SetData <VertexPositionColor>(vertices);
            ibuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.None);
            ibuffer.SetData <short>(indices);

            // Create the effect
            effect = new BasicEffect(device);
        }
        /// <summary>
        /// Moves forward while painting a branch here.
        /// </summary>
        /// <param name="length">Length of the new branch. The current scale will be applied to this.</param>
        /// <param name="radiusEndScale">How much smaller the ending radius should be. The equation is: StartRadius * RadiusEndScale = EndRadius.</param>
        /// <remarks>
        /// The crayon always moves along its local Y-axis, which is initially upwards.
        /// </remarks>
        public void Forward(float length, float radiusEndScale)
        {
            // Run the constraints
            if (constraints != null && !constraints.ConstrainForward(this, ref length, ref radiusEndScale))
            {
                return;
            }

            // Create the branch
            var branch = new TreeBranch(
                state.Rotation,
                length * state.Scale,
                GetRadiusAt(state.ParentIndex, state.ParentPosition) * state.RadiusScale,
                GetRadiusAt(state.ParentIndex, state.ParentPosition) * state.RadiusScale * radiusEndScale,
                state.ParentIndex,
                state.ParentPosition);

            branch.BoneIndex = state.ParentBoneIndex;
            skeleton.Branches.Add(branch);
            branchTransforms.Add(GetTransform());

            // Set newest branch to parent
            state.ParentIndex = skeleton.Branches.Count - 1;

            // Rotation is relative to the current parent, so set to identity
            // to maintain original orientation
            state.Rotation = Quaternion.Identity;

            // Move to the end of the branch
            state.ParentPosition = 1.0f;

            // Move radius scale back to one, since the radius will now be relative to the new parent
            state.RadiusScale = 1.0f;
        }
        /// <summary>
        /// Returns the radius of a given branch at the height.
        /// </summary>
        private float GetRadiusAt(int parentIndex, float f)
        {
            if (parentIndex == -1)
            {
                return(128.0f);
            }

            TreeBranch branch = skeleton.Branches[parentIndex];

            return(branch.StartRadius + f * (branch.EndRadius - branch.StartRadius));
        }
Example #4
0
        /// <summary>
        /// Sets the EndRadius to 0.0f on all branches without children.
        /// This is automatically called by the TreeGenerator.
        /// </summary>
        public void CloseEdgeBranches()
        {
            // Create a map of all the branches to remember if it is a parent or not
            var parentmap = new bool[branches.Count];

            for (int i = branches.Count - 1; i >= 0; --i)
            {
                int parent = branches[i].ParentIndex;
                if (parent != -1)
                {
                    parentmap[parent] = true;
                }
                if (!parentmap[i])
                {
                    TreeBranch branch = branches[i];
                    branch.EndRadius = 0.0f;
                    branches[i]      = branch;
                }
            }
        }
        /// <summary>
        /// Moves forward while painting a branch here.
        /// </summary>
        /// <param name="length">Length of the new branch. The current scale will be applied to this.</param>
        /// <param name="radiusEndScale">How much smaller the ending radius should be. The equation is: StartRadius * RadiusEndScale = EndRadius.</param>
        /// <remarks>
        /// The crayon always moves along its local Y-axis, which is initially upwards.
        /// </remarks>
        public void Forward(float length, float radiusEndScale)
        {
            // Run the constraints
            if (constraints != null && !constraints.ConstrainForward(this, ref length, ref radiusEndScale))
                return;

            // Create the branch
            TreeBranch branch = new TreeBranch(
                state.Rotation,
                length * state.Scale,
                GetRadiusAt(state.ParentIndex, state.ParentPosition) * state.RadiusScale,
                GetRadiusAt(state.ParentIndex, state.ParentPosition) * state.RadiusScale * radiusEndScale,
                state.ParentIndex,
                state.ParentPosition);
            branch.BoneIndex = state.ParentBoneIndex;
            skeleton.Branches.Add(branch);
            branchTransforms.Add(GetTransform());

            // Set newest branch to parent
            state.ParentIndex = skeleton.Branches.Count - 1;

            // Rotation is relative to the current parent, so set to identity
            // to maintain original orientation
            state.Rotation = Quaternion.Identity;

            // Move to the end of the branch
            state.ParentPosition = 1.0f;

            // Move radius scale back to one, since the radius will now be relative to the new parent
            state.RadiusScale = 1.0f;
        }
        /// <summary>
        /// Places the end of a bone here, unless the bone level would become too high, or too many bones have been added already.
        /// The bone's origin is at the previously added bone (as seen from the current state).
        /// </summary>
        /// <param name="delta">Amount to adjust the current bone level by</param>
        /// <remarks>
        /// Branches added between this and the previously added bone will be controlled by the new bone.
        ///
        /// The current bone is part of the crayon's state, like position and rotation, and is affected by PushState and PopState.
        /// </remarks>
        public void Bone(int delta)
        {
            if (state.BoneLevel > boneLevels + delta || skeleton.Bones.Count == MaxBones)
            {
                return;
            }

            // Get index of the parent
            int parent = state.ParentBoneIndex;

            // Get the parent's absolute transform
            Matrix parentTransform        = Matrix.Identity;
            Matrix parentInverseTransform = Matrix.Identity;
            float  parentLength           = 0.0f;

            if (parent != -1)
            {
                parentTransform        = skeleton.Bones[parent].ReferenceTransform;
                parentInverseTransform = skeleton.Bones[parent].InverseReferenceTransform;
                parentLength           = skeleton.Bones[parent].Length;
            }

            // Find the starting and ending point of the new bone
            Vector3 targetLocation = GetTransform().Translation;
            Vector3 fromLocation   = parentTransform.Translation + parentTransform.Up * parentLength;

            // Direction of the bone's Y-axis
            Vector3 directionY = Vector3.Normalize(targetLocation - fromLocation);

            // Choose arbitrary perpendicular X and Z axes
            Vector3 directionX;
            Vector3 directionZ;

            if (directionY.Y < 0.50f)
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Up));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }
            else
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Backward));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }

            // Construct the absolute rotation of the child
            Matrix childAbsoluteTransform = Matrix.Identity;

            childAbsoluteTransform.Right       = directionX;
            childAbsoluteTransform.Up          = directionY;
            childAbsoluteTransform.Backward    = directionZ;
            childAbsoluteTransform.Translation = fromLocation;

            // Calculate the relative transformation
            Matrix     relativeTransformation = childAbsoluteTransform * parentInverseTransform;
            Quaternion rotation = Quaternion.CreateFromRotationMatrix(relativeTransformation);

            // Create the new bone
            var bone = new TreeBone();

            bone.ReferenceTransform        = childAbsoluteTransform;
            bone.InverseReferenceTransform = Matrix.Invert(bone.ReferenceTransform);
            bone.Length      = Vector3.Distance(fromLocation, targetLocation);
            bone.Rotation    = rotation;
            bone.ParentIndex = parent;
            bone.Stiffness   = skeleton.Branches[state.ParentIndex].StartRadius;
            // 1.0f; // TODO: Set stiffness according to radius
            bone.EndBranchIndex = state.ParentIndex;

            // Add the bone to the skeleton
            skeleton.Bones.Add(bone);

            // Set this bone as the parent
            int endIndex  = (state.ParentBoneIndex == -1 ? -1 : skeleton.Bones[state.ParentBoneIndex].EndBranchIndex);
            int boneIndex = state.ParentBoneIndex = skeleton.Bones.Count - 1;

            state.BoneLevel -= delta;

            // Update the bone index on branches
            int branchIndex = state.ParentIndex;

            while (branchIndex != endIndex)
            {
                TreeBranch branch = skeleton.Branches[branchIndex];
                branch.BoneIndex = boneIndex;
                skeleton.Branches[branchIndex] = branch;
                branchIndex = branch.ParentIndex;
            }
        }