void f3(int a, int b, int c, Shape shape, bool isBottom, int shapesOffset, WorldUVGenerator uvgen, Option options) { a += shapesOffset; b += shapesOffset; c += shapesOffset; // normal, color, material Face3 face; if (faceIndex >= faces.Count) { face = new Face3(a, b, c); this.faces.Add(face); } else { face = faces[faceIndex]; face.a = a; face.b = b; face.c = c; } faceIndex++; TubeGeometry.FrenetFrames splineTube = options.frames; Vector3 normal; if (splineTube != null) { int stepIndex = isBottom ? 0 : splineTube.tangents.Count - 1; normal = splineTube.tangents[stepIndex] * (isBottom ? -1 : 1); } else { normal = (isBottom ? -1 : 1) * Vector3.forward; } face.vertexNormals = new Vector3[] { normal, normal, normal }; List <Vector2> uvs = isBottom ? uvgen.generateBottomUV(this, shape, a, b, c) : uvgen.generateTopUV(this, shape, a, b, c); face.uvs = uvs.ToArray(); // TODO: faceVertexUvs の変更で問題点ないか確認 // if(faceIndex-1 >= faceVertexUvs.Count){ // this.faceVertexUvs.Add( new List<Vector2>( uvs )); // }else{ // this.faceVertexUvs[faceIndex - 1] = new List<Vector2>( uvs ); // } // //this.faceVertexUvs.Add( new List<Vector2>( new Vector2[]{ Vector2.one, Vector2.one, Vector2.one } )); // Debug }
void f4(int a, int b, int c, int d, Shape shape, List <Vector3> wallContour, int stepIndex, int stepsLength, int contourIndex1, int contourIndex2, int shapesOffset, WorldUVGenerator uvgen, Option options, bool reverse, Quaternion tQ0, Quaternion tQ1) { a += shapesOffset; b += shapesOffset; c += shapesOffset; d += shapesOffset; List <Vector2> uvs = uvgen.generateSideWallUV(this, shape, wallContour, a, b, c, d, stepIndex, stepsLength, contourIndex1, contourIndex2); Face3 face0; if (faceIndex >= faces.Count) { face0 = new Face3(a, b, d); this.faces.Add(face0); } else { face0 = faces[faceIndex]; face0.a = a; face0.b = b; face0.c = d; } face0.uvs = new Vector2[] { uvs[0], uvs[1], uvs[3] }; faceIndex++; Face3 face1; if (faceIndex >= faces.Count) { face1 = new Face3(b, c, d); this.faces.Add(face1); } else { face1 = faces[faceIndex]; face1.a = b; face1.b = c; face1.c = d; } face1.uvs = new Vector2[] { uvs[1], uvs[2], uvs[3] }; faceIndex++; // Vector3 normal0; Vector3 normal1; TubeGeometry.FrenetFrames splineTube = options.frames; if (shape.normals != null) { if (splineTube != null) { Vector3 n0 = shape.normals[contourIndex1]; if (reverse) { n0.y *= -1; } normal0 = tQ0 * n0; normal0.Normalize(); Vector3 n1 = shape.normals[contourIndex1]; if (reverse) { n1.y *= -1; } normal1 = tQ1 * n1; normal1.Normalize(); } else { Vector3 norm = shape.normals[contourIndex1]; if (reverse) { norm.y *= -1; } normal0 = norm; normal1 = norm; } // face0.vertexNormals = new Vector3[]{normal0, normal0, normal1 }; // face1.vertexNormals = new Vector3[]{normal0, normal1, normal1 }; face0.vertexNormals[0] = normal0; face0.vertexNormals[1] = normal0; face0.vertexNormals[2] = normal1; face1.vertexNormals[0] = normal0; face1.vertexNormals[1] = normal1; face1.vertexNormals[2] = normal1; } // // TODO: faceVertexUvs の変更で問題点ないか確認 // List<Vector2> uvs0; // if(faceIndex - 2 >= this.faceVertexUvs.Count){ // uvs0 = new List<Vector2>( new Vector2[]{ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] } ); // this.faceVertexUvs.Add(uvs0); // }else{ // this.faceVertexUvs[faceIndex - 2] = new List<Vector2>( new Vector2[]{ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] } ); // } // List<Vector2> uvs1; // if(faceIndex - 1 >= this.faceVertexUvs.Count){ // uvs1 = new List<Vector2>( new Vector2[]{ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] } ); // this.faceVertexUvs.Add(uvs1); // }else{ // this.faceVertexUvs[faceIndex - 1] = new List<Vector2>( new Vector2[]{ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] } ); // } // this.faceVertexUvs.Add( new List<Vector2>( new Vector2[]{ Vector2.one, Vector2.one, Vector2.one, Vector2.one } )); // Debug // this.faceVertexUvs.Add( new List<Vector2>( new Vector2[]{ Vector2.one, Vector2.one, Vector2.one, Vector2.one } )); // Debug }
void sidewalls(int vlen, List <Vector3> contour, int layeroffset, int steps, int bevelSegments, int shapesOffset, WorldUVGenerator uvgen, Shape shape, Option options, bool closePath = false, bool reverse = true) { int j, k; TubeGeometry.FrenetFrames splineTube = options.frames; // pre compute Quat int sl = steps + bevelSegments * 2; Quaternion[] normalQuats = new Quaternion[sl + 1]; if (splineTube != null) { for (int i = 0; i < normalQuats.Length; i++) { normalQuats[i] = Quaternion.LookRotation(splineTube.tangents[i], splineTube.normals[i]) * Quaternion.AngleAxis(90, Vector3.forward); } } for (int i = 0; i < contour.Count; i++) { j = i; k = i - 1; if (k < 0) { k = contour.Count - 1; } //console.log('b', i,j, i-1, k,vertices.length); //Debug.Log(">>> k: "+k + " steps: "+steps); int s = 0; //int sl = steps + bevelSegments * 2; for (s = 0; s < sl; s++) { int slen1 = vlen * s; int slen2 = vlen * (s + 1); if (closePath && s == steps - 1) { // close path end slen1 = vlen * (sl - 1); slen2 = 0; } int a = layeroffset + j + slen1; int b = layeroffset + k + slen1; int c = layeroffset + k + slen2; int d = layeroffset + j + slen2; // int stepIndex = s; int stepsLength = sl; Quaternion tQ0; Quaternion tQ1; if (splineTube != null) { tQ0 = normalQuats[stepIndex]; int id = stepIndex + 1; if (id > stepsLength) { id = 0; } tQ1 = normalQuats[id]; } else { tQ0 = Quaternion.identity; tQ1 = Quaternion.identity; } f4(a, b, c, d, shape, contour, s, sl, j, k, shapesOffset, uvgen, options, reverse, tQ0, tQ1); } } }
// Create faces for the z-sides of the shape void buildSideFaces(int vlen, List <Vector3> contour, List <List <Vector3> > holes, int steps, int bevelSegments, int shapesOffset, WorldUVGenerator uvgen, Shape shape, Option options, bool closePath = false, bool reverse = true) { int layeroffset = 0; sidewalls(vlen, contour, layeroffset, steps, bevelSegments, shapesOffset, uvgen, shape, options, closePath, reverse); layeroffset += contour.Count; // holes sideWall for (int h = 0, hl = holes.Count; h < hl; h++) { List <Vector3> ahole = holes[h]; sidewalls(vlen, ahole, layeroffset, steps, bevelSegments, shapesOffset, uvgen, shape, options, closePath, reverse); layeroffset += ahole.Count; } }
///// Internal functions void buildLidFaces(int vlen, List <List <int> > faces, int flen, int steps, int bevelSegments, bool bevelEnabled, int shapesOffset, Shape shape, WorldUVGenerator uvgen, Option options, bool reverse = false) { if (bevelEnabled) { int layer = 0; // steps + 1 int offset = vlen * layer; // Bottom faces for (int i = 0; i < flen; i++) { List <int> face = faces[i]; //f3( face[ 2 ] + offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); f3(face[2] + offset, face[1] + offset, face[0] + offset, shape, true, shapesOffset, uvgen, options); } layer = steps + bevelSegments * 2; offset = vlen * layer; // Top faces for (int i = 0; i < flen; i++) { List <int> face = faces[i]; //f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); f3(face[0] + offset, face[1] + offset, face[2] + offset, shape, false, shapesOffset, uvgen, options); } } else { // Bottom faces for (int i = 0; i < flen; i++) { List <int> face = faces[i]; //f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); f3(face[2], face[1], face[0], shape, true, shapesOffset, uvgen, options); } // Top faces for (int i = 0; i < flen; i++) { List <int> face = faces[i]; //f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps, shape, false, shapesOffset, uvgen, options); } } }
//void addShape(Shape shape, Option options ) { void addShape(ShapeAndHoleObject shapePoints, Option options) { Shape shape = shapePoints.baseShape; int amount = options.amount; float bevelThickness = options.bevelThickness; float bevelSize = options.bevelSize; int bevelSegments = options.bevelSegments; bool bevelEnabled = options.bevelEnabled; int curveSegments = options.curveSegments; int steps = options.steps; Curve extrudePath = options.extrudePath; //Material material = options.material; //Material extrudeMaterial = options.extrudeMaterial; // Use default WorldUVGenerator if no UV generators are specified. WorldUVGenerator uvgen = options.UVGenerator; if (uvgen == null) { uvgen = new WorldUVGenerator(); } List <Vector3> extrudePts = new List <Vector3>(); bool extrudeByPath = false; THREE.TubeGeometry.FrenetFrames splineTube = null; Vector3 binormal, normal, position2; bool isClosePath = false; if (extrudePath != null) { extrudePts = extrudePath.getSpacedPoints(steps); extrudeByPath = true; bevelEnabled = false; // bevels not supported for path extrusion isClosePath = (extrudePath.GetType() == typeof(ClosedSplineCurve3)); // add inok // SETUP TNB variables // Reuse TNB from TubeGeomtry for now. splineTube = options.frames; if (splineTube == null) { splineTube = new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, isClosePath); options.frames = splineTube; } binormal = new Vector3(); normal = new Vector3(); position2 = new Vector3(); } else { Debug.Log("no extrudePath"); } // Safeguards if bevels are not enabled if (!bevelEnabled) { bevelSegments = 0; bevelThickness = 0; bevelSize = 0; } // Variables initalization //var ahole, h, hl; // looping of holes List <Vector3> ahole; //int shapesOffset = this.vertices.Count; int shapesOffset = vertIndex; // ShapeAndHoleObject shapePoints = shape.extractPoints( curveSegments ); // // List<Vector3> vertices = shapePoints.shape; // List<List<Vector3>> holes = shapePoints.holes; // // bool reverse = !Shape.Utils.isClockWise( vertices ) ; // // if ( reverse ) { // vertices.Reverse(); // // for (int h = 0, hl = holes.Count; h < hl; h ++ ) { // ahole = holes[ h ]; // // if ( Shape.Utils.isClockWise( ahole ) ) { // ahole.Reverse(); // holes[ h ] = ahole; // } // } // } List <Vector3> vertices = shapePoints.shapeVertices; List <List <Vector3> > holes = shapePoints.holes; bool reverse = shapePoints.reverse; List <List <int> > faces = Shape.Utils.triangulateShape(vertices, holes); /* Vertices */ //List<Vector3> contour = vertices; // vertices has all points but contour has only points of circumference List <Vector3> contour = new List <Vector3>(); // 上記だとholeが上手くいかない。改良の余地あり contour.AddRange(vertices); for (int h = 0, hl = holes.Count; h < hl; h++) { ahole = holes[h]; vertices.AddRange(ahole); } float t; float z, bs; Vector3 vert; int vlen = vertices.Count; //Face3 face; int flen = faces.Count; List <Vector3> contourMovements = new List <Vector3>(); for (int i = 0, il = contour.Count, j = il - 1, k = i + 1; i < il; i++, j++, k++) { if (j == il) { j = 0; } if (k == il) { k = 0; } // (j)---(i)---(k) Vector3 bevelVec = getBevelVec(contour[i], contour[j], contour[k]); contourMovements.Add(bevelVec); //contourMovements[ i ] = bevelVec; } List <List <Vector3> > holesMovements = new List <List <Vector3> >(); List <Vector3> oneHoleMovements; //verticesMovements = contourMovements.concat(); // TODO: Check ///////// List <Vector3> verticesMovements = new List <Vector3>(); verticesMovements.AddRange(contourMovements); // COPY???? //List<Vector3> ahole; for (int h = 0, hl = holes.Count; h < hl; h++) { ahole = holes[h]; oneHoleMovements = new List <Vector3>(); for (int i = 0, il = ahole.Count, j = il - 1, k = i + 1; i < il; i++, j++, k++) { if (j == il) { j = 0; } if (k == il) { k = 0; } // (j)---(i)---(k) //oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); Vector3 bevelVec = getBevelVec(ahole[i], ahole[j], ahole[k]); oneHoleMovements.Add(bevelVec); } holesMovements.Add(oneHoleMovements); verticesMovements.AddRange(oneHoleMovements); } // Loop bevelSegments, 1 for the front, 1 for the back for (int b = 0; b < bevelSegments; b++) { t = (float)b / bevelSegments; z = bevelThickness * (1 - t); bs = bevelSize * (Mathf.Sin(t * Mathf.PI / 2)); // curved // contract shape for (int i = 0, il = contour.Count; i < il; i++) { vert = scalePt2(contour[i], contourMovements[i], bs); addVertex(vert.x, vert.y, -z); } // expand holes for (int h = 0, hl = holes.Count; h < hl; h++) { ahole = holes[h]; oneHoleMovements = holesMovements[h]; for (int i = 0, il = ahole.Count; i < il; i++) { vert = scalePt2(ahole[i], oneHoleMovements[i], bs); addVertex(vert.x, vert.y, -z); } } } bs = bevelSize; // Back facing vertices for (int i = 0; i < vlen; i++) { vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; if (!extrudeByPath) { addVertex(vert.x, vert.y, 0); } else { normal = splineTube.normals[0] * (vert.x); binormal = splineTube.binormals[0] * (vert.y); position2 = (extrudePts[0]) + (normal) + (binormal); addVertex(position2.x, position2.y, position2.z); } } // Add stepped vertices... // Including front facing vertices for (int s = 1; s <= steps; s++) { for (int i = 0; i < vlen; i++) { vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; if (!extrudeByPath) { addVertex(vert.x, vert.y, (float)amount / steps * s); } else { normal = splineTube.normals[s] * (vert.x); binormal = (splineTube.binormals[s]) * (vert.y); position2 = (extrudePts[s]) + (normal) + (binormal); addVertex(position2.x, position2.y, position2.z); } } } // Add bevel segments planes for (int b = bevelSegments - 1; b >= 0; b--) { t = (float)b / bevelSegments; z = bevelThickness * (1.0f - t); bs = bevelSize * Mathf.Sin(t * Mathf.PI / 2.0f); // contract shape for (int i = 0, il = contour.Count; i < il; i++) { vert = scalePt2(contour[i], contourMovements[i], bs); addVertex(vert.x, vert.y, (float)amount + z); } // expand holes for (int h = 0, hl = holes.Count; h < hl; h++) { ahole = holes[h]; oneHoleMovements = holesMovements[h]; for (int i = 0, il = ahole.Count; i < il; i++) { vert = scalePt2(ahole[i], oneHoleMovements[i], bs); if (!extrudeByPath) { addVertex(vert.x, vert.y, (float)amount + z); } else { addVertex(vert.x, vert.y + extrudePts[steps - 1].y, extrudePts[steps - 1].x + z); } } } } /* Faces */ faceIndex = 0; // Top and bottom faces if (!isClosePath) { buildLidFaces(vlen, faces, flen, steps, bevelSegments, bevelEnabled, shapesOffset, shape, uvgen, options, reverse); } // Sides faces buildSideFaces(vlen, contour, holes, steps, bevelSegments, shapesOffset, uvgen, shape, options, isClosePath, reverse); }