CylinderGeometry constructor

CylinderGeometry([
  1. double radiusTop = 1,
  2. double radiusBottom = 1,
  3. double height = 1,
  4. int radialSegments = 8,
  5. int heightSegments = 1,
  6. bool openEnded = false,
  7. num thetaStart = 0,
  8. double thetaLength = math.pi * 2,
])

radiusTop — Radius of the cylinder at the top. Default is 1.

radiusBottom — Radius of the cylinder at the bottom. Default is 1.

height — Height of the cylinder. Default is 1.

radialSegments — Number of segmented faces around the circumference of the cylinder. Default is 32

heightSegments — Number of rows of faces along the height of the cylinder. Default is 1.

openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped.

thetaStart — Start angle for first segment, default = 0 (three o'clock position).

thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete cylinder.

Implementation

CylinderGeometry([
  double radiusTop = 1,
  double radiusBottom = 1,
  double height = 1,
  int radialSegments = 8,
  int heightSegments = 1,
  bool openEnded = false,
  num thetaStart = 0,
  double thetaLength = math.pi * 2
]): super() {
  type = "Cylinder";
  parameters = {
    "radiusTop": radiusTop,
    "radiusBottom": radiusBottom,
    "height": height,
    "radialSegments": radialSegments,
    "heightSegments": heightSegments,
    "openEnded": openEnded,
    "thetaStart": thetaStart,
    "thetaLength": thetaLength
  };

  final scope = this;

  // radialSegments = math.floor(radialSegments);
  // heightSegments = math.floor(heightSegments);

  // buffers

  List<num> indices = [];
  List<double> vertices = [];
  List<double> normals = [];
  List<double> uvs = [];

  // helper variables

  int index = 0;
  final indexArray = [];
  final halfHeight = height / 2;
  int groupStart = 0;

  // generate geometry

  void generateTorso() {
    final normal = Vector3.zero();
    final vertex = Vector3.zero();

    int groupCount = 0;

    // this will be used to calculate the normal
    final slope = (radiusBottom - radiusTop) / height;

    // generate vertices, normals and uvs

    for (int y = 0; y <= heightSegments; y++) {
      final indexRow = [];

      final v = y / heightSegments;

      // calculate the radius of the current row

      final radius = v * (radiusBottom - radiusTop) + radiusTop;

      for (int x = 0; x <= radialSegments; x++) {
        final u = x / radialSegments;

        final theta = u * thetaLength + thetaStart;

        final sinTheta = math.sin(theta);
        final cosTheta = math.cos(theta);

        // vertex

        vertex.x = radius * sinTheta;
        vertex.y = -v * height + halfHeight;
        vertex.z = radius * cosTheta;
        vertices.addAll(
            [vertex.x.toDouble(), vertex.y.toDouble(), vertex.z.toDouble()]);

        // normal

        normal..setValues(sinTheta, slope, cosTheta)..normalize();
        normals.addAll(
            [normal.x.toDouble(), normal.y.toDouble(), normal.z.toDouble()]);

        // uv

        uvs.addAll([u, 1 - v]);

        // save index of vertex in respective row

        indexRow.add(index++);
      }

      // now save vertices of the row in our index array

      indexArray.add(indexRow);
    }

    // generate indices

    for (int x = 0; x < radialSegments; x++) {
      for (int y = 0; y < heightSegments; y++) {
        // we use the index array to access the correct indices

        final a = indexArray[y][x];
        final b = indexArray[y + 1][x];
        final c = indexArray[y + 1][x + 1];
        final d = indexArray[y][x + 1];

        // faces

        indices.addAll([a, b, d]);
        indices.addAll([b, c, d]);

        // update group counter

        groupCount += 6;
      }
    }

    // add a group to the geometry. this will ensure multi material support

    scope.addGroup(groupStart, groupCount, 0);

    // calculate new start value for groups

    groupStart += groupCount;
  }

  void generateCap(bool top) {
    // save the index of the first center vertex
    final centerIndexStart = index;

    final uv = Vector2.zero();
    final vertex = Vector3.zero();

    int groupCount = 0;

    final radius = (top == true) ? radiusTop : radiusBottom;
    final sign = (top == true) ? 1 : -1;

    // first we generate the center vertex data of the cap.
    // because the geometry needs one set of uvs per face,
    // we must generate a center vertex per face/segment

    for (int x = 1; x <= radialSegments; x++) {
      // vertex

      vertices.addAll([0, halfHeight * sign, 0]);

      // normal

      normals.addAll([0, sign.toDouble(), 0]);

      // uv

      uvs.addAll([0.5, 0.5]);

      // increase index

      index++;
    }

    // save the index of the last center vertex
    final centerIndexEnd = index;

    // now we generate the surrounding vertices, normals and uvs

    for (int x = 0; x <= radialSegments; x++) {
      final u = x / radialSegments;
      final theta = u * thetaLength + thetaStart;

      final cosTheta = math.cos(theta);
      final sinTheta = math.sin(theta);

      // vertex

      vertex.x = radius * sinTheta;
      vertex.y = halfHeight * sign;
      vertex.z = radius * cosTheta;
      vertices.addAll(
          [vertex.x.toDouble(), vertex.y.toDouble(), vertex.z.toDouble()]);

      // normal

      normals.addAll([0, sign.toDouble(), 0]);

      // uv

      uv.x = (cosTheta * 0.5) + 0.5;
      uv.y = (sinTheta * 0.5 * sign) + 0.5;
      uvs.addAll([uv.x.toDouble(), uv.y.toDouble()]);

      // increase index

      index++;
    }

    // generate indices

    for (int x = 0; x < radialSegments; x++) {
      final c = centerIndexStart + x;
      final i = centerIndexEnd + x;

      if (top == true) {
        // face top

        indices.addAll([i, i + 1, c]);
      } else {
        // face bottom

        indices.addAll([i + 1, i, c]);
      }

      groupCount += 3;
    }

    // add a group to the geometry. this will ensure multi material support

    scope.addGroup(groupStart, groupCount,
        top == true ? 1 : 2);

    // calculate new start value for groups

    groupStart += groupCount;
  }

  generateTorso();

  if (openEnded == false) {
    if (radiusTop > 0) generateCap(true);
    if (radiusBottom > 0) generateCap(false);
  }

  // build geometry

  setIndex(indices);
  setAttribute(Attribute.position,Float32BufferAttribute.fromList(vertices, 3, false));
  setAttribute(Attribute.normal, Float32BufferAttribute.fromList(normals, 3, false));
  setAttribute(Attribute.uv, Float32BufferAttribute.fromList(uvs, 2, false));
}