123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- //
- // The graphics engine GXScene https://github.com/glscene
- //
- unit GXS.MeshCSG;
- (*
- Constructive Solid Geometry in Scene.
- The CSG system uses BSP to optimize what triangles it considers.
- Its kept on a mesh basis to simplyfy things, it allways generates new BSP's,
- even if the meshes allready had BSP optimization.
- Features: CSG_Union, CSG_Subtraction, CSG_Intersection.
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- System.SysUtils,
- System.Classes,
- System.Math,
-
- GXS.Scene,
- Stage.VectorTypes,
- GXS.VectorFileObjects,
- Stage.VectorGeometry,
- GXS.BSP,
- GXS.VectorLists;
- type
- TCSGOperation = (CSG_Union, CSG_Subtraction, CSG_Intersection);
- procedure CSG_Operation(obj1, obj2: TgxMeshObject; Operation: TCSGOperation; Res: TgxMeshObject; const MaterialName1, MaterialName2: string);
- //----------------------------------------------------------------------
- implementation
- //----------------------------------------------------------------------
- const
- cOwnTriangleEpsilon = 1e-5;
- function IntersectPointToPointLinePlane(const point1, point2: TAffineVector; const plane: THmgPlane; intersectPoint: PAffineVector = nil): Boolean;
- var
- a, b: Extended;
- t: Single;
- Direction: TAffineVector;
- begin
- Result := False;
- VectorSubtract(Point2, Point1, Direction);
- a := VectorDotProduct(plane, Direction); // direction projected to plane normal
- if a <> 0 then
- begin // direction is parallel to plane
- b := PlaneEvaluatePoint(plane, point1); // distance to plane
- t := -b / a; // parameter of intersection
- Result := (t - EPSILON2 > 0) and (t + EPSILON2 < 1);
- if Result and (intersectPoint <> nil) then
- begin
- intersectPoint^ := VectorCombine(Point1, Direction, 1, t);
- if VectorEquals(intersectPoint^, point1) or VectorEquals(intersectPoint^, point2) then
- Result := False;
- end;
- end;
- end;
- type
- TCSGTri = array[0..2] of PAffineVector;
- function MakeCSGTri(const V1, V2, V3: PAffineVector): TCSGTri;
- begin
- Result[0] := v1;
- Result[1] := v2;
- Result[2] := v3;
- end;
- procedure CSG_Iterate_tri(const vec, nor: TCSGTri; BSP: TBSPMeshObject;
- Node: TFGBSPNode; ResMesh: TgxMeshObject; ResFG: TFGVertexNormalTexIndexList; keepinside, keepoutside, inverttriangle: Boolean);
- var
- vertex_offset: Integer;
- function Iterate_further(const vec, nor: TCSGTri; Node: TFGBSPNode): Boolean;
- function MustSplit(d1, d2, d3: Single): Integer;
- var
- side: Integer;
- function Ok(Int: Single): Boolean;
- begin
- Result := False;
- if Int < 0 then
- begin
- if Side > 0 then
- begin
- Result := True;
- Exit;
- end
- else
- Side := -1;
- end
- else if Int > 0 then
- begin
- if Side < 0 then
- begin
- Result := True;
- Exit;
- end
- else
- Side := 1;
- end;
- end;
- begin
- Result := 0; // no split
- side := 0;
- Ok(D1); // can't go wrong yet...
- if Ok(D2) then
- begin
- Result := 1; // pure split.
- Exit;
- end;
- if Ok(D3) then
- begin
- Result := 1; // pure split.
- Exit;
- end;
- if side = 0 then
- begin
- Result := 2; // on plane.
- Exit;
- end;
- end;
- var
- d: array[0..2] of Single;
- i, i1: Integer;
- b1, b2, b3: Boolean;
- intersect_points: array[0..2] of TAffineVector;
- intersect_lines: array[0..2] of Integer;
- intersect_count: Integer;
- p0, p1: Integer;
- NextNode: TFGBSPNode;
- plane: THmgPlane;
- begin
- // This have no effect, however it removes a warning...
- Result := False;
- b1 := False;
- b2 := False;
- b3 := False;
- // This have no effect, however it removes a warning...
- // normally we use the Node.SplitPlane, however on the last branch this is a NullPlane, so we have to calculate it.
- if VectorEquals(Node.SplitPlane, NullHmgVector) then
- plane := PlaneMake(BSP.Vertices[Node.VertexIndices[0]], BSP.Vertices[Node.VertexIndices[1]], BSP.Vertices[Node.VertexIndices[2]])
- else
- plane := Node.SplitPlane;
- // check the three points in the triangle against the plane
- for i := 0 to 2 do
- begin
- d[i] := PlaneEvaluatePoint(plane, Vec[i]^);
- if Abs(d[i]) < cOwnTriangleEpsilon then
- d[i] := 0;
- end;
- // based on points placement determine action
- case MustSplit(d[0], d[1], d[2]) of
- 0: // no split
- if (d[0] + d[1] + d[2] >= 0) then
- begin
- // check for sub node, and either iterate them or stop if none.
- if Node.PositiveSubNodeIndex = 0 then
- Result := keepoutside
- else
- Result := Iterate_further(Vec, nor, TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex]));
- end
- else
- begin
- // check for sub node, and either iterate them or stop if none.
- if Node.NegativeSubNodeIndex = 0 then
- Result := keepinside
- else
- Result := Iterate_further(Vec, nor, TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]));
- end;
- 1: // must split.
- begin
- // determine if 2 or 3 triangles are needed for the split.
- intersect_count := 0;
- for i := 0 to 2 do
- begin
- i1 := (i + 1) mod 3;
- if IntersectPointToPointLinePlane(Vec[i]^, Vec[i1]^, plane, @intersect_points[intersect_count]) then
- begin
- intersect_lines[intersect_count] := i;
- Inc(intersect_count);
- end;
- end;
- // from here of its not thoroughly commented
- // the base concept is isolate the two or three triangles, findout which to keep.
- // If all is kept we can simply return true and the original triangle wont be split.
- // however if only some are needed, we have to return false and add them ourselves...
- case intersect_count of
- 1:
- begin
- // simple split, two tri's
- i := intersect_lines[0];
- i1 := (i + 2) mod 3;
- // cannot be 0, as then intersect_lines[0] would have other value
- if (d[i] > 0) then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b1 := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b1 := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- b1 := Iterate_further(MakeCSGTri(Vec[i], @intersect_points[0], Vec[i1]), MakeCSGTri(Nor[i], Nor[i {}], Nor[i1]), NextNode);
- i := (intersect_lines[0] + 1) mod 3;
- i1 := (i + 1) mod 3;
- // cannot be 0, as then intersect_lines[0] would have other value
- if (d[i] > 0) then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b2 := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b2 := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- b2 := Iterate_further(MakeCSGTri(Vec[i], Vec[i1], @intersect_points[0]), MakeCSGTri(Nor[i], Nor[i1], Nor[i {}]), NextNode);
- Result := b1 and b2;
- if not Result then
- begin
- if B1 then
- begin
- i := intersect_lines[0];
- i1 := (i + 2) mod 3;
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(Vec[i]^, intersect_points[0], Vec[i1]^);
- ResMesh.TexCoords.Add(Vec[i]^, intersect_points[0], Vec[i1]^);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[i]^, -1), VectorScale(Nor[i {}]^, -1), VectorScale(Nor[i1]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[i]^, Nor[i {}]^, Nor[i1]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end
- else if B2 then
- begin
- i := (intersect_lines[0] + 1) mod 3;
- i1 := (i + 1) mod 3;
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(Vec[i]^, Vec[i1]^, intersect_points[0]);
- ResMesh.TexCoords.Add(Vec[i]^, Vec[i1]^, intersect_points[0]);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[i]^, -1), VectorScale(Nor[i {}]^, -1), VectorScale(Nor[i1]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[i]^, Nor[i {}]^, Nor[i1]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end;
- end;
- end;
- 2:
- begin
- // complex split, three tri's
- if intersect_lines[0] + 1 = intersect_lines[1] then
- begin
- p0 := 0;
- p1 := 1;
- end
- else
- begin
- p0 := 1;
- p1 := 0;
- end;
- i := intersect_lines[p0];
- i1 := (i + 2) mod 3;
- // cannot be 0 as then there would be no intersection
- if (d[i] > 0) then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b1 := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b1 := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- b1 := Iterate_further(MakeCSGTri(Vec[i], @intersect_points[p0], Vec[i1]), MakeCSGTri(Nor[i], Nor[i {}], Nor[i1]), NextNode);
- i1 := (i + 1) mod 3;
- // cannot be 0 as then there would be no intersection
- if (d[i1] > 0) then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b2 := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b2 := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- b2 := Iterate_further(MakeCSGTri(@intersect_points[p0], Vec[i1], @intersect_points[p1]), MakeCSGTri(Nor[i1 {}], Nor[i1], Nor[i1 {}]), NextNode);
- i1 := (i + 2) mod 3;
- // cannot be 0 as then there would be no intersection
- if (d[i1] > 0) then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b3 := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- b3 := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- b3 := Iterate_further(MakeCSGTri(@intersect_points[p0], @intersect_points[p1], Vec[i1]), MakeCSGTri(Nor[i1 {}], Nor[i1 {}], Nor[i1]), NextNode);
- Result := b1 and b2 and b3;
- if not Result then
- begin
- if B1 then
- begin
- i1 := (i + 2) mod 3;
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(Vec[i]^, intersect_points[p0], Vec[i1]^);
- ResMesh.TexCoords.Add(Vec[i]^, intersect_points[p0], Vec[i1]^);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[i]^, -1), VectorScale(Nor[i {}]^, -1), VectorScale(Nor[i1]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[i]^, Nor[i {}]^, Nor[i1]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end;
- if B2 then
- begin
- i1 := (i + 1) mod 3;
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(intersect_points[p0], Vec[i1]^, intersect_points[p1]);
- ResMesh.TexCoords.Add(intersect_points[p0], Vec[i1]^, intersect_points[p1]);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[i1 {}]^, -1), VectorScale(Nor[i1]^, -1), VectorScale(Nor[i1 {}]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[i1 {}]^, Nor[i1]^, Nor[i1 {}]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end;
- if B3 then
- begin
- i1 := (i + 2) mod 3;
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(intersect_points[p0], intersect_points[p1], Vec[i1]^);
- ResMesh.TexCoords.Add(intersect_points[p0], intersect_points[p1], Vec[i1]^);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[i1 {}]^, -1), VectorScale(Nor[i1 {}]^, -1), VectorScale(Nor[i1]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[i1 {}]^, Nor[i1 {}]^, Nor[i1]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end;
- end;
- end;
- end;
- end;
- 2: // on plane, no split but special logic
- begin
- // find out if they point the same direction.
- d[0] := PlaneEvaluatePoint(Plane, VectorAdd(Vec[0]^, Nor[0]^));
- // check for sub node, and either iterate them or stop if none.
- if d[0] >= 0 then
- if Node.PositiveSubNodeIndex = 0 then
- begin
- NextNode := nil;
- Result := keepoutside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.PositiveSubNodeIndex])
- else if Node.NegativeSubNodeIndex = 0 then
- begin
- NextNode := nil;
- Result := keepinside;
- end
- else
- NextNode := TFGBSPNode(BSP.FaceGroups[Node.NegativeSubNodeIndex]);
- if NextNode <> nil then
- Result := Iterate_further(Vec, Nor, NextNode);
- end;
- end;
- end;
- begin
- // check this triangle.
- if Iterate_Further(Vec, nor, Node) then
- begin
- // Keep this triangle, logic based on the (keepinside, keepoutside) booleans.
- vertex_offset := ResMesh.Vertices.count;
- ResMesh.Vertices.Add(Vec[0]^, Vec[1]^, Vec[2]^);
- ResMesh.TexCoords.Add(Vec[0]^, Vec[1]^, Vec[2]^);
- if inverttriangle then
- begin
- ResMesh.Normals.Add(VectorScale(Nor[0]^, -1), VectorScale(Nor[1]^, -1), VectorScale(Nor[2]^, -1));
- ResFG.VertexIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.NormalIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- ResFG.TexCoordIndices.Add(vertex_offset + 2, vertex_offset + 1, vertex_offset);
- end
- else
- begin
- ResMesh.Normals.Add(Nor[0]^, Nor[1]^, Nor[2]^);
- ResFG.VertexIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.NormalIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- ResFG.TexCoordIndices.Add(vertex_offset, vertex_offset + 1, vertex_offset + 2);
- end;
- end;
- end;
- procedure CSG_Operation(obj1, obj2: TgxMeshObject; Operation: TCSGOperation;
- Res: TgxMeshObject; const MaterialName1, MaterialName2: string);
- var
- v1, t1, n1: TgxAffineVectorList;
- v2, t2, n2: TgxAffineVectorList;
- BSP1, BSP2: TBSPMeshObject;
- FG1, FG2: TFGBSPNode;
- i: Integer;
- FGR: TFGVertexNormalTexIndexList;
- begin
- // prepare containers, fill the triangle list from the objects
- BSP1 := TBSPMeshObject.Create;
- BSP2 := TBSPMeshObject.Create;
- BSP1.Mode := momFaceGroups;
- BSP2.Mode := momFaceGroups;
- FG1 := TFGBSPNode.CreateOwned(BSP1.FaceGroups);
- FG2 := TFGBSPNode.CreateOwned(BSP2.FaceGroups);
- t1 := TgxAffineVectorList.create;
- n1 := TgxAffineVectorList.create;
- v1 := obj1.ExtractTriangles(t1, n1);
- v1.TransformAsPoints(obj1.Owner.Owner.Matrix^);
- BSP1.Mode := momTriangles;
- BSP1.Vertices := v1;
- BSP1.Normals := n1;
- BSP1.TexCoords := t1;
- FG1.VertexIndices.AddSerie(0, 1, BSP1.Vertices.Count);
- t2 := TgxAffineVectorList.create;
- n2 := TgxAffineVectorList.create;
- v2 := obj2.ExtractTriangles(t2, n2);
- v2.TransformAsPoints(obj2.Owner.Owner.Matrix^);
- BSP2.Mode := momTriangles;
- BSP2.Vertices := v2;
- BSP2.Normals := n2;
- BSP2.TexCoords := t2;
- FG2.VertexIndices.AddSerie(0, 1, BSP2.Vertices.Count);
- // Build BSPs
- FG1.PerformSplit(FG1.FindSplitPlane, 1);
- FG2.PerformSplit(FG2.FindSplitPlane, 1);
- // Start creating result.
- FGR := TFGVertexNormalTexIndexList.CreateOwned(Res.FaceGroups);
- FGR.MaterialName := MaterialName1;
- // should be obj1.FaceGroups iteration for perfection and multiple materials!
- // First iterate all triangles of object 1, one at a time, down through the BSP tree of Object 2, the last booleans are the key to what actuelly happends.
- i := 0;
- while i < v1.Count - 2 do
- begin
- case Operation of
- CSG_Union:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v1.List^[i], @v1.List^[i + 1], @v1.List^[i + 2]), MakeCSGTri(@n1.List^[i], @n1.List^[i + 1], @n1.List^[i + 2]), BSP2, FG2, Res, FGR, false, true, false);
- end;
- CSG_Subtraction:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v1.List^[i], @v1.List^[i + 1], @v1.List^[i + 2]), MakeCSGTri(@n1.List^[i], @n1.List^[i + 1], @n1.List^[i + 2]), BSP2, FG2, Res, FGR, false, true, false);
- end;
- CSG_Intersection:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v1.List^[i], @v1.List^[i + 1], @v1.List^[i + 2]), MakeCSGTri(@n1.List^[i], @n1.List^[i + 1], @n1.List^[i + 2]), BSP2, FG2, Res, FGR, true, false, false);
- end;
- end;
- inc(i, 3);
- end;
- // Then iterate all triangles of object 2, one at a time, down through the BSP tree of Object 1, the last booleans are the key to what actuelly happends.
- FGR := TFGVertexNormalTexIndexList.CreateOwned(Res.FaceGroups);
- FGR.MaterialName := MaterialName2;
- i := 0;
- while i < v2.Count - 2 do
- begin
- case Operation of
- CSG_Union:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v2.List^[i], @v2.List^[i + 1], @v2.List^[i + 2]), MakeCSGTri(@n2.List^[i], @n2.List^[i + 1], @n2.List^[i + 2]), BSP1, FG1, Res, FGR, false, true, false);
- end;
- CSG_Subtraction:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v2.List^[i], @v2.List^[i + 1], @v2.List^[i + 2]), MakeCSGTri(@n2.List^[i], @n2.List^[i + 1], @n2.List^[i + 2]), BSP1, FG1, Res, FGR, true, false, true);
- end;
- CSG_Intersection:
- begin
- CSG_Iterate_tri(MakeCSGTri(@v2.List^[i], @v2.List^[i + 1], @v2.List^[i + 2]), MakeCSGTri(@n2.List^[i], @n2.List^[i + 1], @n2.List^[i + 2]), BSP1, FG1, Res, FGR, true, false, false);
- end;
- end;
- inc(i, 3);
- end;
- // clean up.
- v1.Free;
- n1.Free;
- t1.Free;
- v2.Free;
- n2.Free;
- t2.Free;
- BSP2.Free;
- BSP1.Free;
- end;
- end.
|