private static Mesh getMeshFromGrid(final ResultGrid resultGrid, float worldScale) {
    Vector3f translate =
        new Vector3f(resultGrid.minLocation.x, resultGrid.minLocation.y, resultGrid.minLocation.z);
    float scale = 1.0f / worldScale;
    Mesh mesh = MarchingCubesMesher.createMesh(resultGrid.dataGrid, scale, translate);

    // Setup bone weight buffer
    FloatBuffer weights = BufferUtils.createFloatBuffer(mesh.getVertexCount() * 4);
    VertexBuffer weightsBuf = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
    weightsBuf.setupData(VertexBuffer.Usage.Static, 4, VertexBuffer.Format.Float, weights);
    mesh.setBuffer(weightsBuf);

    // Setup bone index buffer
    ByteBuffer indices = BufferUtils.createByteBuffer(mesh.getVertexCount() * 4);
    VertexBuffer indicesBuf = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
    indicesBuf.setupData(VertexBuffer.Usage.Static, 4, VertexBuffer.Format.UnsignedByte, indices);
    mesh.setBuffer(indicesBuf);

    Vector3f v1 = new Vector3f();
    Vector3f v2 = new Vector3f();
    Vector3f v3 = new Vector3f();
    for (int i = 0; i < mesh.getTriangleCount(); i++) {
      mesh.getTriangle(i, v1, v2, v3);
      putBoneData(weights, indices, v1, resultGrid, scale, translate);
      putBoneData(weights, indices, v2, resultGrid, scale, translate);
      putBoneData(weights, indices, v3, resultGrid, scale, translate);
    }

    return mesh;
  }
Exemple #2
0
  public static void convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt) {
    geom.updateModelBound();
    BoundingBox bbox = (BoundingBox) geom.getModelBound();
    Mesh mesh = geom.getMesh();

    VertexBuffer positions = mesh.getBuffer(Type.Position);
    VertexBuffer normals = mesh.getBuffer(Type.Normal);
    VertexBuffer texcoords = mesh.getBuffer(Type.TexCoord);
    VertexBuffer indices = mesh.getBuffer(Type.Index);

    // positions
    FloatBuffer fb = (FloatBuffer) positions.getData();
    if (posFmt != Format.Float) {
      Buffer newBuf =
          VertexBuffer.createBuffer(posFmt, positions.getNumComponents(), mesh.getVertexCount());
      Transform t = convertPositions(fb, bbox, newBuf);
      t.combineWithParent(geom.getLocalTransform());
      geom.setLocalTransform(t);

      VertexBuffer newPosVb = new VertexBuffer(Type.Position);
      newPosVb.setupData(positions.getUsage(), positions.getNumComponents(), posFmt, newBuf);
      mesh.clearBuffer(Type.Position);
      mesh.setBuffer(newPosVb);
    }

    // normals, automatically convert to signed byte
    fb = (FloatBuffer) normals.getData();

    ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
    convertNormals(fb, bb);

    normals = new VertexBuffer(Type.Normal);
    normals.setupData(Usage.Static, 3, Format.Byte, bb);
    normals.setNormalized(true);
    mesh.clearBuffer(Type.Normal);
    mesh.setBuffer(normals);

    // texcoords
    fb = (FloatBuffer) texcoords.getData();
    if (tcFmt != Format.Float) {
      Buffer newBuf =
          VertexBuffer.createBuffer(tcFmt, texcoords.getNumComponents(), mesh.getVertexCount());
      convertTexCoords2D(fb, newBuf);

      VertexBuffer newTcVb = new VertexBuffer(Type.TexCoord);
      newTcVb.setupData(texcoords.getUsage(), texcoords.getNumComponents(), tcFmt, newBuf);
      mesh.clearBuffer(Type.TexCoord);
      mesh.setBuffer(newTcVb);
    }
  }
