public void Dig(CsgNode shape, BoundingSphere shapeBoundary, DigMode digMode, IEnumerable <int> materialFilter) { CsgNode digShape = null; // constraintDiffNode performs the constraint as a CSG operation // by cutting away anything of thge digging shape not inside the allowed area. CsgOpDiff constraintDiffNode = new CsgOpDiff(); // Assemble difference operation by applying all drone constraints. player.AddDroneConstraints(constraintDiffNode, shapeBoundary.Center); // When placing material, add a safety margin around the player to prevent it from physically glitching trough the terrain if (digMode == DigMode.Add) { playerNode.SetParameterFloat("playerRadius", player.Character.CharacterDiameter * 0.5f + 0.2f); playerNode.SetParameterVec3("playerPosition", player.Character.Position); playerNode.SetParameterVec3("digDirX", new vec3(1, 0, 0)); playerNode.SetParameterVec3("digDirZ", new vec3(0, 0, 1)); playerNode.SetParameterVec3("digDirY", new vec3(0, 0, player.Character.BodyHeight * 0.5f + 0.2f)); constraintDiffNode.AddNode(playerNode); } // We apply the constraint by substracting it from the given shape. CsgOpConcat constraintedShape = new CsgOpConcat(); constraintedShape.AddNode(shape); constraintedShape.AddNode(constraintDiffNode); digShape = constraintedShape; CsgNode digNode = null; // Depending on the digging mode, we either add or substract the digging shape from the terrain. if (digMode == DigMode.Substract) { digNode = new CsgOpDiff(digShape); } else { digNode = new CsgOpUnion(digShape); } // Filter for tools CsgNode filterNode = digNode; if (materialFilter != null) { CsgFilterNode filter = new CsgFilterNode(true, digNode); foreach (int mat in materialFilter) { filter.AddMaterial(mat); } filter.AddMaterial(0); // Air must be white-listed, too! filterNode = filter; } // Float elimination CsgOpConcat collapser = new CsgOpConcat(filterNode); collapser.AddNode(new CsgCollapseNode()); // Callback for statistical purposes. CsgStatCallback finalNode = new CsgStatCallback(collapser, 4, 4); finalNode.AddSimpleVolumeCallback("UpvoidMiner", UpvoidMiner.ModDomain, "UpvoidMiner.DiggingController", "StatCallback"); finalNode.AddVolumeChangePointCallback("UpvoidMiner", UpvoidMiner.ModDomain, "UpvoidMiner.DiggingController", "PointCallback"); world.Terrain.ModifyTerrain(shapeBoundary, finalNode); }
/// <summary> /// Creates the CSG node network for the terrain generation. /// </returns> public CsgNode createTerrain() { // Load and return a CsgNode based on the "Hills" expression resource. This will create some generic perlin-based hills. CsgOpConcat concat = new CsgOpConcat(); { CsgOpUnion union = new CsgOpUnion(); StringBuilder hillsDefines = new StringBuilder(); // Introduce variables. hillsDefines.Append("pos = vec3(x, y, z);"); // Import perlin noise. hillsDefines.Append("perlins(x,y,z) $= ::Perlin;"); hillsDefines.Append("perlin(v) = perlins(v.x, v.y, v.z);"); // Hill structue. //hillsDefines.Append("Hills = perlins(x / 300, 0.00001 * y, z / 300) + perlins(x / 100, 0.00001 * y, z / 100) * .5 + perlins(x / 30, 0.00001 * y, z / 30) * .25 + perlins(x / 10, 0.00001 * y, z / 10) * .05;"); hillsDefines.Append("Hills = perlins(x / 300, y / 300, z / 300) + perlins(x / 100, y / 100, z / 100) * .5 + perlins(x / 30, y / 30, z / 30) * .25 + perlins(x / 10, y / 10, z / 10) * .05;"); hillsDefines.Append("Hills = (Hills + 1).pow2 * 50;"); string hillsDef = hillsDefines.ToString(); CsgOpConcat groundTerrain = new CsgOpConcat(); { CsgOpUnion groundTerrainFull = new CsgOpUnion(); groundTerrainFull.AddNode(new CsgExpression(terrainDirt.Index, "-1", UpvoidMiner.ModDomain)); groundTerrainFull.AddNode(new CsgExpression(terrainDesert.Index, hillsDef + "3 * perlins(x / 300, z / 300, y / 100)", UpvoidMiner.ModDomain)); CsgOpDiff groundTerrainDiff = new CsgOpDiff(); groundTerrainDiff.AddNode(new CsgExpression(1, "-y-90", UpvoidMiner.ModDomain)); groundTerrain.AddNode(groundTerrainFull); groundTerrain.AddNode(groundTerrainDiff); } union.AddNode(new CsgExpression(terrainDirt.Index, hillsDef + "y + Hills", UpvoidMiner.ModDomain)); union.AddNode(groundTerrain); union.AddNode(new CsgExpression(terrainRock.Index, hillsDef + "y + Hills + (5 + perlins(x / 5, z / 6, y / 7) * 3 + perlins(z / 45, y / 46, x / 47) * 13)", UpvoidMiner.ModDomain)); concat.AddNode(union); } { CsgOpDiff diff = new CsgOpDiff(); StringBuilder caveDefines = new StringBuilder(); // Introduce variables. caveDefines.Append("pos = vec3(x, y, z);"); // Import perlin noise. caveDefines.Append("perlins(x,y,z) $= ::Perlin;"); caveDefines.Append("perlin(v) = perlins(v.x, v.y, v.z);"); // Cave structue. //hillsDefines.Append("Hills = perlins(x / 300, 0.00001 * y, z / 300) + perlins(x / 100, 0.00001 * y, z / 100) * .5 + perlins(x / 30, 0.00001 * y, z / 30) * .25 + perlins(x / 10, 0.00001 * y, z / 10) * .05;"); caveDefines.Append("CaveDensity = clamp(perlins(x / 30, y / 30, z / 30) * 4, 0, 1);"); caveDefines.Append("CaveDensity = CaveDensity * clamp((y + 100) * .2, 0, 1);"); caveDefines.Append("Caves = (perlins(x / 17, y / 17, z / 17) + perlins(x / 6, y / 6, z / 6) * .5 - .2) + (5 - CaveDensity * 5);"); string caveDef = caveDefines.ToString(); diff.AddNode(new CsgExpression(1, caveDef + "Caves", UpvoidMiner.ModDomain)); concat.AddNode(diff); } //concat.AddNode(new CsgAutomatonNode(Resources.UseAutomaton("Trees", UpvoidMiner.ModDomain), world, 4)); //concat.AddNode(new CsgAutomatonNode(Resources.UseAutomaton("Cacti", UpvoidMiner.ModDomain), world, 4)); //concat.AddNode(new CsgAutomatonNode(Resources.UseAutomaton("Surface", UpvoidMiner.ModDomain), world, 4)); concat.AddNode(new CsgCollapseNode()); return(concat); }