better plane clipping algo, also faster

This commit is contained in:
GoaLitiuM
2021-08-31 20:03:23 +03:00
parent 61b244b850
commit f0faac7322
11 changed files with 6761 additions and 117 deletions

View File

@@ -3,32 +3,104 @@
// entity 0
{
"classname" "worldspawn"
"_tb_textures" "textures/common"
"_tb_textures" "textures/common;textures/dev"
// brush 0
{
( 0 0 -16 ) ( 0 1 -16 ) ( 0 0 -15 ) common/slick2 0 0 0 4 4
( 0 0 -16 ) ( 0 0 -15 ) ( 1 0 -16 ) common/slick2 0 0 0 4 4
( 0 0 -512 ) ( 1 0 -512 ) ( 0 1 -512 ) common/slick2 0 0 0 4 4
( 80 64 0 ) ( 80 65 0 ) ( 81 64 0 ) common/slick2 0 0 0 4 4
( 80 512 0 ) ( 81 512 0 ) ( 80 512 1 ) common/slick2 0 0 0 4 4
( 512 64 0 ) ( 512 64 1 ) ( 512 65 0 ) common/slick2 0 0 0 4 4
( 160 301.25483399593907 192 ) ( 160.70710678118655 301.96194077712562 192 ) ( 160 301.25483399593907 193 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 160 210.74516600406099 128 ) ( 159.29289321881339 211.45227278524754 128 ) ( 160 210.74516600406099 129 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 160 210.74516600406099 128 ) ( 160.7071067811865 211.45227278524754 128 ) ( 159.29289321881339 211.45227278524754 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 160 301.25483399593907 192 ) ( 159.29289321881345 301.96194077712562 192 ) ( 160.70710678118655 301.96194077712562 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 160 301.25483399593907 192 ) ( 160 301.25483399593907 193 ) ( 159.29289321881345 301.96194077712562 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 160 210.74516600406099 128 ) ( 160 210.74516600406099 129 ) ( 160.7071067811865 211.45227278524754 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
}
// brush 1
{
( 128 384 128 ) ( 128 385 128 ) ( 128 384 129 ) common/slick2 0 0 0 1 1
( 128 384 128 ) ( 128 384 129 ) ( 129 384 128 ) common/slick2 0 0 0 1 1
( 128 384 128 ) ( 129 384 128 ) ( 128 385 128 ) common/slick2 0 0 0 1 1
( 192 448 192 ) ( 192 449 192 ) ( 193 448 192 ) common/slick2 0 0 0 1 1
( 192 448 192 ) ( 193 448 192 ) ( 192 448 193 ) common/slick2 0 0 0 1 1
( 192 448 192 ) ( 192 448 193 ) ( 192 449 192 ) common/slick2 0 0 0 1 1
( 0 0 -16 ) ( 0 1 -16 ) ( 0 0 -15 ) dev/dev_128_gray 0 0 0 0.25 0.25
( 0 0 -16 ) ( 0 0 -15 ) ( 1 0 -16 ) dev/dev_128_gray 0 0 0 0.25 0.25
( 0 0 -512 ) ( 1 0 -512 ) ( 0 1 -512 ) dev/dev_128_gray 0 0 0 0.25 0.25
( 80 64 0 ) ( 80 65 0 ) ( 81 64 0 ) dev/dev_128_gray 0 0 0 0.25 0.25
( 80 512 0 ) ( 81 512 0 ) ( 80 512 1 ) dev/dev_128_gray 0 0 0 0.25 0.25
( 512 64 0 ) ( 512 64 1 ) ( 512 65 0 ) dev/dev_128_gray 0 0 0 0.25 0.25
}
// brush 2
{
( 256 384 128 ) ( 256 385 128 ) ( 256 384 129 ) common/slick2 0 0 90 1 1
( 256 384 128 ) ( 256 384 129 ) ( 257 384 128 ) common/slick2 0 0 90 1 1
( 256 384 128 ) ( 257 384 128 ) ( 256 385 128 ) common/slick2 0 0 90 1 1
( 320 448 192 ) ( 320 449 192 ) ( 321 448 192 ) common/slick2 0 0 90 1 1
( 320 448 192 ) ( 321 448 192 ) ( 320 448 193 ) common/slick2 0 0 90 1 1
( 320 448 192 ) ( 320 448 193 ) ( 320 449 192 ) common/slick2 0 0 90 1 1
( 128 384 128 ) ( 128 385 128 ) ( 128 384 129 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 128 384 128 ) ( 128 384 129 ) ( 129 384 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 128 384 128 ) ( 129 384 128 ) ( 128 385 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 192 448 192 ) ( 192 449 192 ) ( 193 448 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 192 448 192 ) ( 193 448 192 ) ( 192 448 193 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( 192 448 192 ) ( 192 448 193 ) ( 192 449 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
}
// brush 3
{
( 256 384 128 ) ( 256 385 128 ) ( 256 384 129 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 256 384 128 ) ( 256 384 129 ) ( 257 384 128 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 256 384 128 ) ( 257 384 128 ) ( 256 385 128 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 320 448 192 ) ( 320 449 192 ) ( 321 448 192 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 320 448 192 ) ( 321 448 192 ) ( 320 448 193 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 320 448 192 ) ( 320 448 193 ) ( 320 449 192 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 4
{
( 520.80816411546914 418.42580298272964 123.23396709819883 ) ( 521.06698316057168 419.35881568462185 123.48396709819883 ) ( 520.80816411546914 418.16698393762715 124.1998929244879 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 520.80816411546914 418.42580298272964 123.23396709819883 ) ( 520.80816411546914 418.16698393762715 124.1998929244879 ) ( 521.77408994175812 418.17580298272964 123.16697980009104 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 520.80816411546914 418.42580298272964 123.23396709819883 ) ( 521.77408994175812 418.17580298272964 123.16697980009104 ) ( 521.06698316057168 419.35881568462185 123.48396709819883 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 599.19183588453086 445.57419701727025 196.76603290180122 ) ( 599.4506549296334 446.50720971916252 197.01603290180122 ) ( 600.15776171081995 445.32419701727031 196.69904560369343 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 599.19183588453086 445.57419701727025 196.76603290180122 ) ( 600.15776171081995 445.32419701727031 196.69904560369343 ) ( 599.19183588453086 445.31537797216771 197.73195872809032 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 599.19183588453086 445.57419701727025 196.76603290180122 ) ( 599.19183588453086 445.31537797216771 197.73195872809032 ) ( 599.4506549296334 446.50720971916252 197.01603290180122 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 5
{
( 612.28718707889811 437.85640646055106 126.430780618347 ) ( 612.787187078898 438.60640646055106 126.86379332023921 ) ( 612.28718707889811 437.35640646055106 127.29680602213142 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 612.28718707889811 437.85640646055106 126.430780618347 ) ( 612.28718707889811 437.35640646055106 127.29680602213142 ) ( 613.15321248268242 437.42339375865885 126.180780618347 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 612.28718707889811 437.85640646055106 126.430780618347 ) ( 613.15321248268242 437.42339375865885 126.180780618347 ) ( 612.787187078898 438.60640646055106 126.86379332023921 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 699.71281292110211 426.14359353944894 193.56921938165306 ) ( 700.21281292110211 426.89359353944894 194.00223208354521 ) ( 700.57883832488653 425.71058083755679 193.31921938165306 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 699.71281292110211 426.14359353944894 193.56921938165306 ) ( 700.57883832488653 425.71058083755679 193.31921938165306 ) ( 699.71281292110211 425.64359353944894 194.43524478543748 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 699.71281292110211 426.14359353944894 193.56921938165306 ) ( 699.71281292110211 425.64359353944894 194.43524478543748 ) ( 700.21281292110211 426.89359353944894 194.00223208354521 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 6
{
( 722.74516600406105 454.62741699796953 137.37258300203047 ) ( 723.45227278524749 455.12741699796965 137.87258300203052 ) ( 722.74516600406105 453.92031021678298 138.07968978321702 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 722.74516600406105 454.62741699796953 137.37258300203047 ) ( 722.74516600406105 453.92031021678298 138.07968978321702 ) ( 723.45227278524749 454.12741699796965 136.87258300203052 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 722.74516600406105 454.62741699796953 137.37258300203047 ) ( 723.45227278524749 454.12741699796965 136.87258300203052 ) ( 723.45227278524749 455.12741699796965 137.87258300203052 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 813.25483399593907 409.37258300203052 182.62741699796948 ) ( 813.96194077712562 409.87258300203041 183.12741699796936 ) ( 813.96194077712551 408.87258300203041 182.12741699796936 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 813.25483399593907 409.37258300203052 182.62741699796948 ) ( 813.25483399593907 408.66547622084397 183.33452377915603 ) ( 813.96194077712562 409.87258300203041 183.12741699796936 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 813.25483399593907 409.37258300203052 182.62741699796948 ) ( 813.96194077712551 408.87258300203041 182.12741699796936 ) ( 813.25483399593907 408.66547622084397 183.33452377915603 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 7
{
( 852.28718707889811 465.56921938165306 154.143593539449 ) ( 852.28718707889811 464.70319397786858 154.643593539449 ) ( 852.787187078898 465.1362066797609 153.39359353944911 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 852.28718707889811 465.56921938165306 154.143593539449 ) ( 853.15321248268242 465.81921938165306 154.57660624134127 ) ( 852.28718707889811 464.70319397786858 154.643593539449 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 939.71281292110211 398.43078061834694 165.856406460551 ) ( 940.57883832488653 398.68078061834683 166.28941916244315 ) ( 940.212812921102 397.99776791645468 165.106406460551 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 852.28718707889811 465.56921938165306 154.143593539449 ) ( 852.787187078898 465.1362066797609 153.39359353944911 ) ( 853.15321248268242 465.81921938165306 154.57660624134127 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 939.71281292110211 398.43078061834694 165.856406460551 ) ( 939.71281292110211 397.56475521456252 166.356406460551 ) ( 940.57883832488653 398.68078061834683 166.28941916244315 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 939.71281292110211 398.43078061834694 165.856406460551 ) ( 940.212812921102 397.99776791645468 165.106406460551 ) ( 939.71281292110211 397.56475521456252 166.356406460551 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 8
{
( 964.28718707889811 465.94112549695427 163.03149905570405 ) ( 964.28718707889811 464.97519967066523 163.29031810080659 ) ( 964.787187078898 465.71698162891232 162.19498275196634 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 964.28718707889811 465.94112549695427 163.03149905570405 ) ( 965.15321248268242 466.07053501950554 163.51446196884865 ) ( 964.28718707889811 464.97519967066523 163.29031810080659 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 1051.7128129211021 398.05887450304567 156.96850094429584 ) ( 1052.5788383248864 398.18828402559689 157.45146385744027 ) ( 1052.2128129211019 397.83473063500367 156.13198464055807 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 964.28718707889811 465.94112549695427 163.03149905570405 ) ( 964.787187078898 465.71698162891232 162.19498275196634 ) ( 965.15321248268242 466.07053501950554 163.51446196884865 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 1051.7128129211021 398.05887450304567 156.96850094429584 ) ( 1051.7128129211021 397.09294867675663 157.22731998939838 ) ( 1052.5788383248864 398.18828402559689 157.45146385744027 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
( 1051.7128129211021 398.05887450304567 156.96850094429584 ) ( 1052.2128129211019 397.83473063500367 156.13198464055807 ) ( 1051.7128129211021 397.09294867675663 157.22731998939838 ) dev/dev_128_gray 0 0 90 0.0625 0.0625
}
// brush 9
{
( -591.43664923901133 1103.4463967490024 128 ) ( -591.45410164544865 1104.4462444441588 128 ) ( -591.43664923901133 1103.4463967490024 129 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -528.56335076098844 1168.5536032509976 192 ) ( -527.56350306583204 1168.571055657435 192 ) ( -528.56335076098844 1168.5536032509976 193 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -591.43664923901133 1103.4463967490024 128 ) ( -590.43680154385493 1103.4638491554397 128 ) ( -591.45410164544865 1104.4462444441588 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -528.56335076098844 1168.5536032509976 192 ) ( -528.58080316742576 1169.553450946154 192 ) ( -527.56350306583204 1168.571055657435 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -591.43664923901133 1103.4463967490024 128 ) ( -591.43664923901133 1103.4463967490024 129 ) ( -590.43680154385493 1103.4638491554397 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -528.56335076098844 1168.5536032509976 192 ) ( -528.56335076098844 1168.5536032509976 193 ) ( -528.58080316742576 1169.553450946154 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
}
// brush 10
{
( -671.94410075351652 335.94419823106603 128 ) ( -671.94584608188234 336.94419670797936 128 ) ( -671.94410075351652 335.94419823106603 129 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -608.05589924648348 400.05580176893392 192 ) ( -607.05590076957014 400.05754709729985 192 ) ( -608.05589924648348 400.05580176893392 193 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -671.94410075351652 335.94419823106603 128 ) ( -670.94410227660319 335.94594355943195 128 ) ( -671.94584608188234 336.94419670797936 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -608.05589924648348 400.05580176893392 192 ) ( -608.05764457484941 401.05580024584725 192 ) ( -607.05590076957014 400.05754709729985 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -671.94410075351652 335.94419823106603 128 ) ( -671.94410075351652 335.94419823106603 129 ) ( -670.94410227660319 335.94594355943195 128 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
( -608.05589924648348 400.05580176893392 192 ) ( -608.05589924648348 400.05580176893392 193 ) ( -608.05764457484941 401.05580024584725 192 ) dev/dev_128_gray 0 0 0 0.0625 0.0625
}
}

6285
Assets/Maps/dm4.map Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,8 @@
"GameCooking": "af2e52554f7faed7b4937181dd22d166",
"Streaming": "3a6ffc3a43e684f77cfed1a1f8f6bd0e",
"CustomSettings": {
"BrushMaterials": "29a0b0c54b40eb3e6857ffb4c9cab71e"
"BrushMaterials": "29a0b0c54b40eb3e6857ffb4c9cab71e",
"BrushMaterialsLegacy": "51fb8bec4cfc9095612aaf992382a255"
},
"WindowsPlatform": "4a5eec97484253fed72934860ae62c40",
"UWPPlatform": null,

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,45 @@
{
"ID": "51fb8bec4cfc9095612aaf992382a255",
"TypeName": "Game.BrushMaterialList",
"EngineBuild": 6224,
"Data": {
"materialAssets": [
{
"name": "MMETAL1_3",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "COP1_2",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL1_6",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL6_1",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL1_4",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL5_8",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL1_3",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "METAL6_2",
"asset": "27c0a4c24751fc390dae04b95483f30d"
},
{
"name": "COP1_7",
"asset": "27c0a4c24751fc390dae04b95483f30d"
}
]
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -15,7 +15,6 @@ using Console = Cabrito.Console;
namespace Game
{
public class BrushGeometry
{
public MapBrush brush;
@@ -33,6 +32,7 @@ namespace Game
//private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\cube_q1.map";
private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\cube_q3.map";
//private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\cube_valve.map";
//private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\dm4.map";
//private string mapPath = @"C:\dev\Goake\maps\aerowalk\aerowalk.map";
//private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\problematic.map";
@@ -56,9 +56,6 @@ namespace Game
var calc = new ConvexHullCalculator();
calc.GenerateHull(points.ToList(), true, ref verts, ref tris, ref normals);
//var qh = new QuickHull();
//verts = qh.QuickHull2(points);
var finalPoints = new List<Vector3>();
foreach (var tri in tris)
@@ -146,7 +143,7 @@ namespace Game
private MapEntity root;
private IEnumerable<IEnumerable<T>> DifferentCombinations<T>(IEnumerable<T> elements, int k)
private static IEnumerable<IEnumerable<T>> DifferentCombinations<T>(IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
@@ -157,35 +154,56 @@ namespace Game
/// Triangulates the brush by calculating intersection points between triplets of planes.
/// Does not work well with off-axis aligned planes.
/// </summary>
void TriangulateBrush(MapBrush brush, out Vector3[] vertices)
public static void TriangulateBrush(MapBrush brush, out Vector3[] vertices)
{
HashSet<Vector3> planePoints = new HashSet<Vector3>();
List<Plane> planes = new List<Plane>();
float maxDist = 0f;
foreach (var brushPlane in brush.planes)
planes.Add(new Plane(brushPlane.v1, brushPlane.v2, brushPlane.v3));
{
if (Mathf.Abs(brushPlane.plane.D) > maxDist)
maxDist = Mathf.Abs(brushPlane.plane.D);
planes.Add(brushPlane.plane);
}
maxDist *= Mathf.Sqrt(3);
var combinations = DifferentCombinations(planes, 3).ToList();
foreach (var comb in Enumerable.Reverse(combinations))
// pass 1: get all intersection points
foreach (var comb in combinations)
{
var p1 = comb.Skip(0).First();
var p2 = comb.Skip(1).First();
var p3 = comb.Skip(2).First();
var maxDist = Math.Abs(p1.D * p2.D * p3.D);//Math.Max(p1.D, Math.Max(p2.D, p3.D));
//var maxDist = Math.Abs(p1.D * p2.D * p3.D);//Math.Max(p1.D, Math.Max(p2.D, p3.D));
// intersection of three planes
double denom = Vector3.Dot(p1.Normal, Vector3.Cross(p2.Normal, p3.Normal));
if (Math.Abs(denom) < 0.000001f)
continue; // multiple or no intersections
//if (denom < 0.0000000001)
// continue;
if (Math.Abs(denom) < 0.000001f)
denom = denom;
var intersection = (Vector3.Cross(p2.Normal, p3.Normal) * -p1.D +
Vector3.Cross(p3.Normal, p1.Normal) * -p2.D +
Vector3.Cross(p1.Normal, p2.Normal) * -p3.D) / (float)denom;
if (Mathf.Abs(intersection.X) > maxDist * 1f || Mathf.Abs(intersection.Y) > maxDist * 1f ||
Mathf.Abs(intersection.Z) > maxDist * 1f)
{
denom = denom;
continue;
}
if (Math.Abs(denom) < 0.0000000001)
{
denom = denom;
continue;
}
//if (intersection.Length > maxDist*2f)
// continue;
// Flip Y and Z
/*var temp = intersection.Y;
intersection.Y = intersection.Z;
@@ -197,6 +215,28 @@ namespace Game
planePoints.Add(intersection);
}
// pass 2: cull points behind clipping planes
var planePoints2 = planePoints;
planePoints = new HashSet<Vector3>();
foreach (var p in planePoints2)
{
bool front = true;
foreach (var brushPlane in brush.planes)
{
var dot = -Plane.DotCoordinate(brushPlane.plane, p);
if (dot < -0.01f)
{
front = false;
break;
}
}
if (front)
planePoints.Add(p);
}
if (planePoints.Count > 0)
{
QuickHull(planePoints.ToArray(), out vertices);
@@ -206,7 +246,7 @@ namespace Game
vertices = new Vector3[0];
}
Vector3[] TriangulateBrush2(MapBrush brush)
static public void TriangulateBrush2(MapBrush brush, out Vector3[] vertices)
{
const float cs = 3000f;
@@ -225,14 +265,14 @@ namespace Game
QuickHull(cubePoints, out cubeVerts);
List<Vector3> brushVertices = new List<Vector3>(cubeVerts);
foreach (var brushPlane in brush.planes.Take(1))
foreach (var brushPlane in brush.planes)
{
Plane plane = new Plane(brushPlane.v1, brushPlane.v2, brushPlane.v3);
Plane plane = brushPlane.plane;
List<Vector3> faceVertices = new List<Vector3>();
List<Vector3> clippedVertices = new List<Vector3>();
Func<float, bool> isFront = (f) => f > epsilon;
Func<float, bool> isBack = (f) => f < -epsilon;
Func<float, bool> isBack = (f) => f < epsilon;
for (int i = 0; i < brushVertices.Count; i++)
{
@@ -255,7 +295,8 @@ namespace Game
//if (isFront(d2))
{
Ray ray = new Ray(start, (end - start).Normalized);
if (plane.Intersects(ref ray, out Vector3 point))
Ray ray2 = new Ray(end, (start - end).Normalized);
if (plane.Intersects(ref ray, out Vector3 point) || plane.Intersects(ref ray2, out point))
{
//faceVertices.Add(point);
@@ -324,6 +365,8 @@ namespace Game
brushVertices.Clear();
brushVertices.AddRange(faceVertices);
Assert.IsTrue(faceVertices.Count % 3 == 0);
/*var newMeshPoints = new List<Vector3>();
int duplis = 0;
foreach (var v in faceVertices)
@@ -368,12 +411,12 @@ namespace Game
}
return brushVertices.ToArray();
vertices = brushVertices.ToArray();
}
static public void TriangulateBrush3(MapBrush brush, out Vector3[] vertices)
{
float cs = 3000f;
float cs = 4000f;
float maxD = 0f;
float minD = 0f;
@@ -402,14 +445,10 @@ namespace Game
QuickHull(cubePoints, out cubeVerts);
List<Vector3> brushVertices = new List<Vector3>(cubeVerts);
int asdf = 0;
//foreach (var brushPlane in brush.planes.Skip(skipPlanes).Take(takePlanes))
foreach (var brushPlane in brush.planes)
{
Plane plane = brushPlane.plane;
//if (asdf % 2 == 0)
//plane = new Plane(-plane.Normal, -plane.D);
List<Vector3> faceVertices = new List<Vector3>();
List<Vector3> clippedVertices = new List<Vector3>();
@@ -417,30 +456,30 @@ namespace Game
Func<float, bool> isFront = (f) => f > epsilon;
Func<float, bool> isBack = (f) => f < epsilon;
List<Tuple<Vector3, Vector3>> edges = new List<Tuple<Vector3, Vector3>>();
List<Tuple<Vector3, Vector3>> faceEdges = new List<Tuple<Vector3, Vector3>>();
List<Tuple<Vector3, Vector3>> planeEdges = new List<Tuple<Vector3, Vector3>>();
var faceEdges = new List<Tuple<Vector3, Vector3>>();
void TriangulateEdges()
void ProcessEdges()
{
if (edges.Count > 0)
if (planeEdges.Count > 0)
{
// heal discontinued edges
for (int j = 0; j < edges.Count; j++)
for (int j = 0; j < planeEdges.Count; j++)
{
var edgePrev = edges[j];
var edgeNext = edges[(j + 1) % edges.Count];
var edgePrev = planeEdges[j];
var edgeNext = planeEdges[(j + 1) % planeEdges.Count];
//if (edgePrev.Item2 != edgeNext.Item1)
if ((edgePrev.Item2 - edgeNext.Item1).Length > 0.0001f)
{
var newEdge = new Tuple<Vector3, Vector3>(edgePrev.Item2, edgeNext.Item1);
edges.Insert(j + 1, newEdge);
planeEdges.Insert(j + 1, newEdge);
j--;
}
}
// triangulate edges
for (int j = 0; j < edges.Count - 1; j++)
/*for (int j = 0; j < edges.Count - 1; j++)
{
var edgePrev = edges[j];
var edgeNext = edges[(j + 1) % edges.Count];
@@ -452,7 +491,7 @@ namespace Game
faceVertices.Add(v0);
faceVertices.Add(v1);
faceVertices.Add(v2);
}
}*/
// triangulate clipped face
/*for (int j = 0; j < clippedVertices.Count-1; j++)
@@ -466,13 +505,16 @@ namespace Game
else
plane = plane;
edges.Clear();
faceEdges.AddRange(planeEdges);
planeEdges = new List<Tuple<Vector3, Vector3>>();
//edges.Clear();
}
for (int i = 0; i < brushVertices.Count; i++)
{
if (i > 0 && i % 3 == 0)
TriangulateEdges();
ProcessEdges();
int i2 = ((i + 1) % 3 == 0) ? (i - 2) : (i + 1);
Vector3 start = brushVertices[i];
@@ -510,11 +552,127 @@ namespace Game
if (isFront(d1) && isFront(d2))
continue;
var abs = Mathf.Abs((edgeEnd-edgeStart).Length);
if (abs < 0.000001f)
{
abs = abs;
//continue;
}
Tuple<Vector3, Vector3> edge = new Tuple<Vector3, Vector3>(edgeStart, edgeEnd);
edges.Add(edge);
planeEdges.Add(edge);
}
ProcessEdges();
if (true)
{
// triangulate edges
faceVertices.Clear();
//foreach (var edges in faceEdges)
{
// merge same points in edges
for (int j = 0; j < faceEdges.Count; j++)
{
Vector3 v0 = faceEdges[j].Item1;
Vector3 v1 = faceEdges[j].Item2;
var edgeNext = faceEdges[(j + 1) % faceEdges.Count];
Vector3 v2 = edgeNext.Item1;
Vector3 v3 = edgeNext.Item2;
var dot = Vector3.Dot(v1.Normalized, v2.Normalized);
if (v1 != v2 && dot > 0.9999999f)
{
v1 = v1;
//faceEdges[(j + 1) % faceEdges.Count] = new Tuple<Vector3, Vector3>(v1, v3);
}
}
List<Tuple<Vector3, Vector3>> newEdges = new List<Tuple<Vector3, Vector3>>();
for (int j = 0; j < faceEdges.Count; j++)
{
Vector3 v0 = faceEdges[j].Item1;
Vector3 v1 = faceEdges[j].Item2;
var abs = Mathf.Abs((v1-v0).Length);
if (abs < 0.000001f)
{
v1 = v1;
//continue;
}
Tuple<Vector3, Vector3> newEdge = new Tuple<Vector3, Vector3>(v0, v1);
while (true)
{
var edgeNext = faceEdges[(j + 1) % faceEdges.Count];
Vector3 v2 = edgeNext.Item1;
Vector3 v3 = edgeNext.Item2;
//var dot = Vector3.Dot((v3 - v0).Normalized, (v1 - v0).Normalized);
/*var dot = Vector3.Dot((v3 - v2).Normalized, (v1 - v0).Normalized);
if (dot > 0.9f)
{
newEdge = new Tuple<Vector3, Vector3>(v0, v3);
j++;
}
else*/
break;
/*var dot = Vector3.Dot((v3 - v2).Normalized, (v1 - v0).Normalized);
if (dot > 0.9f)
{
newEdge = new Tuple<Vector3, Vector3>(v0, v3);
j++;
}
else
break;*/
}
newEdges.Add(newEdge);
}
for (int j = 0; j < newEdges.Count - 1; j++)
{
var edgePrev = newEdges[j];
var edgeNext = newEdges[(j + 1) % newEdges.Count];
Vector3 v0 = newEdges[0].Item1;
Vector3 v1 = edgePrev.Item2;
Vector3 v2 = edgeNext.Item2;
faceVertices.Add(v0);
faceVertices.Add(v1);
faceVertices.Add(v2);
}
}
}
TriangulateEdges();
List<Vector3> uniqPoints = new List<Vector3>();
foreach (var v in faceVertices)
{
bool found = false;
foreach (var v2 in uniqPoints)
{
if ((v - v2).Length < 0.01f)
{
found = true;
break;
}
}
if (!found)
uniqPoints.Add(v);
//uniqPoints.Add(new Vector3((float)Math.Round(v.X, 3), (float)Math.Round(v.Y, 3), (float)Math.Round(v.Z, 3)));
}
//debugPoints = new List<Vector3>(uniqPoints);
Vector3[] hullPoints;
QuickHull(uniqPoints.ToArray(), out hullPoints);
var hullVerts = new MeshSimplifier().Simplify(hullPoints);
if (false)
{
// create edges from clipped points
@@ -567,32 +725,13 @@ namespace Game
if (true)
{
List<Vector3> uniqPoints = new List<Vector3>();
foreach (var v in faceVertices)
{
bool found = false;
foreach (var v2 in uniqPoints)
{
if ((v - v2).Length < 0.01f)
{
found = true;
break;
}
}
if (!found)
uniqPoints.Add(v);
//uniqPoints.Add(new Vector3((float)Math.Round(v.X, 3), (float)Math.Round(v.Y, 3), (float)Math.Round(v.Z, 3)));
}
uniqPoints = uniqPoints;
hullVerts = hullVerts;
hullPoints = hullPoints;
faceVertices = faceVertices;
//debugPoints = new List<Vector3>(uniqPoints);
Vector3[] hullPoints;
QuickHull(uniqPoints.ToArray(), out hullPoints);
var ms = new MeshSimplifier(1f, 7f);
var optimizedVerts = ms.Simplify(hullPoints);
var optimizedVerts = hullVerts;//new MeshSimplifier().Simplify(faceVertices.ToArray());
brushVertices.Clear();
brushVertices.AddRange(optimizedVerts);
@@ -601,7 +740,7 @@ namespace Game
{
//debugPoints = new List<Vector3>(faceVertices);
var hullPoints = faceVertices;
//var hullPoints = faceVertices;
var ms = new MeshSimplifier();
var optimizedVerts = hullPoints; //ms.Simplify(hullPoints);
@@ -609,39 +748,11 @@ namespace Game
brushVertices.Clear();
brushVertices.AddRange(optimizedVerts);
}
asdf++;
}
vertices = brushVertices.ToArray();
}
/*
Development (game)
cube3: 8.1ms + 123ms
aerowalk: 78ms + 1372ms
Development (editor)
cube3: 4.6ms + 77.3ms
aerowalk: 74ms + 1328ms
Release
cube3: 4.4ms + 61.4ms
aerowalk: 17ms + 511ms
UnitTest release:
aerowalk: 8ms + 267ms
aero unit:
.net6: 667 + 229
.net5: 704 + 237
.net5win7: 697 + 237
.net48 809 + 242
.net472 810 + 246
.net462 810 + 243
.net452 808 + 244
*/
public override void OnStart()
{
byte[] mapChars = File.ReadAllBytes(mapPath);
@@ -668,25 +779,30 @@ namespace Game
// pass 1: triangulation
sw.Restart();
int brushIndex = 0;
int totalverts = 0;
foreach (var brush in root.entities[0].brushes)
{
try
{
BrushGeometry geom = new BrushGeometry();
TriangulateBrush3(brush, out geom.vertices);
TriangulateBrush(brush, out geom.vertices);
geom.brush = brush;
brushGeometries.Add(geom);
totalverts += geom.vertices.Length;
Assert.IsTrue(geom.vertices.Length > 0);
}
catch (Exception e)
{
Console.Print("Failed to triangulate brush " + brushIndex.ToString() + ": " + e.Message);
//FlaxEngine.Engine.RequestExit();
}
brushIndex++;
}
sw.Stop();
Console.Print("Pass 1: triangulation: " + sw.Elapsed.TotalMilliseconds + "ms");
Console.Print("Pass 1: triangulation: " + sw.Elapsed.TotalMilliseconds + "ms, total verts: " + totalverts + ", should be 1002");
// pass 2: texturing
sw.Restart();
@@ -700,18 +816,28 @@ namespace Game
if (materials == null)
{
var customSettings = Engine.GetCustomSettings("BrushMaterials");
BrushMaterialList brushMaterialList = customSettings?.CreateInstance<BrushMaterialList>();
materials = new Dictionary<string, MaterialBase>();
BrushMaterialList brushMaterialList = Engine.GetCustomSettings("BrushMaterials")
?.CreateInstance<BrushMaterialList>();
if (brushMaterialList != null)
{
materials = brushMaterialList.materialAssets.ToDictionary(x => x.name, y => y.asset);
foreach (var m in brushMaterialList.materialAssets)
materials.Add(m.name, m.asset);
Console.Print("materials dictionary with " + materials.Count + " entries");
}
else
{
materials = new Dictionary<string, MaterialBase>();
Console.Print("no materials dictionary found");
}
BrushMaterialList brushMaterialList2 = Engine.GetCustomSettings("BrushMaterialsLegacy")
?.CreateInstance<BrushMaterialList>();
if (brushMaterialList2 != null)
{
foreach (var m in brushMaterialList2.materialAssets)
materials.Add(m.name, m.asset);
}
}
// FIXME: brush can have multiple textures
@@ -719,6 +845,7 @@ namespace Game
{
Console.Print("Material '" + textureName + "' not found for brush");
materials.Add(textureName, material);
geom.brushMaterial = material;
}
for (int i = 0; i < brushVertices.Length; i += 3)
@@ -860,6 +987,7 @@ namespace Game
// pass 3: collision
sw.Restart();
brushIndex = 0;
foreach (var geom in brushGeometries)
{
StaticModel childModel = Actor.AddChild<StaticModel>();
@@ -888,6 +1016,7 @@ namespace Game
var meshCollider = childModel.AddChild<MeshCollider>();
meshCollider.CollisionData = collisionData;
brushIndex++;
}
sw.Stop();
Console.Print("Pass 3: collision: " + sw.Elapsed.TotalMilliseconds + "ms");

View File

@@ -13,11 +13,19 @@ namespace GoakeTests.MapParser
private byte[] aerowalkBytes;
private MapEntity aerowalkRoot;
private byte[] q1mapBytes;
private byte[] dm4Bytes;
[SetUp]
public void Setup()
{
dm4Bytes = File.ReadAllBytes(@"C:\dev\GoakeFlax\Assets\Maps\dm4.map");
aerowalkBytes = File.ReadAllBytes(@"C:\dev\Goake\maps\aerowalk\aerowalk.map");
aerowalkRoot = Game.MapParser.Parse(aerowalkBytes);
q1mapBytes = File.ReadAllBytes(@"C:\dev\GoakeFlax\Assets\Maps\cube_q1.map");
}
[TearDown]
@@ -26,6 +34,46 @@ namespace GoakeTests.MapParser
}
[Test]
public void Perf_LoadQ1test()
{
List<Game.MapEntity> mapEntities = new List<Game.MapEntity>(100);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
{
var root = Game.MapParser.Parse(q1mapBytes);
Assert.IsTrue(root.entities[0].brushes.Count > 0);
mapEntities.Add(root);
}
sw.Stop();
var elapsedMs = sw.Elapsed.TotalMilliseconds;
TestContext.Out.WriteLine("Map parsing time: " + elapsedMs/100 + "ms");
}
[Test]
public void Perf_LoadDM4()
{
List<Game.MapEntity> mapEntities = new List<Game.MapEntity>(100);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 100; i++)
{
var root = Game.MapParser.Parse(dm4Bytes);
Assert.IsTrue(root.entities[0].brushes.Count > 0);
mapEntities.Add(root);
}
sw.Stop();
var elapsedMs = sw.Elapsed.TotalMilliseconds;
TestContext.Out.WriteLine("Map parsing time: " + elapsedMs/100 + "ms");
}
[Test]
public void Perf_LoadAerowalk()
{
@@ -52,6 +100,7 @@ namespace GoakeTests.MapParser
//var roott = Game.MapParser.Parse(aerowalkBytes);
List<Game.MapEntity> mapEntities = new List<Game.MapEntity>(100);
aerowalkRoot = Game.MapParser.Parse(aerowalkBytes);
Stopwatch sw = Stopwatch.StartNew();
@@ -70,5 +119,68 @@ namespace GoakeTests.MapParser
var elapsedMs = sw.Elapsed.TotalMilliseconds;
TestContext.Out.WriteLine("Triangulation time: " + elapsedMs + "ms");
}
[Test]
public void Perf_TriangulateAerowalk2()
{
// warmup?
//var roott = Game.MapParser.Parse(aerowalkBytes);
List<Game.MapEntity> mapEntities = new List<Game.MapEntity>(100);
aerowalkRoot = Game.MapParser.Parse(aerowalkBytes);
/*for (int i = 0; i < 1; i++)
{
foreach (var ent in aerowalkRoot.entities)
foreach (var brush in ent.brushes)
{
Q3MapImporter.TriangulateBrush(brush, out Vector3[] verts);
Assert.IsTrue(verts.Length > 0);
}
}*/
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1; i++)
{
foreach (var ent in aerowalkRoot.entities)
foreach (var brush in ent.brushes)
{
Q3MapImporter.TriangulateBrush(brush, out Vector3[] verts);
Assert.IsTrue(verts.Length > 0);
}
}
sw.Stop();
var elapsedMs = sw.Elapsed.TotalMilliseconds;
TestContext.Out.WriteLine("Triangulation time: " + elapsedMs + "ms");
}
[Test]
public void Perf_TriangulateQ1test()
{
// warmup?
//var roott = Game.MapParser.Parse(aerowalkBytes);
List<Game.MapEntity> mapEntities = new List<Game.MapEntity>(100);
var root = Game.MapParser.Parse(q1mapBytes);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1; i++)
{
foreach (var ent in root.entities)
foreach (var brush in ent.brushes)
{
Q3MapImporter.TriangulateBrush3(brush, out Vector3[] verts);
Assert.IsTrue(verts.Length > 0);
}
}
sw.Stop();
var elapsedMs = sw.Elapsed.TotalMilliseconds;
TestContext.Out.WriteLine("Triangulation time: " + elapsedMs + "ms");
}
}
}