public BrushMeshInstance CreateCube(int userID) { BrushMesh cube = RealtimeCSG.Legacy.BrushFactory.CreateCube(Vector3.one); BrushMeshInstance cubeMeshInstance = BrushMeshInstance.Create(cube, userID); return(cubeMeshInstance); }
public void CreateBrushMeshInstanceFromBrushMesh() { BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, null); BrushMeshInstance coreBrushMesh = BrushMeshInstance.Create(brushMesh); Assert.AreEqual(true, coreBrushMesh.Valid); }
public void Clear() { if (brushMesh == null) { brushMesh = new BrushMesh(); } polygons = null; }
public void DestroyBrushMeshInstance() { BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, null); BrushMeshInstance brushMeshInstance = BrushMeshInstance.Create(brushMesh); brushMeshInstance.Destroy(); Assert.AreEqual(false, brushMeshInstance.Valid); }
internal BrushMesh CreateOrUpdateBrushMesh() { if (brushMesh == null) { brushMesh = new BrushMesh(); } // In case a user sets "polygons" to null, for consistency if (polygons == null || polygons.Length == 0) { brushMesh.polygons = null; return(brushMesh); } if (brushMesh.polygons == null || brushMesh.polygons.Length != polygons.Length) { brushMesh.polygons = new BrushMesh.Polygon[polygons.Length]; } var dstPolygons = brushMesh.polygons; for (int i = 0; i < polygons.Length; i++) { if (polygons[i] == null) { Debug.LogError("Polygons[" + i + "] is not initialized."); Clear(); return(brushMesh); } dstPolygons[i].firstEdge = polygons[i].firstEdge; dstPolygons[i].edgeCount = polygons[i].edgeCount; dstPolygons[i].surfaceID = polygons[i].surfaceID; dstPolygons[i].description = polygons[i].description; var surfaceAsset = polygons[i].surfaceAsset; if (surfaceAsset == null) { dstPolygons[i].layers.layerUsage = LayerUsageFlags.None; dstPolygons[i].layers.layerParameter1 = 0; dstPolygons[i].layers.layerParameter2 = 0; continue; } dstPolygons[i].layers.layerUsage = surfaceAsset.LayerUsage; dstPolygons[i].layers.layerParameter1 = surfaceAsset.RenderMaterialInstanceID; dstPolygons[i].layers.layerParameter2 = surfaceAsset.PhysicsMaterialInstanceID; } if (!Validate()) { Clear(); } return(brushMesh); }
static BrushMeshInstance CreateBox(Vector3 size, CSGOperationType operation = CSGOperationType.Additive, Material material = null) { if (material == null) { material = material2; } var brushMaterial = ChiselBrushMaterial.CreateInstance(material); BrushMesh brushMesh = TestUtility.CreateBox(size, brushMaterial); return(BrushMeshInstance.Create(brushMesh)); }
public void CreateBrushMesh() { BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, null); Assert.AreNotEqual(null, brushMesh); Assert.AreNotEqual(null, brushMesh.vertices); Assert.AreNotEqual(null, brushMesh.halfEdges); Assert.AreNotEqual(null, brushMesh.polygons); Assert.AreEqual(8, brushMesh.vertices.Length); Assert.AreEqual(24, brushMesh.halfEdges.Length); Assert.AreEqual(6, brushMesh.polygons.Length); }
public void CreateBrushMeshInstanceFromBrushMesh() { var layers = new SurfaceLayers { layerUsage = LayerUsageFlags.None }; BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, layers); BrushMeshInstance coreBrushMesh = BrushMeshInstance.Create(brushMesh); Assert.AreEqual(true, coreBrushMesh.Valid); }
public void CreateCoreBrushMeshFromControlMesh() { ControlMesh controlMesh; Shape shape; BrushFactory.CreateCubeControlMesh(out controlMesh, out shape, Vector3.one); BrushMesh brushMesh = RealtimeCSG.Legacy.BrushFactory.GenerateFromControlMesh(controlMesh, shape); BrushMeshInstance coreBrushMesh = BrushMeshInstance.Create(brushMesh); Assert.AreEqual(true, coreBrushMesh.Valid); }
public void DestroyBrushMeshInstance() { var layers = new SurfaceLayers { layerUsage = LayerUsageFlags.None }; BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, layers); BrushMeshInstance brushMeshInstance = BrushMeshInstance.Create(brushMesh); brushMeshInstance.Destroy(); Assert.AreEqual(false, brushMeshInstance.Valid); }
static BrushMeshInstance CreateCube(Vector3 size, CSGOperationType operation = CSGOperationType.Additive, Material material = null) { if (material == null) { material = material2; } ControlMesh controlMesh; Shape shape; BrushFactory.CreateCubeControlMesh(out controlMesh, out shape, size, material); BrushMesh brushMesh = RealtimeCSG.Legacy.BrushFactory.GenerateFromControlMesh(controlMesh, shape); return(BrushMeshInstance.Create(brushMesh)); }
static BrushMeshInstance CreateBox(Vector3 size, CSGOperationType operation = CSGOperationType.Additive, Material material = null) { if (material == null) { material = material2; } var layers = new SurfaceLayers { layerUsage = LayerUsageFlags.All, layerParameter1 = (material) ? material.GetInstanceID() : 0 }; BrushMesh brushMesh = TestUtility.CreateBox(size, layers); return(BrushMeshInstance.Create(brushMesh)); }
public void CreateBrushMesh() { var layers = new SurfaceLayers { layerUsage = LayerUsageFlags.None }; BrushMesh brushMesh = TestUtility.CreateBox(Vector3.one, layers); Assert.AreNotEqual(null, brushMesh); Assert.AreNotEqual(null, brushMesh.vertices); Assert.AreNotEqual(null, brushMesh.halfEdges); Assert.AreNotEqual(null, brushMesh.polygons); Assert.AreEqual(8, brushMesh.vertices.Length); Assert.AreEqual(24, brushMesh.halfEdges.Length); Assert.AreEqual(6, brushMesh.polygons.Length); }
public void CreateBrushMeshFromControlMesh() { ControlMesh controlMesh; Shape shape; BrushFactory.CreateCubeControlMesh(out controlMesh, out shape, Vector3.one); BrushMesh brushMesh = RealtimeCSG.Legacy.BrushFactory.GenerateFromControlMesh(controlMesh, shape); Assert.AreNotEqual(null, brushMesh); Assert.AreNotEqual(null, brushMesh.vertices); Assert.AreNotEqual(null, brushMesh.halfEdges); Assert.AreNotEqual(null, brushMesh.polygons); Assert.AreEqual(8, brushMesh.vertices.Length); Assert.AreEqual(24, brushMesh.halfEdges.Length); Assert.AreEqual(6, brushMesh.polygons.Length); }
// Creates a new optimized/fixed brushMesh based on the brushMesh inside of the generator // this will not be copied to the generator until the current operation is complete. // This prevents, for example, dragging an edge over another edge DURING a dragging operation messing things up. void UpdateEditableOutline(ChiselBrush generator, float3[] vertices) { generatorModified = true; var outline = activeOutlines[generator]; var internalBrushMesh = new BrushMesh(outline.brushMesh); // Removes infinitely thin polygons (for instance, when snapping edges to edges) internalBrushMesh.RemoveDegenerateTopology(out outline.edgeRemap, out outline.polygonRemap); internalBrushMesh.CalculatePlanes(); // If the brush is concave, we set the generator to not be valid, so that when we commit, it will be reverted generator.definition.ValidState = !internalBrushMesh.IsConcave() && // TODO: eventually allow concave shapes !internalBrushMesh.IsSelfIntersecting() && internalBrushMesh.HasVolume(); generator.definition.brushOutline = internalBrushMesh; generator.OnValidate(); outline.Rebuild(); }
// Creates a new optimized/fixed brushMesh based on the brushMesh inside of the generator // this will not be copied to the generator until the current operation is complete. // This prevents, for example, dragging an edge over another edge DURING a dragging operation messing things up. void UpdateEditableOutline(ChiselBrushComponent generator) { generatorModified = true; var outline = activeOutlines[generator]; var internalBrushMesh = new BrushMesh(outline.brushMesh); // Removes infinitely thin polygons (for instance, when snapping edges to edges) internalBrushMesh.RemoveDegenerateTopology(out outline.edgeRemap, out outline.polygonRemap); internalBrushMesh.CalculatePlanes(); // If the brush is concave, we set the generator to not be valid, so that when we commit, it will be reverted generator.definition.ValidState = internalBrushMesh.HasVolume() && // TODO: implement this, so we know if a brush is a 0D/1D/2D shape !internalBrushMesh.IsConcave() && // TODO: eventually allow concave shapes !internalBrushMesh.IsSelfIntersecting(); // TODO: in which case this needs to be implemented generator.definition.brushOutline = internalBrushMesh; generator.definition.EnsurePlanarPolygons(); generator.OnValidate(); outline.Rebuild(); }
/// <summary> /// Imports the specified world into the SabreCSG model. /// </summary> /// <param name="model">The model to import into.</param> /// <param name="world">The world to be imported.</param> /// <param name="scale">The scale modifier.</param> public static void Import(Transform rootTransform, MapWorld world) { _conversionScale = 1.0f / _Scale; // create a material searcher to associate materials automatically. MaterialSearcher materialSearcher = new MaterialSearcher(); var mapTransform = CreateGameObjectWithUniqueName(world.mapName, rootTransform); mapTransform.position = Vector3.zero; // Index of entities by trenchbroom id var entitiesById = new Dictionary <int, EntityContainer>(); var layers = new List <EntityContainer>(); for (int e = 0; e < world.Entities.Count; e++) { var entity = world.Entities[e]; //EntityContainer eContainer = null; if (entity.tbId >= 0) { var name = String.IsNullOrEmpty(entity.tbName) ? "Unnamed" : entity.tbName; var t = CreateGameObjectWithUniqueName(name, mapTransform); var eContainer = new EntityContainer(t, entity); entitiesById.Add(entity.tbId, eContainer); if (entity.tbType == "_tb_layer") { layers.Add(eContainer); eContainer.transform.SetParent(null); // unparent until layers are sorted by sort index } } } var defaultLayer = CreateGameObjectWithUniqueName("Default Layer", mapTransform); layers = layers.OrderBy(l => l.entity.tbLayerSortIndex).ToList(); // sort layers by layer sort index foreach (var l in layers) { l.transform.SetParent(mapTransform); // parent layers to map in order } bool valveFormat = world.valveFormat; // iterate through all entities. for (int e = 0; e < world.Entities.Count; e++) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("Importing Quake 1 Map", "Converting Quake 1 Entities To Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count); #endif MapEntity entity = world.Entities[e]; Transform brushParent = mapTransform; bool isLayer = false; bool isTrigger = false; if (entity.ClassName == "worldspawn") { brushParent = defaultLayer; } else if (entity.tbType == "_tb_layer") { isLayer = true; if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer)) { brushParent = eContainer.transform; } } else if (entity.tbType == "_tb_group") { if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer)) { brushParent = eContainer.transform; } } else { if (entity.ClassName.Contains("trigger")) { isTrigger = true; } brushParent = CreateGameObjectWithUniqueName(entity.ClassName, mapTransform); } if (brushParent != mapTransform && brushParent != defaultLayer) { if (entity.tbGroup > 0) { if (entitiesById.TryGetValue(entity.tbGroup, out EntityContainer eContainer)) { brushParent.SetParent(eContainer.transform); } } else if (entity.tbLayer > 0) { if (entitiesById.TryGetValue(entity.tbLayer, out EntityContainer eContainer)) { brushParent.SetParent(eContainer.transform); } } else if (!isLayer) { brushParent.SetParent(defaultLayer); } } //if(entity.) if (entity.Brushes.Count == 0) { continue; } var model = ChiselModelManager.CreateNewModel(brushParent); // var model = OperationsUtility.CreateModelInstanceInScene(brushParent); var parent = model.transform; if (isTrigger) { //model.Settings = (model.Settings | ModelSettingsFlags.IsTrigger | ModelSettingsFlags.SetColliderConvex | ModelSettingsFlags.DoNotRender); } // iterate through all entity brushes. for (int i = 0; i < entity.Brushes.Count; i++) { MapBrush brush = entity.Brushes[i]; // build a very large cube brush. ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model); go.definition.surfaceDefinition = new ChiselSurfaceDefinition(); go.definition.surfaceDefinition.EnsureSize(6); BrushMesh brushMesh = new BrushMesh(); go.definition.brushOutline = brushMesh; BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition); // prepare for uv calculations of clip planes after cutting. var planes = new float4[brush.Sides.Count]; var planeSurfaces = new ChiselSurface[brush.Sides.Count]; // compute all the sides of the brush that will be clipped. for (int j = brush.Sides.Count; j-- > 0;) { MapBrushSide side = brush.Sides[j]; // detect excluded polygons. //if (IsExcludedMaterial(side.Material)) //polygon.UserExcludeFromFinal = true; // detect collision-only brushes. //if (IsInvisibleMaterial(side.Material)) //pr.IsVisible = false; // find the material in the unity project automatically. Material material; string materialName = side.Material.Replace("*", "#"); material = materialSearcher.FindMaterial(new string[] { materialName }); if (material == null) { material = ChiselMaterialManager.DefaultFloorMaterial; } // create chisel surface for the clip. ChiselSurface surface = new ChiselSurface(); surface.brushMaterial = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial); surface.surfaceDescription = SurfaceDescription.Default; // detect collision-only polygons. if (IsInvisibleMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows; } // detect excluded polygons. if (IsExcludedMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows; surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable; } // calculate the clipping planes. Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * _conversionScale), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * _conversionScale), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * _conversionScale)); planes[j] = new float4(clip.normal, clip.distance); planeSurfaces[j] = surface; } // cut all the clipping planes out of the brush in one go. brushMesh.Cut(planes, planeSurfaces); // now iterate over the planes to calculate UV coordinates. int[] indices = new int[brush.Sides.Count]; for (int k = 0; k < planes.Length; k++) { var plane = planes[k]; int closestIndex = 0; float closestDistance = math.lengthsq(plane - brushMesh.planes[0]); for (int j = 1; j < brushMesh.planes.Length; j++) { float testDistance = math.lengthsq(plane - brushMesh.planes[j]); if (testDistance < closestDistance) { closestIndex = j; closestDistance = testDistance; } } indices[k] = closestIndex; } for (int j = 0; j < indices.Length; j++) { brushMesh.planes[indices[j]] = planes[j]; } for (int j = brush.Sides.Count; j-- > 0;) { MapBrushSide side = brush.Sides[j]; var surface = brushMesh.polygons[indices[j]].surface; var material = surface.brushMaterial.RenderMaterial; // calculate the texture coordinates. int w = 256; int h = 256; if (material.mainTexture != null) { w = material.mainTexture.width; h = material.mainTexture.height; } var clip = new Plane(planes[j].xyz, planes[j].w); if (world.valveFormat) { var uAxis = new VmfAxis(side.t1, side.Offset.X, side.Scale.X); var vAxis = new VmfAxis(side.t2, side.Offset.Y, side.Scale.Y); CalculateTextureCoordinates(go, surface, clip, w, h, uAxis, vAxis); } else { if (GetTextureAxises(clip, out MapVector3 t1, out MapVector3 t2)) { var uAxis = new VmfAxis(t1, side.Offset.X, side.Scale.X); var vAxis = new VmfAxis(t2, side.Offset.Y, side.Scale.Y); CalculateTextureCoordinates(go, surface, clip, w, h, uAxis, vAxis); } } } try { // finalize the brush by snapping planes and centering the pivot point. go.transform.position += brushMesh.CenterAndSnapPlanes(); } catch { // Brush failed, destroy brush GameObject.DestroyImmediate(go); } } } #if UNITY_EDITOR UnityEditor.EditorUtility.ClearProgressBar(); #endif }
public static void CreateBox(Vector3 size, ChiselBrushMaterial brushMaterial, out BrushMesh box) { var chiselSurface = new ChiselSurface(); chiselSurface.brushMaterial = brushMaterial; BrushMeshFactory.CreateBox(Vector3.one, in chiselSurface, out box); }
/// <summary> /// Imports the specified world into the Chisel model. /// </summary> /// <param name="model">The model to import into.</param> /// <param name="world">The world to be imported.</param> public static void Import(ChiselModel model, VmfWorld world) { // create a material searcher to associate materials automatically. MaterialSearcher materialSearcher = new MaterialSearcher(); HashSet <string> materialSearcherWarnings = new HashSet <string>(); // iterate through all world solids. for (int i = 0; i < world.Solids.Count; i++) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map (1/3)", "Converting Hammer Solids To Chisel Brushes (" + (i + 1) + " / " + world.Solids.Count + ")...", i / (float)world.Solids.Count); #endif VmfSolid solid = world.Solids[i]; // don't add triggers to the scene. if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material)) { continue; } // HACK: Fix me in the future! // HACK: Chisel doesn't support collision brushes yet- skip them completely! if (solid.Sides.Count > 0 && IsInvisibleMaterial(solid.Sides[0].Material)) { continue; } // HACK: Fix me in the future! // build a very large cube brush. ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model); go.definition.surfaceDefinition = new ChiselSurfaceDefinition(); go.definition.surfaceDefinition.EnsureSize(6); BrushMesh brushMesh = new BrushMesh(); go.definition.brushOutline = brushMesh; BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition); // prepare for any displacements. List <DisplacementSide> DisplacementSurfaces = new List <DisplacementSide>(); // prepare for uv calculations of clip planes after cutting. var planes = new float4[solid.Sides.Count]; var planeSurfaces = new ChiselSurface[solid.Sides.Count]; // compute all the sides of the brush that will be clipped. for (int j = solid.Sides.Count; j-- > 0;) { VmfSolidSide side = solid.Sides[j]; // detect excluded polygons. //if (IsExcludedMaterial(side.Material)) //polygon.UserExcludeFromFinal = true; // detect collision-only brushes. //if (IsInvisibleMaterial(side.Material)) //pr.IsVisible = false; // find the material in the unity project automatically. Material material; // try finding the fully qualified texture name with '/' replaced by '.' so 'BRICK.BRICKWALL052D'. string materialName = side.Material.Replace("/", "."); if (materialName.Contains(".")) { // try finding both 'BRICK.BRICKWALL052D' and 'BRICKWALL052D'. string tiny = materialName.Substring(materialName.LastIndexOf('.') + 1); material = materialSearcher.FindMaterial(new string[] { materialName, tiny }); if (material == null && materialSearcherWarnings.Add(materialName)) { Debug.Log("Chisel: Tried to find material '" + materialName + "' and also as '" + tiny + "' but it couldn't be found in the project."); } } else { // only try finding 'BRICKWALL052D'. material = materialSearcher.FindMaterial(new string[] { materialName }); if (material == null && materialSearcherWarnings.Add(materialName)) { Debug.Log("Chisel: Tried to find material '" + materialName + "' but it couldn't be found in the project."); } } // fallback to default material. if (material == null) { material = ChiselMaterialManager.DefaultFloorMaterial; } // create chisel surface for the clip. ChiselSurface surface = new ChiselSurface(); surface.brushMaterial = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial); surface.surfaceDescription = SurfaceDescription.Default; // detect collision-only polygons. if (IsInvisibleMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows; } // detect excluded polygons. if (IsExcludedMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows; surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable; } // calculate the clipping planes. Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * inchesInMeters)); planes[j] = new float4(clip.normal, clip.distance); planeSurfaces[j] = surface; // check whether this surface is a displacement. if (side.Displacement != null) { // disable the brush. go.gameObject.GetComponent <ChiselBrush>().enabled = false; // keep track of the surface used to cut the mesh. DisplacementSurfaces.Add(new DisplacementSide { side = side, surface = surface }); } } // cut all the clipping planes out of the brush in one go. brushMesh.Cut(planes, planeSurfaces); // now iterate over the planes to calculate UV coordinates. int[] indices = new int[solid.Sides.Count]; for (int k = 0; k < planes.Length; k++) { var plane = planes[k]; int closestIndex = 0; float closestDistance = math.lengthsq(plane - brushMesh.planes[0]); for (int j = 1; j < brushMesh.planes.Length; j++) { float testDistance = math.lengthsq(plane - brushMesh.planes[j]); if (testDistance < closestDistance) { closestIndex = j; closestDistance = testDistance; } } indices[k] = closestIndex; } for (int j = 0; j < indices.Length; j++) { brushMesh.planes[indices[j]] = planes[j]; } for (int j = solid.Sides.Count; j-- > 0;) { VmfSolidSide side = solid.Sides[j]; var surface = brushMesh.polygons[indices[j]].surface; var material = surface.brushMaterial.RenderMaterial; // calculate the texture coordinates. int w = 256; int h = 256; if (material.mainTexture != null) { w = material.mainTexture.width; h = material.mainTexture.height; } var clip = new Plane(planes[j].xyz, planes[j].w); CalculateTextureCoordinates(go, surface, clip, w, h, side.UAxis, side.VAxis); } // build displacements. foreach (DisplacementSide displacement in DisplacementSurfaces) { // find the brush mesh polygon: for (int polyidx = 0; polyidx < brushMesh.polygons.Length; polyidx++) { if (brushMesh.polygons[polyidx].surface == displacement.surface) { // find the polygon plane. Plane plane = new Plane(brushMesh.planes[polyidx].xyz, brushMesh.planes[polyidx].w); // find all vertices that belong to this polygon: List <Vector3> vertices = new List <Vector3>(); { var polygon = brushMesh.polygons[polyidx]; var firstEdge = polygon.firstEdge; var edgeCount = polygon.edgeCount; var lastEdge = firstEdge + edgeCount; for (int e = firstEdge; e < lastEdge; e++) { vertices.Add(brushMesh.vertices[brushMesh.halfEdges[e].vertexIndex]); } } // reverse the winding order. vertices.Reverse(); var first = vertices[0]; vertices.RemoveAt(0); vertices.Add(first); // build displacement: BuildDisplacementSurface(go, displacement.side, displacement.surface, vertices, plane); } } } // finalize the brush by snapping planes and centering the pivot point. go.transform.position += brushMesh.CenterAndSnapPlanes(); foreach (Transform child in go.transform) { child.position -= go.transform.position; } } // iterate through all entities. for (int e = 0; e < world.Entities.Count; e++) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map (2/3)", "Converting Hammer Entities To Chisel Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count); #endif VmfEntity entity = world.Entities[e]; // skip entities that chisel can't handle. switch (entity.ClassName) { case "func_areaportal": case "func_areaportalwindow": case "func_capturezone": case "func_changeclass": case "func_combine_ball_spawner": case "func_dustcloud": case "func_dustmotes": case "func_nobuild": case "func_nogrenades": case "func_occluder": case "func_precipitation": case "func_proprespawnzone": case "func_regenerate": case "func_respawnroom": case "func_smokevolume": case "func_viscluster": continue; } // iterate through all entity solids. for (int i = 0; i < entity.Solids.Count; i++) { VmfSolid solid = entity.Solids[i]; // don't add triggers to the scene. if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material)) { continue; } // HACK: Fix me in the future! // HACK: Chisel doesn't support collision brushes yet- skip them completely! if (solid.Sides.Count > 0 && IsInvisibleMaterial(solid.Sides[0].Material)) { continue; } // HACK: Fix me in the future! // build a very large cube brush. ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model); go.definition.surfaceDefinition = new ChiselSurfaceDefinition(); go.definition.surfaceDefinition.EnsureSize(6); BrushMesh brushMesh = new BrushMesh(); go.definition.brushOutline = brushMesh; BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition); // prepare for uv calculations of clip planes after cutting. var planes = new float4[solid.Sides.Count]; var planeSurfaces = new ChiselSurface[solid.Sides.Count]; // clip all the sides out of the brush. for (int j = solid.Sides.Count; j-- > 0;) { VmfSolidSide side = solid.Sides[j]; // detect excluded polygons. //if (IsExcludedMaterial(side.Material)) // polygon.UserExcludeFromFinal = true; // detect collision-only brushes. //if (IsInvisibleMaterial(side.Material)) // pr.IsVisible = false; // find the material in the unity project automatically. Material material; // try finding the fully qualified texture name with '/' replaced by '.' so 'BRICK.BRICKWALL052D'. string materialName = side.Material.Replace("/", "."); if (materialName.Contains(".")) { // try finding both 'BRICK.BRICKWALL052D' and 'BRICKWALL052D'. string tiny = materialName.Substring(materialName.LastIndexOf('.') + 1); material = materialSearcher.FindMaterial(new string[] { materialName, tiny }); if (material == null && materialSearcherWarnings.Add(materialName)) { Debug.Log("Chisel: Tried to find material '" + materialName + "' and also as '" + tiny + "' but it couldn't be found in the project."); } } else { // only try finding 'BRICKWALL052D'. material = materialSearcher.FindMaterial(new string[] { materialName }); if (material == null && materialSearcherWarnings.Add(materialName)) { Debug.Log("Chisel: Tried to find material '" + materialName + "' but it couldn't be found in the project."); } } // fallback to default material. if (material == null) { material = ChiselMaterialManager.DefaultFloorMaterial; } // create chisel surface for the clip. ChiselSurface surface = new ChiselSurface(); surface.brushMaterial = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial); surface.surfaceDescription = SurfaceDescription.Default; // detect collision-only polygons. if (IsInvisibleMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows; } // detect excluded polygons. if (IsExcludedMaterial(side.Material)) { surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows; surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable; } // calculate the clipping planes. Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * inchesInMeters)); planes[j] = new float4(clip.normal, clip.distance); planeSurfaces[j] = surface; } // cut all the clipping planes out of the brush in one go. brushMesh.Cut(planes, planeSurfaces); // now iterate over the planes to calculate UV coordinates. int[] indices = new int[solid.Sides.Count]; for (int k = 0; k < planes.Length; k++) { var plane = planes[k]; int closestIndex = 0; float closestDistance = math.lengthsq(plane - brushMesh.planes[0]); for (int j = 1; j < brushMesh.planes.Length; j++) { float testDistance = math.lengthsq(plane - brushMesh.planes[j]); if (testDistance < closestDistance) { closestIndex = j; closestDistance = testDistance; } } indices[k] = closestIndex; } for (int j = 0; j < indices.Length; j++) { brushMesh.planes[indices[j]] = planes[j]; } for (int j = solid.Sides.Count; j-- > 0;) { VmfSolidSide side = solid.Sides[j]; var surface = brushMesh.polygons[indices[j]].surface; var material = surface.brushMaterial.RenderMaterial; // calculate the texture coordinates. int w = 256; int h = 256; if (material.mainTexture != null) { w = material.mainTexture.width; h = material.mainTexture.height; } var clip = new Plane(planes[j].xyz, planes[j].w); CalculateTextureCoordinates(go, surface, clip, w, h, side.UAxis, side.VAxis); } // finalize the brush by snapping planes and centering the pivot point. go.transform.position += brushMesh.CenterAndSnapPlanes(); // detail brushes that do not affect the CSG world. //if (entity.ClassName == "func_detail") //pr.IsNoCSG = true; // collision only brushes. //if (entity.ClassName == "func_vehicleclip") //pr.IsVisible = false; } } }
public static void CreateBox(Vector3 size, int descriptionIndex, out BrushMesh box) { BrushMeshFactory.CreateBox(size, descriptionIndex, out box); }
/// <summary>Converts a <see cref="RealtimeCSG.Legacy.ControlMesh"/>/<see cref="RealtimeCSG.Legacy.Shape"/> pair into a <see cref="RealtimeCSG.Foundation.BrushMesh"/>.</summary> /// <param name="controlMesh">A legacy <see cref="RealtimeCSG.Legacy.ControlMesh"/> that describes the shape of the <see cref="RealtimeCSG.Foundation.BrushMesh"/>.</param> /// <param name="shape">A legacy <see cref="RealtimeCSG.Legacy.Shape"/> that describes the surfaces in the <see cref="RealtimeCSG.Foundation.BrushMesh"/>.</param> /// <returns>A new <see cref="RealtimeCSG.Foundation.BrushMesh"/></returns> public static BrushMesh GenerateFromControlMesh(ControlMesh controlMesh, Shape shape) { if (controlMesh == null || shape == null) { return(null); } if (!ControlMeshUtility.Validate(controlMesh, shape)) { return(null); } var vertices = controlMesh.Vertices; var srcEdges = controlMesh.Edges; var srcPolygons = controlMesh.Polygons; if (vertices == null || srcEdges == null || srcPolygons == null) { return(null); } var surfaces = shape.Surfaces; var texgens = shape.TexGens; var texgenFlags = shape.TexGenFlags; if (surfaces == null || texgens == null || texgenFlags == null) { return(null); } var polygonCount = surfaces.Length; if (polygonCount != srcPolygons.Length || polygonCount != texgens.Length || polygonCount != texgenFlags.Length || polygonCount != surfaces.Length) { return(null); } var brushMesh = new BrushMesh { polygons = new BrushMesh.Polygon[polygonCount], vertices = vertices.ToArray() }; for (int i = 0; i < polygonCount; i++) { var polygonIndex = i; var surface = surfaces[polygonIndex]; var texGenIndex = surface.TexGenIndex; var texGen = texgens[texGenIndex]; var flags = texgenFlags[texGenIndex]; brushMesh.polygons[i].polygonID = polygonIndex; brushMesh.polygons[i].surface = CreateSurfaceDescription(surface, texGen, flags); brushMesh.polygons[i].layers = CreateSurfaceLayer(texGen, flags); } int counter = 0; for (var i = 0; i < polygonCount; i++) { var polygonIndex = i; var edgeIndices = srcPolygons[polygonIndex].EdgeIndices; brushMesh.polygons[i].firstEdge = counter; brushMesh.polygons[i].edgeCount = edgeIndices.Length; counter += edgeIndices.Length; } brushMesh.halfEdges = new BrushMesh.HalfEdge[counter]; counter = 0; for (var i = 0; i < polygonCount; i++) { var polygonIndex = i; var edgeIndices = srcPolygons[polygonIndex].EdgeIndices; for (var v = 0; v < edgeIndices.Length; v++) { var edge = srcEdges[edgeIndices[v]]; brushMesh.halfEdges[counter + v].vertexIndex = edge.VertexIndex; var twinIndex = edge.TwinIndex; var twinPolygonIndex = srcEdges[twinIndex].PolygonIndex; var twinEdges = srcPolygons[twinPolygonIndex].EdgeIndices; var found = false; for (var t = 0; t < twinEdges.Length; t++) { if (twinEdges[t] == twinIndex) { twinIndex = t + brushMesh.polygons[twinPolygonIndex].firstEdge; found = true; break; } } if (!found) { return(null); } brushMesh.halfEdges[counter + v].twinIndex = twinIndex; } counter += edgeIndices.Length; } return(brushMesh); }