Exemple #3
0
  public static void compressIndexBuffer(Mesh mesh) {
    int vertCount = mesh.getVertexCount();
    VertexBuffer vb = mesh.getBuffer(Type.Index);
    Format targetFmt;
    if (vb.getFormat() == Format.UnsignedInt && vertCount <= 0xffff) {
      if (vertCount <= 256) targetFmt = Format.UnsignedByte;
      else targetFmt = Format.UnsignedShort;
    } else if (vb.getFormat() == Format.UnsignedShort && vertCount <= 0xff) {
      targetFmt = Format.UnsignedByte;
    } else {
      return;
    }

    IndexBuffer src = mesh.getIndexBuffer();
    Buffer newBuf = VertexBuffer.createBuffer(targetFmt, vb.getNumComponents(), src.size());

    VertexBuffer newVb = new VertexBuffer(Type.Index);
    newVb.setupData(vb.getUsage(), vb.getNumComponents(), targetFmt, newBuf);
    mesh.clearBuffer(Type.Index);
    mesh.setBuffer(newVb);

    IndexBuffer dst = mesh.getIndexBuffer();
    for (int i = 0; i < src.size(); i++) {
      dst.put(i, src.get(i));
    }
  }
  public RenderDeviceJme(NiftyJmeDisplay display) {
    this.display = display;

    quadColor = new VertexBuffer(Type.Color);
    quadColor.setNormalized(true);
    ByteBuffer bb = BufferUtils.createByteBuffer(4 * 4);
    quadColor.setupData(Usage.Stream, 4, Format.UnsignedByte, bb);
    quad.setBuffer(quadColor);

    quadModTC.setUsage(Usage.Stream);

    // Load the 3 material types separately to avoid
    // reloading the shader when the defines change.

    // Material with a single color (no texture or vertex color)
    colorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");

    // Material with a texture and a color (no vertex color)
    textureColorMaterial =
        new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");

    // Material with vertex color, used for gradients (no texture)
    vertexColorMaterial =
        new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
    vertexColorMaterial.setBoolean("VertexColor", true);

    // Shared render state for all materials
    renderState.setDepthTest(false);
    renderState.setDepthWrite(false);
  }
Exemple #5
0
  public static VertexBuffer convertToUByte(VertexBuffer vb) {
    FloatBuffer fb = (FloatBuffer) vb.getData();
    ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
    convertToUByte(fb, bb);

    VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
    newVb.setupData(vb.getUsage(), vb.getNumComponents(), Format.UnsignedByte, bb);
    newVb.setNormalized(true);
    return newVb;
  }
