ParametricGeometry constructor

ParametricGeometry(
  1. dynamic func(
    1. double,
    2. double,
    3. Vector3
    ),
  2. int slices,
  3. int stacks
)

func — A function that takes in a u and v value each between 0 and 1 and modifies a third Vector3 argument. Default is a function that generates a curved plane surface.

slices — The count of slices to use for the parametric function. Default is 8.

stacks — The count of stacks to use for the parametric function. Default is 8.

Implementation

ParametricGeometry(Function(double,double,Vector3) func, int slices, int stacks) : super() {
  type = "ParametricGeometry";
  parameters = {"func": func, "slices": slices, "stacks": stacks};

  // buffers

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

  const eps = 0.00001;

  final normal = Vector3.zero();

  final p0 = Vector3.zero(), p1 = Vector3.zero();
  final pu = Vector3.zero(), pv = Vector3.zero();

  final sliceCount = slices + 1;

  for (int i = 0; i <= stacks; i++) {
    final v = i / stacks;

    for (int j = 0; j <= slices; j++) {
      final u = j / slices;

      // vertex

      func(u, v, p0);
      vertices.addAll([p0.x.toDouble(), p0.y.toDouble(), p0.z.toDouble()]);

      // normal

      // approximate tangent vectors via finite differences

      if (u - eps >= 0) {
        func(u - eps, v, p1);
        pu.sub2(p0, p1);
      } else {
        func(u + eps, v, p1);
        pu.sub2(p1, p0);
      }

      if (v - eps >= 0) {
        func(u, v - eps, p1);
        pv.sub2(p0, p1);
      } else {
        func(u, v + eps, p1);
        pv.sub2(p1, p0);
      }

      // cross product of tangent vectors returns surface normal

      normal.cross2(pu, pv).normalize();
      normals.addAll(
          [normal.x.toDouble(), normal.y.toDouble(), normal.z.toDouble()]);

      // uv

      uvs.addAll([u, v]);
    }
  }

  // generate indices

  for (int i = 0; i < stacks; i++) {
    for (int j = 0; j < slices; j++) {
      final a = i * sliceCount + j;
      final b = i * sliceCount + j + 1;
      final c = (i + 1) * sliceCount + j + 1;
      final d = (i + 1) * sliceCount + j;

      // faces one and two

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

  // build geometry

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