// Construct a solid sphere. Optional parameters are `center`, `radius`, // `slices`, and `stacks`, which default to `[0, 0, 0]`, `1`, `16`, and `8`. // The `slices` and `stacks` parameters control the tessellation along the // longitude and latitude directions. // // Example usage: // // var sphere = CSG.sphere({ // center: [0, 0, 0], // radius: 1, // slices: 16, // stacks: 8 // }); static public CSG sphere(CSGVector3 center, float radius, int slices, int stacks, CSGShared shared) { List <CSGPolygon> polygons = new List <CSGPolygon>(); for (float i = 0; i < slices; i++) { for (float j = 0; j < stacks; j++) { List <CSGVertex> vertices = new List <CSGVertex>(); sphereVertex(center, radius, i / slices, j / stacks, vertices); if (j > 0) { sphereVertex(center, radius, (i + 1) / slices, j / stacks, vertices); } if (j < stacks - 1) { sphereVertex(center, radius, (i + 1) / slices, (j + 1) / stacks, vertices); } sphereVertex(center, radius, i / slices, (j + 1) / stacks, vertices); polygons.Add(new CSGPolygon(vertices, shared)); } } return(CSG.fromPolygons(polygons)); }
// Construct an axis-aligned solid cuboid. Optional parameters are `center` and // `radius`, which default to `[0, 0, 0]` and `[1, 1, 1]`. The radius can be // specified using a single number or a list of three numbers, one for each axis. static public CSG cube(CSGVector3 center, CSGVector3 halfSize, CSGShared shared) { int[][][] data = new int[][][] { new int[][] { new int[] { 0, 4, 6, 2 }, new int[] { -1, 0, 0 } }, new int[][] { new int[] { 1, 3, 7, 5 }, new int[] { +1, 0, 0 } }, new int[][] { new int[] { 0, 1, 5, 4 }, new int[] { 0, -1, 0 } }, new int[][] { new int[] { 2, 6, 7, 3 }, new int[] { 0, +1, 0 } }, new int[][] { new int[] { 0, 2, 3, 1 }, new int[] { 0, 0, -1 } }, new int[][] { new int[] { 4, 5, 7, 6 }, new int[] { 0, 0, +1 } } }; List <CSGPolygon> polygons = new List <CSGPolygon>(); foreach (int[][] info in data) { List <CSGVertex> vertices = new List <CSGVertex>(); foreach (int i in info[0]) { CSGVector3 pos = new CSGVector3( center.x + halfSize.x * (2 * ((i & 1) != 0 ? 1 : 0) - 1), center.y + halfSize.y * (2 * ((i & 2) != 0 ? 1 : 0) - 1), center.z + halfSize.z * (2 * ((i & 4) != 0 ? 1 : 0) - 1) ); vertices.Add(new CSGVertex(pos, new CSGVector3(info[1][0], info[1][1], info[1][2]))); } polygons.Add(new CSGPolygon(vertices, shared)); } return(CSG.fromPolygons(polygons)); }
public CSGVector3 cross(CSGVector3 a) { return(new CSGVector3( this.y * a.z - this.z * a.y, this.z * a.x - this.x * a.z, this.x * a.y - this.y * a.x )); }
static private CSGVertex cylinderPoint(CSGVector3 s, CSGVector3 ray, float r, CSGVector3 axisX, CSGVector3 axisY, CSGVector3 axisZ, float stack, float slice, float normalBlend) { float angle = slice * ((float)Math.PI) * 2; CSGVector3 outv = axisX.times((float)Math.Cos(angle)).plus(axisY.times((float)Math.Sin(angle))); CSGVector3 pos = s.plus(ray.times(stack)).plus(outv.times(r)); CSGVector3 normal = outv.times(1 - Math.Abs(normalBlend)).plus(axisZ.times(normalBlend)); return(new CSGVertex(pos, normal)); }
// Affine transformation of vertex. Returns a new CSG.Vertex public CSGVertex transform(CSGMatrix4x4 matrix4x4) { CSGVector3 newpos = this.pos.multiply4x4(matrix4x4); CSGVector3 posPlusNormal = this.pos.plus(this.normal); CSGVector3 newPosPlusNormal = posPlusNormal.multiply4x4(matrix4x4); CSGVector3 newnormal = newPosPlusNormal.minus(newpos).unit(); return(new CSGVertex(newpos, newnormal)); }
static private void sphereVertex(CSGVector3 center, float radius, float theta, float phi, List <CSGVertex> vertices) { theta *= ((float)Math.PI) * 2; phi *= ((float)Math.PI); CSGVector3 dir = new CSGVector3( (float)Math.Cos(theta) * (float)Math.Sin(phi), (float)Math.Cos(phi), (float)Math.Sin(theta) * (float)Math.Sin(phi) ); vertices.Add(new CSGVertex(center.plus(dir.times(radius)), dir)); }
// 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)); }
// Create an affine matrix for scaling: static public CSGMatrix4x4 scaling(CSGVector3 vec) { CSGMatrix4x4 result = new CSGMatrix4x4(); result.this0 = vec.x; result.this5 = vec.y; result.this10 = vec.z; result.this15 = 1; /* * float[] els = new float[] { * vec.x, 0, 0, 0, * 0, vec.y, 0, 0, * 0, 0, vec.z, 0, * 0, 0, 0, 1 * }; */ return(result); }
// Multiply a CSG.Vector (interpreted as 1 row, 3 column) by this matrix // Fourth element is taken as 1 public CSGVector3 rightMultiply1x3Vector(CSGVector3 v) { float v0 = v.x; float v1 = v.y; float v2 = v.z; float v3 = 1; float x = v0 * this0 + v1 * this1 + v2 * this2 + v3 * this3; float y = v0 * this4 + v1 * this5 + v2 * this6 + v3 * this7; float z = v0 * this8 + v1 * this9 + v2 * this10 + v3 * this11; float w = v0 * this12 + v1 * this13 + v2 * this14 + v3 * this15; // scale such that fourth element becomes 1: if (w != 1) { float invw = 1.0f / w; x *= invw; y *= invw; z *= invw; } return(new CSGVector3(x, y, z)); }
// Create an affine matrix for translation: static public CSGMatrix4x4 translation(CSGVector3 vec) { CSGMatrix4x4 result = new CSGMatrix4x4(); result.this0 = 1; result.this3 = vec.x; result.this5 = 1; result.this7 = vec.y; result.this10 = 1; result.this11 = vec.z; result.this15 = 1; /* * float[] els = new float[] { * 1, 0, 0, vec.x, * 0, 1, 0, vec.y, * 0, 0, 1, vec.z, * 0, 0, 0, 1 * }; */ return(result); }
public CSGVertex(CSGVector3 pos, CSGVector3 normal) { this.pos = pos; this.normal = normal; }
public CSGPlane(CSGVector3 normal, float w) { this.normal = normal; this.w = w; }
public void flip() { normal = normal.negated(); w = -w; }
static public CSGPlane fromPoints(CSGVector3 a, CSGVector3 b, CSGVector3 c) { CSGVector3 n = b.minus(a).cross(c.minus(a)).unit(); return(new CSGPlane(n, n.dot(a))); }
public CSGVector3 plus(CSGVector3 a) { return(new CSGVector3(x + a.x, y + a.y, z + a.z)); }
public CSGShared(float r, float g, float b) { this.color = new CSGVector3(r, g, b); }
public CSG scale(CSGVector3 v) { return(this.transform(CSGMatrix4x4.scaling(v))); }
public CSG translate(CSGVector3 v) { return(this.transform(CSGMatrix4x4.translation(v))); }
public CSGVector3 minus(CSGVector3 a) { return(new CSGVector3(x - a.x, y - a.y, z - a.z)); }
public CSGVector3 lerp(CSGVector3 a, float t) { return(this.plus(a.minus(this).times(t))); }
public float dot(CSGVector3 a) { return(this.x * a.x + this.y * a.y + this.z * a.z); }