Exemple #6
0
  public static VertexBuffer convertToFloat(VertexBuffer vb) {
    if (vb.getFormat() == Format.Float) return vb;

    IntBuffer ib = (IntBuffer) vb.getData();
    FloatBuffer fb = BufferUtils.createFloatBuffer(ib.capacity());
    convertToFloat(ib, fb);

    VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
    newVb.setupData(vb.getUsage(), vb.getNumComponents(), Format.Float, fb);
    return newVb;
  }
  public static void generate(Mesh mesh, boolean approxTangents, boolean splitMirrored) {
    int[] index = new int[3];
    Vector3f[] v = new Vector3f[3];
    Vector2f[] t = new Vector2f[3];
    for (int i = 0; i < 3; i++) {
      v[i] = new Vector3f();
      t[i] = new Vector2f();
    }

    if (mesh.getBuffer(Type.Normal) == null) {
      throw new IllegalArgumentException("The given mesh has no normal data!");
    }

    List<VertexData> vertices;
    switch (mesh.getMode()) {
      case Triangles:
        vertices = processTriangles(mesh, index, v, t, splitMirrored);
        if (splitMirrored) {
          splitVertices(mesh, vertices, splitMirrored);
        }
        break;
      case TriangleStrip:
        vertices = processTriangleStrip(mesh, index, v, t);
        break;
      case TriangleFan:
        vertices = processTriangleFan(mesh, index, v, t);
        break;
      default:
        throw new UnsupportedOperationException(mesh.getMode() + " is not supported.");
    }

    processTriangleData(mesh, vertices, approxTangents, splitMirrored);

    // if the mesh has a bind pose, we need to generate the bind pose for the tangent buffer
    if (mesh.getBuffer(Type.BindPosePosition) != null) {

      VertexBuffer tangents = mesh.getBuffer(Type.Tangent);
      if (tangents != null) {
        VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent);
        bindTangents.setupData(
            Usage.CpuOnly, 4, Format.Float, BufferUtils.clone(tangents.getData()));

        if (mesh.getBuffer(Type.BindPoseTangent) != null) {
          mesh.clearBuffer(Type.BindPoseTangent);
        }
        mesh.setBuffer(bindTangents);
        tangents.setUsage(Usage.Stream);
      }
    }
  }
  /**
   * Merges all geometries in the collection into the output mesh. Creates a new material using the
   * TextureAtlas.
   *
   * @param geometries
   * @param outMesh
   */
  public static void mergeGeometries(Collection<Geometry> geometries, Mesh outMesh) {
    int[] compsForBuf = new int[VertexBuffer.Type.values().length];
    Format[] formatForBuf = new Format[compsForBuf.length];

    int totalVerts = 0;
    int totalTris = 0;
    int totalLodLevels = 0;
    int maxWeights = -1;

    Mode mode = null;
    for (Geometry geom : geometries) {
      totalVerts += geom.getVertexCount();
      totalTris += geom.getTriangleCount();
      totalLodLevels = Math.min(totalLodLevels, geom.getMesh().getNumLodLevels());

      Mode listMode;
      int components;
      switch (geom.getMesh().getMode()) {
        case Points:
          listMode = Mode.Points;
          components = 1;
          break;
        case LineLoop:
        case LineStrip:
        case Lines:
          listMode = Mode.Lines;
          components = 2;
          break;
        case TriangleFan:
        case TriangleStrip:
        case Triangles:
          listMode = Mode.Triangles;
          components = 3;
          break;
        default:
          throw new UnsupportedOperationException();
      }

      for (VertexBuffer vb : geom.getMesh().getBufferList().getArray()) {
        int currentCompsForBuf = compsForBuf[vb.getBufferType().ordinal()];
        if (vb.getBufferType() != Type.Index
            && currentCompsForBuf != 0
            && currentCompsForBuf != vb.getNumComponents()) {
          throw new UnsupportedOperationException(
              "The geometry "
                  + geom
                  + " buffer "
                  + vb.getBufferType()
                  + " has different number of components than the rest of the meshes "
                  + "(this: "
                  + vb.getNumComponents()
                  + ", expected: "
                  + currentCompsForBuf
                  + ")");
        }
        compsForBuf[vb.getBufferType().ordinal()] = vb.getNumComponents();
        formatForBuf[vb.getBufferType().ordinal()] = vb.getFormat();
      }

      maxWeights = Math.max(maxWeights, geom.getMesh().getMaxNumWeights());

      if (mode != null && mode != listMode) {
        throw new UnsupportedOperationException(
            "Cannot combine different" + " primitive types: " + mode + " != " + listMode);
      }
      mode = listMode;
      compsForBuf[Type.Index.ordinal()] = components;
    }

    outMesh.setMaxNumWeights(maxWeights);
    outMesh.setMode(mode);
    if (totalVerts >= 65536) {
      // make sure we create an UnsignedInt buffer so
      // we can fit all of the meshes
      formatForBuf[Type.Index.ordinal()] = Format.UnsignedInt;
    } else {
      formatForBuf[Type.Index.ordinal()] = Format.UnsignedShort;
    }

    // generate output buffers based on retrieved info
    for (int i = 0; i < compsForBuf.length; i++) {
      if (compsForBuf[i] == 0) {
        continue;
      }

      Buffer data;
      if (i == Type.Index.ordinal()) {
        data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalTris);
      } else {
        data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalVerts);
      }

      VertexBuffer vb = new VertexBuffer(Type.values()[i]);
      vb.setupData(Usage.Static, compsForBuf[i], formatForBuf[i], data);
      outMesh.setBuffer(vb);
    }

    int globalVertIndex = 0;
    int globalTriIndex = 0;

    for (Geometry geom : geometries) {
      Mesh inMesh = geom.getMesh();
      geom.computeWorldMatrix();
      Matrix4f worldMatrix = geom.getWorldMatrix();

      int geomVertCount = inMesh.getVertexCount();
      int geomTriCount = inMesh.getTriangleCount();

      for (int bufType = 0; bufType < compsForBuf.length; bufType++) {
        VertexBuffer inBuf = inMesh.getBuffer(Type.values()[bufType]);
        VertexBuffer outBuf = outMesh.getBuffer(Type.values()[bufType]);

        if (inBuf == null || outBuf == null) {
          continue;
        }

        if (Type.Index.ordinal() == bufType) {
          int components = compsForBuf[bufType];

          IndexBuffer inIdx = inMesh.getIndicesAsList();
          IndexBuffer outIdx = outMesh.getIndexBuffer();

          for (int tri = 0; tri < geomTriCount; tri++) {
            for (int comp = 0; comp < components; comp++) {
              int idx = inIdx.get(tri * components + comp) + globalVertIndex;
              outIdx.put((globalTriIndex + tri) * components + comp, idx);
            }
          }
        } else if (Type.Position.ordinal() == bufType) {
          FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
          FloatBuffer outPos = (FloatBuffer) outBuf.getData();
          doTransformVerts(inPos, globalVertIndex, outPos, worldMatrix);
        } else if (Type.Normal.ordinal() == bufType) {
          FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
          FloatBuffer outPos = (FloatBuffer) outBuf.getData();
          doTransformNorms(inPos, globalVertIndex, outPos, worldMatrix);
        } else if (Type.Tangent.ordinal() == bufType) {
          FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
          FloatBuffer outPos = (FloatBuffer) outBuf.getData();
          int components = inBuf.getNumComponents();
          doTransformTangents(inPos, globalVertIndex, components, outPos, worldMatrix);
        } else {
          inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount);
        }
      }

      globalVertIndex += geomVertCount;
      globalTriIndex += geomTriCount;
    }
  }
  /**
   * This method returns an array of size 2. The first element is a vertex buffer holding bone
   * weights for every vertex in the model. The second element is a vertex buffer holding bone
   * indices for vertices (the indices of bones the vertices are assigned to).
   *
   * @param meshStructure the mesh structure object
   * @param vertexListSize a number of vertices in the model
   * @param bonesGroups this is an output parameter, it should be a one-sized array; the maximum
   *     amount of weights per vertex (up to MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
   * @param vertexReferenceMap this reference map allows to map the original vertices read from
   *     blender to vertices that are really in the model; one vertex may appear several times in
   *     the result model
   * @param groupToBoneIndexMap this object maps the group index (to which a vertices in blender
   *     belong) to bone index of the model
   * @param blenderContext the blender context
   * @return arrays of vertices weights and their bone indices and (as an output parameter) the
   *     maximum amount of weights for a vertex
   * @throws BlenderFileException this exception is thrown when the blend file structure is somehow
   *     invalid or corrupted
   */
  private VertexBuffer[] getBoneWeightAndIndexBuffer(
      Structure meshStructure,
      int vertexListSize,
      int[] bonesGroups,
      Map<Integer, List<Integer>> vertexReferenceMap,
      Map<Integer, Integer> groupToBoneIndexMap,
      BlenderContext blenderContext)
      throws BlenderFileException {
    Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert"); // dvert = DeformVERTices
    FloatBuffer weightsFloatData =
        BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
    ByteBuffer indicesData =
        BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
    if (pDvert.isNotNull()) { // assigning weights and bone indices
      List<Structure> dverts =
          pDvert.fetchData(
              blenderContext.getInputStream()); // dverts.size() == verticesAmount (one dvert per
      // vertex in blender)
      int vertexIndex = 0;
      for (Structure dvert : dverts) {
        int totweight =
            ((Number) dvert.getFieldValue("totweight"))
                .intValue(); // total amount of weights assignet to the vertex
        // (max. 4 in JME)
        Pointer pDW = (Pointer) dvert.getFieldValue("dw");
        List<Integer> vertexIndices =
            vertexReferenceMap.get(
                Integer.valueOf(vertexIndex)); // we fetch the referenced vertices here
        if (totweight > 0
            && pDW.isNotNull()
            && groupToBoneIndexMap
                != null) { // pDW should never be null here, but I check it just in case :)
          int weightIndex = 0;
          List<Structure> dw = pDW.fetchData(blenderContext.getInputStream());
          for (Structure deformWeight : dw) {
            Integer boneIndex =
                groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());

            // Remove this code if 4 weights limitation is removed
            if (weightIndex == 4) {
              LOGGER.log(
                  Level.WARNING,
                  "{0} has more than 4 weight on bone index {1}",
                  new Object[] {meshStructure.getName(), boneIndex});
              break;
            }

            if (boneIndex
                != null) { // null here means that we came accross group that has no bone attached
                           // to
              float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
              if (weight == 0.0f) {
                weight = 1;
                boneIndex = Integer.valueOf(0);
              }
              // we apply the weight to all referenced vertices
              for (Integer index : vertexIndices) {
                weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
                indicesData.put(
                    index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
              }
            }
            ++weightIndex;
          }
        } else {
          for (Integer index : vertexIndices) {
            weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
            indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
          }
        }
        ++vertexIndex;
      }
    } else {
      // always bind all vertices to 0-indexed bone
      // this bone makes the model look normally if vertices have no bone assigned
      // and it is used in object animation, so if we come accross object animation
      // we can use the 0-indexed bone for this
      for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
        // we apply the weight to all referenced vertices
        for (Integer index : vertexIndexList) {
          weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
          indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
        }
      }
    }

    bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);
    VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);
    verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);

    VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);
    verticesWeightsIndices.setupData(
        Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
    return new VertexBuffer[] {verticesWeights, verticesWeightsIndices};
  }