public int Hash(CSGVertex p) { for (var i = 0; i < count; i++) { var item = buckets[i]; var diffX = p.P.x - item.P.x; var diffY = p.P.y - item.P.y; var diffZ = p.P.z - item.P.z; var sqrMag = diffX * diffX + diffY * diffY + diffZ * diffZ; if (sqrMag < bucketSize2) { diffX = p.N.x - item.N.x; diffY = p.N.y - item.N.y; diffZ = p.N.z - item.N.z; sqrMag = diffX * diffX + diffY * diffY + diffZ * diffZ; if (sqrMag < bucketSize2) { diffX = p.UV.x - item.UV.x; diffY = p.UV.y - item.UV.y; sqrMag = diffX * diffX + diffY * diffY; if (sqrMag < bucketSize2) { return(i); } } } } buckets[count++] = p; return(count - 1); }
public int Hash(CSGVertex p) { for (int i=0; i<count; i++) { var item = buckets[i]; float diffX = p.P.x - item.P.x; float diffY = p.P.y - item.P.y; float diffZ = p.P.z - item.P.z; float sqrMag = diffX*diffX + diffY*diffY + diffZ*diffZ; if (sqrMag < bucketSize2) { diffX = p.N.x - item.N.x; diffY = p.N.y - item.N.y; diffZ = p.N.z - item.N.z; sqrMag = diffX * diffX + diffY * diffY + diffZ * diffZ; if (sqrMag < bucketSize2) { diffX = p.UV.x - item.UV.x; diffY = p.UV.y - item.UV.y; sqrMag = diffX*diffX + diffY*diffY; if (sqrMag < bucketSize2) { return i; } } } } buckets[count++] = p; return count-1; }
// Create a new vertex between this vertex and `other` by linearly // interpolating all properties using a parameter of `t`. Subclasses should // override this to interpolate additional properties. public CSGVertex interpolate(CSGVertex other, float t) { return(new CSGVertex( this.pos.lerp(other.pos, t), this.normal.lerp(other.normal, t) )); }
// Construct a solid cylinder. Optional parameters are `start`, `end`, // `radius`, and `slices`, which default to `[0, -1, 0]`, `[0, 1, 0]`, `1`, and // `16`. The `slices` parameter controls the tessellation. // // Example usage: // // var cylinder = CSG.cylinder({ // start: [0, -1, 0], // end: [0, 1, 0], // radius: 1, // slices: 16 // }); static public CSG cylinder(CSGVector3 s, CSGVector3 e, float radius, int slices, CSGShared shared) { CSGVector3 ray = e.minus(s); CSGVector3 axisZ = ray.unit(); bool isY = (Math.Abs(axisZ.y) > 0.5f); CSGVector3 axisX = new CSGVector3(isY ? 1 : 0, !isY ? 1 : 0, 0).cross(axisZ).unit(); CSGVector3 axisY = axisX.cross(axisZ).unit(); CSGVertex start = new CSGVertex(s, axisZ.negated()); CSGVertex end = new CSGVertex(e, axisZ.unit()); List <CSGPolygon> polygons = new List <CSGPolygon>(); for (float i = 0; i < slices; i++) { float t0 = i / slices; float t1 = (i + 1) / slices; //cylinderPoint(s, ray, radius, axisX, axisY, axisZ, polygons.Add( new CSGPolygon( new CSGVertex[] { start, cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 0, t0, -1), cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 0, t1, -1) }, shared)); polygons.Add( new CSGPolygon( new CSGVertex[] { cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 0, t1, 0), cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 0, t0, 0), cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 1, t0, 0), cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 1, t1, 0) }, shared)); polygons.Add( new CSGPolygon( new CSGVertex[] { end, cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 1, t1, 1), cylinderPoint(s, ray, radius, axisX, axisY, axisZ, 1, t0, 1) }, shared)); } return(CSG.fromPolygons(polygons)); }
protected List <DefaultVertex> ConvertCSGVertices(IList <CSGVertex> csgVertices) { List <DefaultVertex> result = new List <DefaultVertex>(); for (int tri = 0; tri < csgVertices.Count / 3; ++tri) { CSGVertex c1 = csgVertices[tri * 3 + 0]; CSGVertex c2 = csgVertices[tri * 3 + 1]; CSGVertex c3 = csgVertices[tri * 3 + 2]; Vector3 v1 = c1.Position; Vector2 w1 = c1.TexUV; Vector3 v2 = c2.Position; Vector2 w2 = c2.TexUV; Vector3 v3 = c3.Position; Vector2 w3 = c3.TexUV; float x1 = v2.X - v1.X; float x2 = v3.X - v1.X; float y1 = v2.Y - v1.Y; float y2 = v3.Y - v1.Y; float z1 = v2.Z - v1.Z; float z2 = v3.Z - v1.Z; float s1 = w2.X - w1.X; float s2 = w3.X - w1.X; float t1 = w2.Y - w1.Y; float t2 = w3.Y - w1.Y; float r = 1f / (s1 * t2 - s2 * t1); Vector3 tan = new Vector3( (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r ); result.Add(new DefaultVertex(c1.Position, c1.Normal, tan, c1.TexUV)); result.Add(new DefaultVertex(c2.Position, c2.Normal, tan, c2.TexUV)); result.Add(new DefaultVertex(c3.Position, c3.Normal, tan, c3.TexUV)); } return(csgVertices.Select(csg => new DefaultVertex(csg.Position, csg.Normal, csg.TexUV)).ToList()); }
// Split `polygon` by this plane if needed, then put the polygon or polygon // fragments in the appropriate lists. Coplanar polygons go into either // `coplanarFront` or `coplanarBack` depending on their orientation with // respect to this plane. Polygons in front or in back of this plane go into // either `front` or `back`. public void splitPolygon(CSGPolygon polygon, List <CSGPolygon> coplanarFront, List <CSGPolygon> coplanarBack, List <CSGPolygon> front, List <CSGPolygon> back) { // Classify each point as well as the entire polygon into one of the above // four classes. int polygonType = 0; int[] types = new int[polygon.vertices.Count]; for (int i = 0; i < polygon.vertices.Count; i++) { float t = this.normal.dot(polygon.vertices[i].pos) - this.w; int type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR; polygonType |= type; types[i] = type; } // Put the polygon in the correct list, splitting it when necessary. switch (polygonType) { case COPLANAR: (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).Add(polygon); break; case FRONT: front.Add(polygon); break; case BACK: back.Add(polygon); break; case SPANNING: { List <CSGVertex> f = new List <CSGVertex>(); List <CSGVertex> b = new List <CSGVertex>(); for (int i = 0; i < polygon.vertices.Count; i++) { int j = (i + 1) % polygon.vertices.Count; int ti = types[i]; int tj = types[j]; CSGVertex vi = polygon.vertices[i]; CSGVertex vj = polygon.vertices[j]; if (ti != BACK) { f.Add(vi); } if (ti != FRONT) { b.Add(ti != BACK ? vi.clone() : vi); } if ((ti | tj) == SPANNING) { float t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(vj.pos.minus(vi.pos)); CSGVertex v = vi.interpolate(vj, t); f.Add(v); b.Add(v.clone()); } } if (f.Count >= 3) { front.Add(new CSGPolygon(f, polygon.shared)); } if (b.Count >= 3) { back.Add(new CSGPolygon(b, polygon.shared)); } break; } } }