private static List<VertexData> processTriangles(
      Mesh mesh, int[] index, Vector3f[] v, Vector2f[] t, boolean splitMirrored) {
    IndexBuffer indexBuffer = mesh.getIndexBuffer();
    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
    if (mesh.getBuffer(Type.TexCoord) == null) {
      throw new IllegalArgumentException(
          "Can only generate tangents for " + "meshes with texture coordinates");
    }

    FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();

    List<VertexData> vertices = initVertexData(vertexBuffer.limit() / 3);

    for (int i = 0; i < indexBuffer.size() / 3; i++) {
      for (int j = 0; j < 3; j++) {
        index[j] = indexBuffer.get(i * 3 + j);
        populateFromBuffer(v[j], vertexBuffer, index[j]);
        populateFromBuffer(t[j], textureBuffer, index[j]);
      }

      TriangleData triData = processTriangle(index, v, t);
      if (splitMirrored) {
        triData.setIndex(index);
        triData.triangleOffset = i * 3;
      }
      if (triData != null) {
        vertices.get(index[0]).triangles.add(triData);
        vertices.get(index[1]).triangles.add(triData);
        vertices.get(index[2]).triangles.add(triData);
      }
    }

    return vertices;
  }
Пример #2
0
  private static void convertTexCoords2D(FloatBuffer input, Buffer output) {
    if (output.capacity() < input.capacity())
      throw new RuntimeException("Output must be at least as large as input!");

    input.clear();
    output.clear();
    Vector2f temp = new Vector2f();
    int vertexCount = input.capacity() / 2;

    ShortBuffer sb = null;
    IntBuffer ib = null;

    if (output instanceof ShortBuffer) sb = (ShortBuffer) output;
    else if (output instanceof IntBuffer) ib = (IntBuffer) output;
    else throw new UnsupportedOperationException();

    for (int i = 0; i < vertexCount; i++) {
      BufferUtils.populateFromBuffer(temp, input, i);

      if (sb != null) {
        sb.put((short) (temp.getX() * Short.MAX_VALUE));
        sb.put((short) (temp.getY() * Short.MAX_VALUE));
      } else {
        int v1 = (int) (temp.getX() * ((float) (1 << 16)));
        int v2 = (int) (temp.getY() * ((float) (1 << 16)));
        ib.put(v1).put(v2);
      }
    }
  }
  private static ArrayList<VertexInfo> linkVertices(Mesh mesh, boolean splitMirrored) {
    ArrayList<VertexInfo> vertexMap = new ArrayList<VertexInfo>();

    FloatBuffer vertexBuffer = mesh.getFloatBuffer(Type.Position);
    FloatBuffer normalBuffer = mesh.getFloatBuffer(Type.Normal);
    FloatBuffer texcoordBuffer = mesh.getFloatBuffer(Type.TexCoord);

    Vector3f position = new Vector3f();
    Vector3f normal = new Vector3f();
    Vector2f texCoord = new Vector2f();

    final int size = vertexBuffer.limit() / 3;
    for (int i = 0; i < size; i++) {

      populateFromBuffer(position, vertexBuffer, i);
      populateFromBuffer(normal, normalBuffer, i);
      populateFromBuffer(texCoord, texcoordBuffer, i);

      boolean found = false;
      // Nehon 07/07/2013
      // Removed this part, joining splitted vertice to compute tangent space makes no sense to me
      // separate vertice should have separate tangent space
      if (!splitMirrored) {
        for (int j = 0; j < vertexMap.size(); j++) {
          VertexInfo vertexInfo = vertexMap.get(j);
          if (approxEqual(vertexInfo.position, position)
              && approxEqual(vertexInfo.normal, normal)
              && approxEqual(vertexInfo.texCoord, texCoord)) {
            vertexInfo.indices.add(i);
            found = true;
            break;
          }
        }
      }
      if (!found) {
        VertexInfo vertexInfo = new VertexInfo(position.clone(), normal.clone(), texCoord.clone());
        vertexInfo.indices.add(i);
        vertexMap.add(vertexInfo);
      }
    }

    return vertexMap;
  }
  public static Mesh genNormalLines(Mesh mesh, float scale) {
    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
    FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();

    ColorRGBA originColor = ColorRGBA.White;
    ColorRGBA normalColor = ColorRGBA.Blue;

    Mesh lineMesh = new Mesh();
    lineMesh.setMode(Mesh.Mode.Lines);

    Vector3f origin = new Vector3f();
    Vector3f point = new Vector3f();

    FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.limit() * 2);
    FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.limit() / 3 * 4 * 2);

    for (int i = 0; i < vertexBuffer.limit() / 3; i++) {
      populateFromBuffer(origin, vertexBuffer, i);
      populateFromBuffer(point, normalBuffer, i);

      int index = i * 2;

      setInBuffer(origin, lineVertex, index);
      setInBuffer(originColor, lineColor, index);

      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 1);
      setInBuffer(normalColor, lineColor, index + 1);
    }

    lineMesh.setBuffer(Type.Position, 3, lineVertex);
    lineMesh.setBuffer(Type.Color, 4, lineColor);

    lineMesh.setStatic();
    // lineMesh.setInterleaved();
    return lineMesh;
  }
  private static List<VertexData> processTriangleStrip(
      Mesh mesh, int[] index, Vector3f[] v, Vector2f[] t) {
    IndexBuffer indexBuffer = mesh.getIndexBuffer();
    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
    FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();

    List<VertexData> vertices = initVertexData(vertexBuffer.limit() / 3);

    index[0] = indexBuffer.get(0);
    index[1] = indexBuffer.get(1);

    populateFromBuffer(v[0], vertexBuffer, index[0]);
    populateFromBuffer(v[1], vertexBuffer, index[1]);

    populateFromBuffer(t[0], textureBuffer, index[0]);
    populateFromBuffer(t[1], textureBuffer, index[1]);

    for (int i = 2; i < indexBuffer.size(); i++) {
      index[2] = indexBuffer.get(i);
      BufferUtils.populateFromBuffer(v[2], vertexBuffer, index[2]);
      BufferUtils.populateFromBuffer(t[2], textureBuffer, index[2]);

      boolean isDegenerate = isDegenerateTriangle(v[0], v[1], v[2]);
      TriangleData triData = processTriangle(index, v, t);

      if (triData != null && !isDegenerate) {
        vertices.get(index[0]).triangles.add(triData);
        vertices.get(index[1]).triangles.add(triData);
        vertices.get(index[2]).triangles.add(triData);
      }

      Vector3f vTemp = v[0];
      v[0] = v[1];
      v[1] = v[2];
      v[2] = vTemp;

      Vector2f tTemp = t[0];
      t[0] = t[1];
      t[1] = t[2];
      t[2] = tTemp;

      index[0] = index[1];
      index[1] = index[2];
    }

    return vertices;
  }
