public Tree(TreeGroup group, SpeedTreeWrapper speedTree, Vector3 location) { this.group = group; this.location = location; this.speedTree = speedTree; billboard0 = new float[20]; billboard1 = new float[20]; // set location for the instance speedTree.TreePosition = SpeedTreeUtil.ToSpeedTree(location); // set bounding box AxisAlignedBox stbox = SpeedTreeUtil.FromSpeedTree(speedTree.BoundingBox); this.bounds = new AxisAlignedBox(stbox.Minimum + location, stbox.Maximum + location); }
// This method is the callback by which the forests controlled // by the scene manager tell us about SpeedTrees. private void AddTreeObstacles(SpeedTreeWrapper tree) { // If this tree didn't use to be in range but now is V3 vp = tree.TreePosition; Vector3 p = new Vector3(vp.x, vp.y, vp.z); // Find the tile in question int tileX, tileZ; WorldToTileCoords(p, out tileX, out tileZ); bool oir = InRange(tileXCenter, tileZCenter, tileX, tileZ); bool nir = InRange(newTileXCenter, newTileZCenter, tileX, tileZ); // if (MO.DoLog) // MO.Log(String.Format("For tree at {0}, testing !InRange({1},{2},{3},{4}) = {5} && InRange({6},{7},{8},{9}) = {10}", // MO.MeterString(p),tileXCenter, tileZCenter, tileX, tileZ, MO.Bool(!oir), // newTileXCenter, newTileZCenter, tileX, tileZ, MO.Bool(nir))); if (!oir && nir) { int tX = TileToArrayIndex(tileX, newTileXCenter); int tZ = TileToArrayIndex(tileZ, newTileZCenter); uint count = tree.CollisionObjectCount; long handle = ComposeHandle(tileX, tileZ); CollisionShape shape = null; if (MO.DoLog) { MO.Log(string.Format("Adding tree at {0}, tiles[{1},{2}] = {3}, tile coords[{4},{5}], obj. new count {6}", MO.MeterString(p), tX, tZ, tiles[tX,tZ], tileX, tileZ, count)); MO.Log(string.Format("Handle {0}, oldcenter {1}, newcenter {2}", MO.HandleString(handle), MO.MeterString(tileWorldCenter), MO.MeterString(newTileWorldCenter))); } float size = 0f; float variance = 0f; tree.GetTreeSize(ref size, ref variance); float scaleFactor = size / tree.OriginalSize; for (uint i=0; i<count; i++) { TreeCollisionObject tco = tree.CollisionObject(i); Vector3 cp = new Vector3(tco.position.x, tco.position.y, tco.position.z) * scaleFactor + p; Vector3 cd = new Vector3(tco.dimensions.x, tco.dimensions.y, tco.dimensions.z) * scaleFactor; switch ((CollisionObjectType)tco.type) { case CollisionObjectType.ColSphere: shape = new CollisionSphere(cp, cd.x); break; case CollisionObjectType.ColCylinder: // We treat it as a capsule, but we raise the // capsule up by the capRadius, and shorten // the segment by the double the capRadius Vector3 top = cp; top.y += cd.y - cd.x * 2f; cp.y += cd.x; shape = new CollisionCapsule(cp, top, cd.x); break; case CollisionObjectType.ColBox: Vector3 tp = cp; tp.x -= cd.x * .5f; tp.y -= cd.y * .5f; shape = new CollisionAABB(tp, tp + cd); break; } collisionAPI.AddCollisionShape(shape, handle); tiles[tX, tZ]++; objectsAdded++; if (MO.DoLog) { MO.Log(string.Format(" tiles[{0},{1}] = {2}, tile at [{3},{4}] after adding shape {5}", tX, tZ, tiles[tX, tZ], tileX, tileZ, shape.ToString())); } } } }
// This method is the callback by which the forests controlled // by the scene manager tell us about SpeedTrees. private void AddTreeObstacles(SpeedTreeWrapper tree) { // If this tree didn't use to be in range but now is V3 vp = tree.TreePosition; Vector3 p = new Vector3(vp.x, vp.y, vp.z); // Find the tile in question int tileX, tileZ; WorldToTileCoords(p, out tileX, out tileZ); bool oir = InRange(tileXCenter, tileZCenter, tileX, tileZ); bool nir = InRange(newTileXCenter, newTileZCenter, tileX, tileZ); // if (MO.DoLog) // MO.Log(String.Format("For tree at {0}, testing !InRange({1},{2},{3},{4}) = {5} && InRange({6},{7},{8},{9}) = {10}", // MO.MeterString(p),tileXCenter, tileZCenter, tileX, tileZ, MO.Bool(!oir), // newTileXCenter, newTileZCenter, tileX, tileZ, MO.Bool(nir))); if (!oir && nir) { int tX = TileToArrayIndex(tileX, newTileXCenter); int tZ = TileToArrayIndex(tileZ, newTileZCenter); uint count = tree.CollisionObjectCount; long handle = ComposeHandle(tileX, tileZ); CollisionShape shape = null; if (MO.DoLog) { MO.Log(string.Format("Adding tree at {0}, tiles[{1},{2}] = {3}, tile coords[{4},{5}], obj. new count {6}", MO.MeterString(p), tX, tZ, tiles[tX, tZ], tileX, tileZ, count)); MO.Log(string.Format("Handle {0}, oldcenter {1}, newcenter {2}", MO.HandleString(handle), MO.MeterString(tileWorldCenter), MO.MeterString(newTileWorldCenter))); } float size = 0f; float variance = 0f; tree.GetTreeSize(ref size, ref variance); float scaleFactor = size / tree.OriginalSize; for (uint i = 0; i < count; i++) { TreeCollisionObject tco = tree.CollisionObject(i); Vector3 cp = new Vector3(tco.position.x, tco.position.y, tco.position.z) * scaleFactor + p; Vector3 cd = new Vector3(tco.dimensions.x, tco.dimensions.y, tco.dimensions.z) * scaleFactor; switch ((CollisionObjectType)tco.type) { case CollisionObjectType.ColSphere: shape = new CollisionSphere(cp, cd.x); break; case CollisionObjectType.ColCylinder: // We treat it as a capsule, but we raise the // capsule up by the capRadius, and shorten // the segment by the double the capRadius Vector3 top = cp; top.y += cd.y - cd.x * 2f; cp.y += cd.x; shape = new CollisionCapsule(cp, top, cd.x); break; case CollisionObjectType.ColBox: Vector3 tp = cp; tp.x -= cd.x * .5f; tp.y -= cd.y * .5f; shape = new CollisionAABB(tp, tp + cd); break; } collisionAPI.AddCollisionShape(shape, handle); tiles[tX, tZ]++; objectsAdded++; if (MO.DoLog) { MO.Log(string.Format(" tiles[{0},{1}] = {2}, tile at [{3},{4}] after adding shape {5}", tX, tZ, tiles[tX, tZ], tileX, tileZ, shape.ToString())); } } } }
public TreeGroup(String filename, float size, float sizeVariance, SpeedWindWrapper speedWind, Forest forest, List<Vector3> locations) { if (!initialized) { Initialize(); } name = String.Format("Forest: {0} File: {1} Instances: {2}", forest.Name, filename, locations.Count); this.forest = forest; this.speedWind = speedWind; speedTree = new SpeedTreeWrapper(); speedTree.TextureFlip = true; LoadTree(filename); speedTree.BranchWindMethod = WindMethod.WindGPU; speedTree.FrondWindMethod = WindMethod.WindGPU; speedTree.LeafWindMethod = WindMethod.WindGPU; float originalSize = 0f; float variance = 0f; speedTree.GetTreeSize(ref originalSize, ref variance); speedTree.OriginalSize = originalSize; speedTree.SetTreeSize(size, sizeVariance); treeTextures = speedTree.Textures; // make sure the tree doesn't have too many leaf texture groups Debug.Assert(treeTextures.LeafTextureFilenames.Length <= 3); // for trees with 3 leaf textures, reduce the number of rocking groups to 2 // (from the default of 3), so that we don't overflow the number of available shader // param registers if (treeTextures.LeafTextureFilenames.Length == 3) { speedTree.NumLeafRockingGroups = 2; } speedTree.Compute(SpeedTreeUtil.ToSpeedTree(Matrix4.Identity), 1, true); speedTree.TreePosition = SpeedTreeUtil.ToSpeedTree(Vector3.Zero); // set lod limits speedTree.SetLodLimits(nearLOD, farLOD); // create the geometry object geometry = new TreeGeometry(); // // Setup branches // // create the render operation branchRenderOp = new RenderOperation(); branchRenderOp.operationType = OperationType.TriangleStrip; branchRenderOp.useIndices = true; // set up the material. branchMaterial = SetupTreeMaterial("SpeedTree/Branch", treeTextures.BranchTextureFilename, treeTextures.SelfShadowFilename, GenerateNormalMapTextureName(treeTextures.BranchTextureFilename), speedTree.BranchMaterial, !normalMapped, branchTechnique); // get number of branch LODs uint nBranchLODs = speedTree.NumBranchLodLevels; // allocate branch buffers branchVertexBuffers = new VertexData[nBranchLODs]; branchIndexBuffers = new IndexData[nBranchLODs]; for (short i = 0; i < nBranchLODs; i++) { // set up the vertex and index buffers for the branch geometry speedTree.GetGeometry(geometry, SpeedTreeWrapper.GeometryFlags.BranchGeometry, i, -1, -1); BuildIndexedBuffer(geometry.Branches, true, out branchVertexBuffers[i], out branchIndexBuffers[i]); } // // Setup fronds // // create the render operation frondRenderOp = new RenderOperation(); frondRenderOp.operationType = OperationType.TriangleStrip; frondRenderOp.useIndices = true; // set up the material frondMaterial = SetupTreeMaterial("SpeedTree/Frond", treeTextures.CompositeFilename, treeTextures.SelfShadowFilename, null, speedTree.FrondMaterial, true, 0); uint nFrondLODs = speedTree.NumFrondLodLevels; // allocate frond buffer arrays frondVertexBuffers = new VertexData[nFrondLODs]; frondIndexBuffers = new IndexData[nFrondLODs]; for ( short i = 0; i < nFrondLODs; i++ ) { // build the frond geometry for each LOD speedTree.GetGeometry(geometry, SpeedTreeWrapper.GeometryFlags.FrondGeometry, -1, i, -1); BuildIndexedBuffer(geometry.Fronds, false, out frondVertexBuffers[i], out frondIndexBuffers[i]); } // // Setup Leaves // TreeCamera saveCam = SpeedTreeWrapper.Camera; TreeCamera treeCamera = new TreeCamera(); treeCamera.position = SpeedTreeUtil.ToSpeedTree(Vector3.Zero); treeCamera.direction = SpeedTreeUtil.ToSpeedTree(new Vector3(1,0,0)); SpeedTreeWrapper.Camera = treeCamera; // set up render ops leaf0RenderOp = new RenderOperation(); leaf0RenderOp.operationType = OperationType.TriangleList; leaf0RenderOp.useIndices = true; leaf1RenderOp = new RenderOperation(); leaf1RenderOp.operationType = OperationType.TriangleList; leaf1RenderOp.useIndices = true; // set up the material leafMaterial = SetupTreeMaterial("SpeedTree/Leaf", treeTextures.CompositeFilename, null, null, speedTree.LeafMaterial, true, 0); uint nLeafLODs = speedTree.NumLeafLodLevels; // allocate leaf buffer arrays leafVertexBuffers = new VertexData[nLeafLODs]; leafIndexBuffers = new IndexData[nLeafLODs]; float [] lodLeafAdjust = speedTree.LeafLodSizeAdjustments; for ( short i = 0; i < nLeafLODs; i++ ) { // build the leaf geometry for each LOD speedTree.GetGeometry(geometry, SpeedTreeWrapper.GeometryFlags.LeafGeometry, -1, -1, i); BuildLeafBuffer(geometry.Leaves0, lodLeafAdjust[i], out leafVertexBuffers[i], out leafIndexBuffers[i]); } // restore the camera afte getting leaf buffers SpeedTreeWrapper.Camera = saveCam; bounds = new AxisAlignedBox(); // build all the trees and accumulate bounds foreach (Vector3 loc in locations) { SpeedTreeWrapper treeInstance = speedTree.MakeInstance(); treeInstance.OriginalSize = originalSize; Tree t = new Tree(this, treeInstance, loc); bounds.Merge(t.Bounds); trees.Add(t); } boundingRadius = (bounds.Maximum - bounds.Minimum).Length / 2; // create the buckets branchBuckets = new Dictionary<int, List<Tree>>[nBranchLODs]; frondBuckets = new Dictionary<int, List<Tree>>[nFrondLODs]; leafBuckets = new Dictionary<int, List<Tree>>[nLeafLODs]; billboardBucket = new Dictionary<int, List<Tree>>[1]; // initialize the bucket dictionaries for (int i = 0; i < nBranchLODs; i++) { branchBuckets[i] = new Dictionary<int, List<Tree>>(); } for (int i = 0; i < nFrondLODs; i++) { frondBuckets[i] = new Dictionary<int, List<Tree>>(); } for (int i = 0; i < nLeafLODs; i++) { leafBuckets[i] = new Dictionary<int, List<Tree>>(); } billboardBucket[0] = new Dictionary<int, List<Tree>>(); allGroups.Add(this); }