예제 #1
0
 /** Apply small blur filter on the grid. */
 private static void blurGrid(ByteArray3d grid) {
   int w = grid.getWidth();
   int h = grid.getHeight();
   int d = grid.getDepth();
   for (int x = 1; x < w - 1; x++) {
     for (int y = 1; y < h - 1; y++) {
       for (int z = 1; z < d - 1; z++) {
         int newVal =
             ((int) grid.get(x, y, z)
                     + grid.get(x - 1, y, z)
                     + grid.get(x + 1, y, z)
                     + grid.get(x, y - 1, z)
                     + grid.get(x, y + 1, z)
                     + grid.get(x, y, z - 1)
                     + grid.get(x, y, z + 1))
                 / 7;
         grid.set(x, y, z, (byte) newVal);
       }
     }
   }
 }
예제 #2
0
  private static ResultGrid makeResultGrid(List<BoneWorldGrid> boneWorldGrids) {
    // find min and max location for all BoneWorldGrids
    Vector3i minLocation = new Vector3i(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
    Vector3i maxLocation = new Vector3i(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
    for (BoneWorldGrid bwg : boneWorldGrids) {
      minLocation.x = Math.min(minLocation.x, bwg.location.x);
      minLocation.y = Math.min(minLocation.y, bwg.location.y);
      minLocation.z = Math.min(minLocation.z, bwg.location.z);

      maxLocation.x = Math.max(maxLocation.x, bwg.location.x + bwg.grid.getWidth());
      maxLocation.y = Math.max(maxLocation.y, bwg.location.y + bwg.grid.getHeight());
      maxLocation.z = Math.max(maxLocation.z, bwg.location.z + bwg.grid.getDepth());
    }

    int requiredSize =
        Math.max(
            Math.max(maxLocation.x - minLocation.x, maxLocation.y - minLocation.y),
            maxLocation.z - minLocation.z);
    // System.out.println("required grid size = " + requiredSize);

    ResultGrid resultGrid = new ResultGrid();
    resultGrid.minLocation = minLocation;
    resultGrid.dataGrid = new ByteArray3d(requiredSize, requiredSize, requiredSize);
    for (int i = 0; i < MAX_BONES_PER_TILE; i++) {
      resultGrid.boneIndexGrid[i] = new ByteArray3d(requiredSize, requiredSize, requiredSize);
      resultGrid.boneWeightGrid[i] = new ByteArray3d(requiredSize, requiredSize, requiredSize);
    }

    ByteArray3d dataGrid = resultGrid.dataGrid;

    int boneIndex = 0;
    for (BoneWorldGrid bwg : boneWorldGrids) {
      ByteArray3d grid = bwg.grid;
      int w = grid.getWidth();
      int h = grid.getHeight();
      int d = grid.getDepth();
      Vector3i offset = bwg.location.subtract(minLocation);
      Vector3i pos = new Vector3i();
      for (int x = 0; x < w; x++) {
        for (int y = 0; y < h; y++) {
          for (int z = 0; z < d; z++) {
            byte add = grid.get(x, y, z);
            if (add > 0) {
              pos.set(x + offset.x, y + offset.y, z + offset.z);
              byte old = dataGrid.get(pos);
              int newValue = (int) old + (int) add;
              // int newValue = Math.max((int) old, (int) add);
              if (newValue > 127) {
                newValue = 127;
              }
              dataGrid.set(pos, (byte) newValue);

              // assign bone weight in next free slot in boneWeightGrid
              int bcount = 0;
              while (bcount < MAX_BONES_PER_TILE
                  && resultGrid.boneWeightGrid[bcount].get(pos) != 0) {
                bcount++;
              }
              if (bcount < MAX_BONES_PER_TILE) {
                resultGrid.boneIndexGrid[bcount].set(pos, (byte) boneIndex);
                resultGrid.boneWeightGrid[bcount].set(pos, add);
              }
            }
          }
        }
      }
      boneIndex++;
    }
    return resultGrid;
  }
예제 #3
0
  private static BoneWorldGrid makeBoneWorldGrid(
      ByteArray3d boneMeshGrid, float worldScale, MyBone bone) {
    Transform transform = BoneTransformUtils.boneTransform2(bone);
    // bounding box needed for boneMeshGrid in world grid:
    float bs = 1.0f;
    Vector3f c1 =
        transform.transformVector(new Vector3f(-bs, -bs, -bs), null).multLocal(worldScale);
    Vector3f c2 =
        transform.transformVector(new Vector3f(+bs, -bs, -bs), null).multLocal(worldScale);
    Vector3f c3 =
        transform.transformVector(new Vector3f(-bs, +bs, -bs), null).multLocal(worldScale);
    Vector3f c4 =
        transform.transformVector(new Vector3f(-bs, -bs, +bs), null).multLocal(worldScale);
    Vector3f c5 =
        transform.transformVector(new Vector3f(+bs, +bs, -bs), null).multLocal(worldScale);
    Vector3f c6 =
        transform.transformVector(new Vector3f(-bs, +bs, +bs), null).multLocal(worldScale);
    Vector3f c7 =
        transform.transformVector(new Vector3f(+bs, -bs, +bs), null).multLocal(worldScale);
    Vector3f c8 =
        transform.transformVector(new Vector3f(+bs, +bs, +bs), null).multLocal(worldScale);

    Vector3f cmin = c1.clone();
    cmin.minLocal(c2);
    cmin.minLocal(c3);
    cmin.minLocal(c4);
    cmin.minLocal(c5);
    cmin.minLocal(c6);
    cmin.minLocal(c7);
    cmin.minLocal(c8);
    Vector3f cmax = c1.clone();
    cmax.maxLocal(c2);
    cmax.maxLocal(c3);
    cmax.maxLocal(c4);
    cmax.maxLocal(c5);
    cmax.maxLocal(c6);
    cmax.maxLocal(c7);
    cmax.maxLocal(c8);

    int xsize = (int) FastMath.ceil(cmax.x - cmin.x);
    int ysize = (int) FastMath.ceil(cmax.y - cmin.y);
    int zsize = (int) FastMath.ceil(cmax.z - cmin.z);

    ByteArray3d grid = new ByteArray3d(xsize, ysize, zsize);
    int w = grid.getWidth();
    int h = grid.getHeight();
    int d = grid.getDepth();
    Vector3f v = new Vector3f();
    Vector3f inv = new Vector3f();
    Vector3f inv2 = new Vector3f();

    // we want to calculate transform: (inv - (-bs)) * (sz / (bs - (-bs)))
    // se let's precalculate it to (inv + shift) * scale
    Vector3f scale =
        new Vector3f(boneMeshGrid.getWidth(), boneMeshGrid.getHeight(), boneMeshGrid.getDepth())
            .divideLocal(bs * 2);
    Vector3f shift = Vector3f.UNIT_XYZ.mult(bs);

    for (int x = 0; x < w; x++) {
      for (int y = 0; y < h; y++) {
        // calculate inverse transform at (x,y,0) and (x,y,1), the rest of the transforms in inner
        // loop
        // can be calculated by adding (inv2-inv1) because the transforms are linear
        v.set(x, y, 0).addLocal(cmin).divideLocal(worldScale);
        transform.transformInverseVector(v, inv);
        inv.addLocal(shift).multLocal(scale);

        v.set(x, y, 1).addLocal(cmin).divideLocal(worldScale);
        transform.transformInverseVector(v, inv2);
        inv2.addLocal(shift).multLocal(scale);

        Vector3f add = inv2.subtractLocal(inv);

        for (int z = 0; z < d; z++) {
          inv.addLocal(add);
          if (inv.x >= 0
              && inv.x < boneMeshGrid.getWidth()
              && inv.y >= 0
              && inv.y < boneMeshGrid.getHeight()
              && inv.z >= 0
              && inv.z < boneMeshGrid.getDepth()) {

            grid.set(x, y, z, boneMeshGrid.get((int) inv.x, (int) inv.y, (int) inv.z));
          }
        }
      }
    }

    // Once the boneMeshGrid has been transformed into world grid, it may suffer from
    // downsampling and upsampling artifacts (because the sampling is very simple nearest-neighbor).
    // Blurring the grid helps with both issues (blur=fake antialias). It has the added benefit
    // that each BoneWorldGrid will have some "smoothing buffer" around the actual shape, so that
    // the shape blends better with other bones' shapes.
    blurGrid(grid);

    BoneWorldGrid bwg2 = new BoneWorldGrid();
    bwg2.grid = grid;
    bwg2.location = new Vector3i(Math.round(cmin.x), Math.round(cmin.y), Math.round(cmin.z));
    return bwg2;
  }