Пример #6
0
  private static void convertNormals(FloatBuffer input, ByteBuffer output) {
    if (output.capacity() < input.capacity())
      throw new RuntimeException("Output must be at least as large as input!");

    input.clear();
    output.clear();
    Vector3f temp = new Vector3f();
    int vertexCount = input.capacity() / 3;
    for (int i = 0; i < vertexCount; i++) {
      BufferUtils.populateFromBuffer(temp, input, i);

      // offset and scale vector into -128 ... 127
      temp.multLocal(127).addLocal(0.5f, 0.5f, 0.5f);

      // quantize
      byte v1 = (byte) temp.getX();
      byte v2 = (byte) temp.getY();
      byte v3 = (byte) temp.getZ();

      // store
      output.put(v1).put(v2).put(v3);
    }
  }
Пример #7
0
  private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output) {
    if (output.capacity() < input.capacity())
      throw new RuntimeException("Output must be at least as large as input!");

    Vector3f offset = bbox.getCenter().negate();
    Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent());
    size.multLocal(2);

    ShortBuffer sb = null;
    ByteBuffer bb = null;
    float dataTypeSize;
    float dataTypeOffset;
    if (output instanceof ShortBuffer) {
      sb = (ShortBuffer) output;
      dataTypeOffset = shortOff;
      dataTypeSize = shortSize;
    } else {
      bb = (ByteBuffer) output;
      dataTypeOffset = byteOff;
      dataTypeSize = byteSize;
    }
    Vector3f scale = new Vector3f();
    scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size);

    Vector3f invScale = new Vector3f();
    invScale.set(size).divideLocal(dataTypeSize);

    offset.multLocal(scale);
    offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset);

    // offset = (-modelOffset * shortSize)/modelSize + shortOff
    // scale = shortSize / modelSize

    input.clear();
    output.clear();
    Vector3f temp = new Vector3f();
    int vertexCount = input.capacity() / 3;
    for (int i = 0; i < vertexCount; i++) {
      BufferUtils.populateFromBuffer(temp, input, i);

      // offset and scale vector into -32768 ... 32767
      // or into -128 ... 127 if using bytes
      temp.multLocal(scale);
      temp.addLocal(offset);

      // quantize and store
      if (sb != null) {
        short v1 = (short) temp.getX();
        short v2 = (short) temp.getY();
        short v3 = (short) temp.getZ();
        sb.put(v1).put(v2).put(v3);
      } else {
        byte v1 = (byte) temp.getX();
        byte v2 = (byte) temp.getY();
        byte v3 = (byte) temp.getZ();
        bb.put(v1).put(v2).put(v3);
      }
    }

    Transform transform = new Transform();
    transform.setTranslation(offset.negate().multLocal(invScale));
    transform.setScale(invScale);
    return transform;
  }
  private static Mesh genTangentLines(Mesh mesh, float scale) {
    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
    FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
    FloatBuffer tangentBuffer = (FloatBuffer) mesh.getBuffer(Type.Tangent).getData();

    FloatBuffer binormalBuffer = null;
    if (mesh.getBuffer(Type.Binormal) != null) {
      binormalBuffer = (FloatBuffer) mesh.getBuffer(Type.Binormal).getData();
    }

    ColorRGBA originColor = ColorRGBA.White;
    ColorRGBA tangentColor = ColorRGBA.Red;
    ColorRGBA binormalColor = ColorRGBA.Green;
    ColorRGBA normalColor = ColorRGBA.Blue;

    Mesh lineMesh = new Mesh();
    lineMesh.setMode(Mesh.Mode.Lines);

    Vector3f origin = new Vector3f();
    Vector3f point = new Vector3f();
    Vector3f tangent = new Vector3f();
    Vector3f normal = new Vector3f();

    IntBuffer lineIndex = BufferUtils.createIntBuffer(vertexBuffer.limit() / 3 * 6);
    FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.limit() * 4);
    FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.limit() / 3 * 4 * 4);

    boolean hasParity = mesh.getBuffer(Type.Tangent).getNumComponents() == 4;
    float tangentW = 1;

    for (int i = 0; i < vertexBuffer.limit() / 3; i++) {
      populateFromBuffer(origin, vertexBuffer, i);
      populateFromBuffer(normal, normalBuffer, i);

      if (hasParity) {
        tangent.x = tangentBuffer.get(i * 4);
        tangent.y = tangentBuffer.get(i * 4 + 1);
        tangent.z = tangentBuffer.get(i * 4 + 2);
        tangentW = tangentBuffer.get(i * 4 + 3);
      } else {
        populateFromBuffer(tangent, tangentBuffer, i);
      }

      int index = i * 4;

      int id = i * 6;
      lineIndex.put(id, index);
      lineIndex.put(id + 1, index + 1);
      lineIndex.put(id + 2, index);
      lineIndex.put(id + 3, index + 2);
      lineIndex.put(id + 4, index);
      lineIndex.put(id + 5, index + 3);

      setInBuffer(origin, lineVertex, index);
      setInBuffer(originColor, lineColor, index);

      point.set(tangent);
      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 1);
      setInBuffer(tangentColor, lineColor, index + 1);

      // wvBinormal = cross(wvNormal, wvTangent) * -inTangent.w

      if (binormalBuffer == null) {
        normal.cross(tangent, point);
        point.multLocal(-tangentW);
        point.normalizeLocal();
      } else {
        populateFromBuffer(point, binormalBuffer, i);
      }

      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 2);
      setInBuffer(binormalColor, lineColor, index + 2);

      point.set(normal);
      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 3);
      setInBuffer(normalColor, lineColor, index + 3);
    }

    lineMesh.setBuffer(Type.Index, 1, lineIndex);
    lineMesh.setBuffer(Type.Position, 3, lineVertex);
    lineMesh.setBuffer(Type.Color, 4, lineColor);

    lineMesh.setStatic();
    // lineMesh.setInterleaved();
    return lineMesh;
  }
  // Don't remove splitmirorred boolean,It's not used right now, but i intend to
  // make this method also split vertice with rotated tangent space and I'll
  // add another splitRotated boolean
  private static List<VertexData> splitVertices(
      Mesh mesh, List<VertexData> vertexData, boolean splitMirorred) {
    int nbVertices = mesh.getBuffer(Type.Position).getNumElements();
    List<VertexData> newVertices = new ArrayList<VertexData>();
    Map<Integer, Integer> indiceMap = new HashMap<Integer, Integer>();
    FloatBuffer normalBuffer = mesh.getFloatBuffer(Type.Normal);

    for (int i = 0; i < vertexData.size(); i++) {
      ArrayList<TriangleData> triangles = vertexData.get(i).triangles;
      Vector3f givenNormal = new Vector3f();
      populateFromBuffer(givenNormal, normalBuffer, i);

      ArrayList<TriangleData> trianglesUp = new ArrayList<TriangleData>();
      ArrayList<TriangleData> trianglesDown = new ArrayList<TriangleData>();
      for (int j = 0; j < triangles.size(); j++) {
        TriangleData triangleData = triangles.get(j);
        if (parity(givenNormal, triangleData.normal) > 0) {
          trianglesUp.add(triangleData);
        } else {
          trianglesDown.add(triangleData);
        }
      }

      // if the vertex has triangles with opposite parity it has to be split
      if (!trianglesUp.isEmpty() && !trianglesDown.isEmpty()) {
        log.log(Level.FINE, "Splitting vertex {0}", i);
        // assigning triangle with the same parity to the original vertex
        vertexData.get(i).triangles.clear();
        vertexData.get(i).triangles.addAll(trianglesUp);

        // creating a new vertex
        VertexData newVert = new VertexData();
        // assigning triangles with opposite parity to it
        newVert.triangles.addAll(trianglesDown);

        newVertices.add(newVert);
        // keep vertex index to fix the index buffers later
        indiceMap.put(nbVertices, i);
        for (TriangleData tri : newVert.triangles) {
          for (int j = 0; j < tri.index.length; j++) {
            if (tri.index[j] == i) {
              tri.index[j] = nbVertices;
            }
          }
        }
        nbVertices++;
      }
    }

    if (!newVertices.isEmpty()) {

      // we have new vertices, we need to update the mesh's buffers.
      for (Type type : VertexBuffer.Type.values()) {
        // skip tangent buffer as we're gonna overwrite it later
        if (type == Type.Tangent || type == Type.BindPoseTangent) {
          continue;
        }
        VertexBuffer vb = mesh.getBuffer(type);
        // Some buffer (hardware skinning ones) can be there but not
        // initialized, they must be skipped.
        // They'll be initialized when Hardware Skinning is engaged
        if (vb == null || vb.getNumComponents() == 0) {
          continue;
        }

        Buffer buffer = vb.getData();
        // IndexBuffer has special treatement, only swapping the vertex indices is needed
        if (type == Type.Index) {
          boolean isShortBuffer = vb.getFormat() == VertexBuffer.Format.UnsignedShort;
          for (VertexData vertex : newVertices) {
            for (TriangleData tri : vertex.triangles) {
              for (int i = 0; i < tri.index.length; i++) {
                if (isShortBuffer) {
                  ((ShortBuffer) buffer).put(tri.triangleOffset + i, (short) tri.index[i]);
                } else {
                  ((IntBuffer) buffer).put(tri.triangleOffset + i, tri.index[i]);
                }
              }
            }
          }
          vb.setUpdateNeeded();
        } else {
          // copy the buffer in a bigger one and append nex vertices to the end
          Buffer newVerts =
              VertexBuffer.createBuffer(vb.getFormat(), vb.getNumComponents(), nbVertices);
          if (buffer != null) {
            buffer.rewind();
            bulkPut(vb.getFormat(), newVerts, buffer);

            int index = vertexData.size();
            newVerts.position(vertexData.size() * vb.getNumComponents());
            for (int j = 0; j < newVertices.size(); j++) {
              int oldInd = indiceMap.get(index);
              for (int i = 0; i < vb.getNumComponents(); i++) {
                putValue(vb.getFormat(), newVerts, buffer, oldInd * vb.getNumComponents() + i);
              }
              index++;
            }
            vb.updateData(newVerts);
            // destroy previous buffer as it's no longer needed
            destroyDirectBuffer(buffer);
          }
        }
      }
      vertexData.addAll(newVertices);

      mesh.updateCounts();
    }

    return vertexData;
  }