private void Init(TreeSkeleton skeleton) { if (skeleton.Branches.Count == 0) { throw new ArgumentException("Tree skeleton had no branches"); } if (maxRadialSegments < 3) { throw new ArgumentException("Tree must have at least 3 radial segments"); } // min and max keep track of the mesh's bounding box. Vector3 min = new Vector3(10000, 10000, 10000); Vector3 max = new Vector3(-10000, -10000, -10000); // Create lists for vertices and indices List <TreeVertex> vertices = new List <TreeVertex>(); List <int> indices = new List <int>(); // Absolute transformation of branches Matrix[] transforms = new Matrix[skeleton.Branches.Count]; skeleton.CopyAbsoluteBranchTransformsTo(transforms); // Branch topological distances from root float[] distances = new float[skeleton.Branches.Count]; skeleton.GetLongestBranching(distances); // // Create vertices and indices // for (int i = 0; i < skeleton.Branches.Count; i++) { int bottomRadials = GetRadialSegmentsBottom(i, skeleton); // Add bottom vertices int parentIndex = skeleton.Branches[i].ParentIndex; int bottomIndex = vertices.Count; Matrix bottomTransform = transforms[i]; if (parentIndex != -1 && skeleton.Branches[i].ParentPosition > 0.99f && Vector3.Dot(transforms[i].Up, transforms[parentIndex].Up) > 0.7f) { bottomTransform = transforms[parentIndex]; bottomTransform.Translation += bottomTransform.Up * skeleton.Branches[parentIndex].Length; // Rotate bottomTransform to the best fit to avoid twisting Vector3 childDir = Vector3.Transform(Vector3.Right, skeleton.Branches[i].Rotation); float maxdot = -2.0f; double bestangle = 0.0; for (int j = 0; j < bottomRadials; j++) { double angle = j / (double)bottomRadials * Math.PI * 2.0; Vector3 vec = new Vector3((float)Math.Cos(angle), 0, (float)Math.Sin(angle)); float dot = Vector3.Dot(childDir, vec); if (dot > maxdot) { maxdot = dot; bestangle = angle; } } float cos = (float)Math.Cos(bestangle); float sin = (float)Math.Sin(bestangle); Vector3 right = bottomTransform.Right * cos + bottomTransform.Backward * sin; Vector3 back = -bottomTransform.Right * sin + bottomTransform.Backward * cos; bottomTransform.Right = right; bottomTransform.Backward = back; } // Texture coordinates float ty = (distances[i] - skeleton.Branches[i].Length) / skeleton.TextureHeight; float txspan = 0.25f + 0.75f * skeleton.Branches[i].StartRadius / skeleton.TrunkRadius; // Bones int parentBoneIndex = (parentIndex == -1? skeleton.Branches[i].BoneIndex : skeleton.Branches[parentIndex].BoneIndex); int branchBoneIndex = skeleton.Branches[i].BoneIndex; AddCircleVertices(ref bottomTransform, skeleton.Branches[i].StartRadius, bottomRadials, ty, 0.0f, txspan, vertices, parentBoneIndex, parentBoneIndex); // Add top vertices int topRadials = GetRadialSegmentsTop(i, skeleton); int topIndex = vertices.Count; Matrix topTransform = transforms[i]; topTransform.Translation += topTransform.Up * skeleton.Branches[i].Length; ty = ty + skeleton.Branches[i].Length / skeleton.TextureHeight; txspan = 0.25f + 0.75f * skeleton.Branches[i].EndRadius / skeleton.TrunkRadius; AddCircleVertices(ref topTransform, skeleton.Branches[i].EndRadius, topRadials, ty, 0.0f, txspan, vertices, branchBoneIndex, branchBoneIndex); // Add indices AddCylinderIndices(bottomIndex, bottomRadials, topIndex, topRadials, indices); // Updates bounds SetMin(ref min, bottomTransform.Translation); SetMin(ref min, topTransform.Translation); SetMax(ref max, bottomTransform.Translation); SetMax(ref max, topTransform.Translation); } numvertices = vertices.Count; numtriangles = indices.Count / 3; // Create the buffers vbuffer = new VertexBuffer(device, TreeVertex.VertexDeclaration, vertices.Count, BufferUsage.None); vbuffer.SetData <TreeVertex>(vertices.ToArray()); if (vertices.Count > 0xFFFF) { ibuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.None); ibuffer.SetData <int>(indices.ToArray()); } else { ibuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Count, BufferUsage.None); ibuffer.SetData <short>(Create16BitArray(indices)); } // Set the bounding sphere boundingSphere.Center = (min + max) / 2.0f; boundingSphere.Radius = (max - min).Length() / 2.0f; }
private void Init(TreeSkeleton skeleton) { if (skeleton.Branches.Count == 0) throw new ArgumentException("Tree skeleton had no branches"); if (maxRadialSegments < 3) throw new ArgumentException("Tree must have at least 3 radial segments"); // min and max keep track of the mesh's bounding box. Vector3 min = new Vector3(10000, 10000, 10000); Vector3 max = new Vector3(-10000, -10000, -10000); // Create lists for vertices and indices List<TreeVertex> vertices = new List<TreeVertex>(); List<int> indices = new List<int>(); // Absolute transformation of branches Matrix[] transforms = new Matrix[skeleton.Branches.Count]; skeleton.CopyAbsoluteBranchTransformsTo(transforms); // Branch topological distances from root float[] distances = new float[skeleton.Branches.Count]; skeleton.GetLongestBranching(distances); // // Create vertices and indices // for (int i = 0; i < skeleton.Branches.Count; i++) { int bottomRadials = GetRadialSegmentsBottom(i, skeleton); // Add bottom vertices int parentIndex = skeleton.Branches[i].ParentIndex; int bottomIndex = vertices.Count; Matrix bottomTransform = transforms[i]; if (parentIndex != -1 && skeleton.Branches[i].ParentPosition > 0.99f && Vector3.Dot(transforms[i].Up, transforms[parentIndex].Up) > 0.7f) { bottomTransform = transforms[parentIndex]; bottomTransform.Translation += bottomTransform.Up * skeleton.Branches[parentIndex].Length; // Rotate bottomTransform to the best fit to avoid twisting Vector3 childDir = Vector3.Transform(Vector3.Right, skeleton.Branches[i].Rotation); float maxdot = -2.0f; double bestangle = 0.0; for (int j = 0; j < bottomRadials; j++) { double angle = j / (double)bottomRadials * Math.PI * 2.0; Vector3 vec = new Vector3((float)Math.Cos(angle), 0, (float)Math.Sin(angle)); float dot = Vector3.Dot(childDir, vec); if (dot > maxdot) { maxdot = dot; bestangle = angle; } } float cos = (float)Math.Cos(bestangle); float sin = (float)Math.Sin(bestangle); Vector3 right = bottomTransform.Right * cos + bottomTransform.Backward * sin; Vector3 back = -bottomTransform.Right * sin + bottomTransform.Backward * cos; bottomTransform.Right = right; bottomTransform.Backward = back; } // Texture coordinates float ty = (distances[i] - skeleton.Branches[i].Length) / skeleton.TextureHeight; float txspan = 0.25f + 0.75f * skeleton.Branches[i].StartRadius / skeleton.TrunkRadius; // Bones int parentBoneIndex = (parentIndex == -1? skeleton.Branches[i].BoneIndex : skeleton.Branches[parentIndex].BoneIndex); int branchBoneIndex = skeleton.Branches[i].BoneIndex; AddCircleVertices(ref bottomTransform, skeleton.Branches[i].StartRadius, bottomRadials, ty, 0.0f, txspan, vertices, parentBoneIndex, parentBoneIndex); // Add top vertices int topRadials = GetRadialSegmentsTop(i, skeleton); int topIndex = vertices.Count; Matrix topTransform = transforms[i]; topTransform.Translation += topTransform.Up * skeleton.Branches[i].Length; ty = ty + skeleton.Branches[i].Length / skeleton.TextureHeight; txspan = 0.25f + 0.75f * skeleton.Branches[i].EndRadius / skeleton.TrunkRadius; AddCircleVertices(ref topTransform, skeleton.Branches[i].EndRadius, topRadials, ty, 0.0f, txspan, vertices, branchBoneIndex, branchBoneIndex); // Add indices AddCylinderIndices(bottomIndex, bottomRadials, topIndex, topRadials, indices); // Updates bounds SetMin(ref min, bottomTransform.Translation); SetMin(ref min, topTransform.Translation); SetMax(ref max, bottomTransform.Translation); SetMax(ref max, topTransform.Translation); } numvertices = vertices.Count; numtriangles = indices.Count / 3; vdeclaration = new VertexDeclaration(TreeVertex.VertexElements); // Create the buffers vbuffer = new VertexBuffer(device, vdeclaration, vertices.Count, BufferUsage.WriteOnly); vbuffer.SetData<TreeVertex>(vertices.ToArray()); if (vertices.Count > 0xFFFF) { ibuffer = new IndexBuffer(device, IndexElementSize.ThirtyTwoBits, indices.Count , BufferUsage.WriteOnly); ibuffer.SetData<int>(indices.ToArray()); } else { ibuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Count , BufferUsage.WriteOnly); ibuffer.SetData<short>(Create16BitArray(indices)); } // Set the bounding sphere boundingSphere.Center = (min + max) / 2.0f; boundingSphere.Radius = (max - min).Length() / 2.0f; }