aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/Meshmerizer.cs')
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs393
1 files changed, 393 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
new file mode 100644
index 0000000..da4ee58
--- /dev/null
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -0,0 +1,393 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29using System;
30using System.IO;
31using System.Globalization;
32using System.Diagnostics;
33using System.Collections.Generic;
34using System.Runtime.InteropServices;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Region.Physics.Manager;
38
39namespace OpenSim.Region.Physics.Meshing
40{
41
42 public class MeshmerizerPlugin : IMeshingPlugin
43 {
44 public MeshmerizerPlugin()
45 {
46 }
47
48 public string GetName()
49 {
50 return "Meshmerizer";
51 }
52
53 public IMesher GetMesher()
54 {
55 return new Meshmerizer();
56 }
57 }
58
59 public class Meshmerizer : IMesher
60 {
61 // Setting baseDir to a path will enable the dumping of raw files
62 // raw files can be imported by blender so a visual inspection of the results can be done
63 // const string baseDir = "rawFiles";
64 const string baseDir = null;
65
66 static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, ref float lambda, ref float mu)
67 {
68 // p1, p2, points on the straight
69 // r1, r2, directional vectors of the straight. Not necessarily of length 1!
70 // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
71 // thus allowing to decide whether an intersection is between two points
72
73 float r1x = r1.X;
74 float r1y = r1.Y;
75 float r2x = r2.X;
76 float r2y = r2.Y;
77
78 float denom = r1y*r2x - r1x*r2y;
79
80 if (denom == 0.0)
81 {
82 lambda = Single.NaN;
83 mu = Single.NaN;
84 return;
85 }
86
87 float p1x = p1.X;
88 float p1y = p1.Y;
89 float p2x = p2.X;
90 float p2y = p2.Y;
91 lambda = (-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x) / denom;
92 mu = (-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x) / denom;
93
94 }
95
96 private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v)
97 {
98 List<Triangle> influenced = new List<Triangle>();
99 foreach (Triangle t in triangles)
100 {
101 if (t.isInCircle(v.X, v.Y))
102 {
103 influenced.Add(t);
104 }
105 }
106 return influenced;
107 }
108
109
110 private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles)
111 {
112 // This is a variant of the delaunay algorithm
113 // each time a new vertex is inserted, all triangles that are influenced by it are deleted
114 // and replaced by new ones including the new vertex
115 // It is not very time efficient but easy to implement.
116
117 int iCurrentVertex;
118 int iMaxVertex = vertices.Count;
119 for (iCurrentVertex = usedForSeed; iCurrentVertex < iMaxVertex; iCurrentVertex++)
120 {
121 // Background: A triangle mesh fulfills the delaunay condition if (iff!)
122 // each circumlocutory circle (i.e. the circle that touches all three corners)
123 // of each triangle is empty of other vertices.
124 // Obviously a single (seeding) triangle fulfills this condition.
125 // If we now add one vertex, we need to reconstruct all triangles, that
126 // do not fulfill this condition with respect to the new triangle
127
128 // Find the triangles that are influenced by the new vertex
129 Vertex v=vertices[iCurrentVertex];
130 if (v == null)
131 continue; // Null is polygon stop marker. Ignore it
132 List<Triangle> influencedTriangles=FindInfluencedTriangles(triangles, v);
133
134 List<Simplex> simplices = new List<Simplex>();
135
136 // Reconstruction phase. First step, dissolve each triangle into it's simplices,
137 // i.e. it's "border lines"
138 // Goal is to find "inner" borders and delete them, while the hull gets conserved.
139 // Inner borders are special in the way that they always come twice, which is how we detect them
140 foreach (Triangle t in influencedTriangles)
141 {
142 List<Simplex> newSimplices = t.GetSimplices();
143 simplices.AddRange(newSimplices);
144 triangles.Remove(t);
145 }
146 // Now sort the simplices. That will make identical ones reside side by side in the list
147 simplices.Sort();
148
149 // Look for duplicate simplices here.
150 // Remember, they are directly side by side in the list right now,
151 // So we only check directly neighbours
152 int iSimplex;
153 List<Simplex> innerSimplices = new List<Simplex>();
154 for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards
155 {
156 if (simplices[iSimplex - 1].CompareTo(simplices[iSimplex]) == 0)
157 {
158 innerSimplices.Add(simplices[iSimplex - 1]);
159 innerSimplices.Add(simplices[iSimplex]);
160 }
161 }
162
163 foreach (Simplex s in innerSimplices)
164 {
165 simplices.Remove(s);
166 }
167
168 // each simplex still in the list belongs to the hull of the region in question
169 // The new vertex (yes, we still deal with verices here :-) ) forms a triangle
170 // with each of these simplices. Build the new triangles and add them to the list
171 foreach (Simplex s in simplices)
172 {
173 Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]);
174 if (!t.isDegraded())
175 {
176 triangles.Add(t);
177 }
178 }
179 }
180
181 }
182
183
184 static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
185 // Builds the z (+ and -) surfaces of a box shaped prim
186 {
187 UInt16 hollowFactor = primShape.ProfileHollow;
188 UInt16 profileBegin = primShape.ProfileBegin;
189 UInt16 profileEnd = primShape.ProfileEnd;
190
191 // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
192 // of a block are basically the same
193 // They may be warped differently but the shape is identical
194 // So we only create one surface as a model and derive both plus and minus surface of the block from it
195 // This is done in a model space where the block spans from -.5 to +.5 in X and Y
196 // The mapping to Scene space is done later during the "extrusion" phase
197
198 // Base
199 Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f);
200 Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f);
201 Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f);
202 Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f);
203
204 Meshing.SimpleHull outerHull = new SimpleHull();
205 outerHull.AddVertex(MM);
206 outerHull.AddVertex(PM);
207 outerHull.AddVertex(PP);
208 outerHull.AddVertex(MP);
209
210 // Deal with cuts now
211 if ((profileBegin != 0) || (profileEnd != 0))
212 {
213 double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; // In degree, for easier debugging and understanding
214 fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
215 double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
216 fProfileEndAngle -= (90.0 + 45.0);
217 if (fProfileBeginAngle < fProfileEndAngle)
218 fProfileEndAngle -= 360.0;
219
220 // Note, that we don't want to cut out a triangle, even if this is a
221 // good approximation for small cuts. Indeed we want to cut out an arc
222 // and we approximate this arc by a polygon chain
223 // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
224 // So it can easily be subtracted from the outer hull
225 int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); // how many steps do we need with approximately 45 degree
226 double dStepWidth=(fProfileBeginAngle-fProfileEndAngle)/iSteps;
227
228 Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
229
230 // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
231 SimpleHull cutHull = new SimpleHull();
232 cutHull.AddVertex(origin);
233 for (int i=0; i<iSteps; i++) {
234 double angle=fProfileBeginAngle-i*dStepWidth; // we count against the angle orientation!!!!
235 Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
236 cutHull.AddVertex(v);
237 }
238 Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); // Calculated separately to avoid errors
239 cutHull.AddVertex(legEnd);
240
241 MainLog.Instance.Debug("Starting cutting of the hollow shape from the prim {1}", 0, primName);
242 SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
243
244 outerHull = cuttedHull;
245 }
246
247 // Deal with the hole here
248 if (hollowFactor > 0)
249 {
250 float hollowFactorF = (float) hollowFactor/(float) 50000;
251 Vertex IMM = new Vertex(-0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
252 Vertex IPM = new Vertex(+0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
253 Vertex IMP = new Vertex(-0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
254 Vertex IPP = new Vertex(+0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
255
256 SimpleHull holeHull = new SimpleHull();
257
258 holeHull.AddVertex(IMM);
259 holeHull.AddVertex(IMP);
260 holeHull.AddVertex(IPP);
261 holeHull.AddVertex(IPM);
262
263 SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
264
265 outerHull = hollowedHull;
266
267 }
268
269 Mesh m = new Mesh();
270
271 Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
272 Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
273 Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
274
275 m.Add(Seed1);
276 m.Add(Seed2);
277 m.Add(Seed3);
278
279 m.Add(new Triangle(Seed1, Seed2, Seed3));
280 m.Add(outerHull.getVertices());
281
282 InsertVertices(m.vertices, 3, m.triangles);
283 m.DumpRaw(baseDir, primName, "Proto first Mesh");
284
285 m.Remove(Seed1);
286 m.Remove(Seed2);
287 m.Remove(Seed3);
288 m.DumpRaw(baseDir, primName, "Proto seeds removed");
289
290 m.RemoveTrianglesOutside(outerHull);
291 m.DumpRaw(baseDir, primName, "Proto outsides removed");
292
293 foreach (Triangle t in m.triangles)
294 {
295 PhysicsVector n = t.getNormal();
296 if (n.Z < 0.0)
297 t.invertNormal();
298 }
299
300 Extruder extr = new Extruder();
301
302 extr.size = size;
303
304 Mesh result = extr.Extrude(m);
305 result.DumpRaw(baseDir, primName, "Z extruded");
306 return result;
307 }
308
309 public static void CalcNormals(Mesh mesh)
310 {
311 int iTriangles = mesh.triangles.Count;
312
313 mesh.normals = new float[iTriangles*3];
314
315 int i = 0;
316 foreach (Triangle t in mesh.triangles)
317 {
318 float ux, uy, uz;
319 float vx, vy, vz;
320 float wx, wy, wz;
321
322 ux = t.v1.X;
323 uy = t.v1.Y;
324 uz = t.v1.Z;
325
326 vx = t.v2.X;
327 vy = t.v2.Y;
328 vz = t.v2.Z;
329
330 wx = t.v3.X;
331 wy = t.v3.Y;
332 wz = t.v3.Z;
333
334
335 // Vectors for edges
336 float e1x, e1y, e1z;
337 float e2x, e2y, e2z;
338
339 e1x = ux - vx;
340 e1y = uy - vy;
341 e1z = uz - vz;
342
343 e2x = ux - wx;
344 e2y = uy - wy;
345 e2z = uz - wz;
346
347
348 // Cross product for normal
349 float nx, ny, nz;
350 nx = e1y*e2z - e1z*e2y;
351 ny = e1z*e2x - e1x*e2z;
352 nz = e1x*e2y - e1y*e2x;
353
354 // Length
355 float l = (float) Math.Sqrt(nx*nx + ny*ny + nz*nz);
356
357 // Normalized "normal"
358 nx /= l;
359 ny /= l;
360 nz /= l;
361
362 mesh.normals[i] = nx;
363 mesh.normals[i + 1] = ny;
364 mesh.normals[i + 2] = nz;
365
366 i += 3;
367 }
368 }
369
370 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
371 {
372 Mesh mesh = null;
373
374 switch (primShape.ProfileShape)
375 {
376 case ProfileShape.Square:
377 mesh=CreateBoxMesh(primName, primShape, size);
378 CalcNormals(mesh);
379 break;
380 default:
381 mesh = CreateBoxMesh(primName, primShape, size);
382 CalcNormals(mesh);
383 //Set default mesh to cube otherwise it'll return
384 // null and crash on the 'setMesh' method in the physics plugins.
385 //mesh = null;
386 break;
387 }
388
389 return mesh;
390 }
391 }
392
393}