use of com.jme3.scene.VertexBuffer in project jmonkeyengine by jMonkeyEngine.
the class GLRenderer method setVertexAttrib.
public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) {
if (vb.getBufferType() == VertexBuffer.Type.Index) {
throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib");
}
if (context.boundShaderProgram <= 0) {
throw new IllegalStateException("Cannot render mesh without shader bound");
}
Attribute attrib = context.boundShader.getAttribute(vb.getBufferType());
int loc = attrib.getLocation();
if (loc == -1) {
// not defined
return;
}
if (loc == -2) {
loc = gl.glGetAttribLocation(context.boundShaderProgram, "in" + vb.getBufferType().name());
// the internal name of the enum (Position).
if (loc < 0) {
attrib.setLocation(-1);
// not available in shader.
return;
} else {
attrib.setLocation(loc);
}
}
if (vb.isInstanced()) {
if (!caps.contains(Caps.MeshInstancing)) {
throw new RendererException("Instancing is required, " + "but not supported by the " + "graphics hardware");
}
}
int slotsRequired = 1;
if (vb.getNumComponents() > 4) {
if (vb.getNumComponents() % 4 != 0) {
throw new RendererException("Number of components in multi-slot " + "buffers must be divisible by 4");
}
slotsRequired = vb.getNumComponents() / 4;
}
if (vb.isUpdateNeeded() && idb == null) {
updateBufferData(vb);
}
VertexBuffer[] attribs = context.boundAttribs;
for (int i = 0; i < slotsRequired; i++) {
if (!context.attribIndexList.moveToNew(loc + i)) {
gl.glEnableVertexAttribArray(loc + i);
}
}
if (attribs[loc] != vb) {
// NOTE: Use id from interleaved buffer if specified
int bufId = idb != null ? idb.getId() : vb.getId();
assert bufId != -1;
if (context.boundArrayVBO != bufId) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufId);
context.boundArrayVBO = bufId;
//statistics.onVertexBufferUse(vb, true);
} else {
//statistics.onVertexBufferUse(vb, false);
}
if (slotsRequired == 1) {
gl.glVertexAttribPointer(loc, vb.getNumComponents(), convertFormat(vb.getFormat()), vb.isNormalized(), vb.getStride(), vb.getOffset());
} else {
for (int i = 0; i < slotsRequired; i++) {
// The pointer maps the next 4 floats in the slot.
// E.g.
// P1: XXXX____________XXXX____________
// P2: ____XXXX____________XXXX________
// P3: ________XXXX____________XXXX____
// P4: ____________XXXX____________XXXX
// stride = 4 bytes in float * 4 floats in slot * num slots
// offset = 4 bytes in float * 4 floats in slot * slot index
gl.glVertexAttribPointer(loc + i, 4, convertFormat(vb.getFormat()), vb.isNormalized(), 4 * 4 * slotsRequired, 4 * 4 * i);
}
}
for (int i = 0; i < slotsRequired; i++) {
int slot = loc + i;
if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
// non-instanced -> instanced
glext.glVertexAttribDivisorARB(slot, vb.getInstanceSpan());
} else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
// instanced -> non-instanced
glext.glVertexAttribDivisorARB(slot, 0);
}
attribs[slot] = vb;
}
}
}
use of com.jme3.scene.VertexBuffer in project jmonkeyengine by jMonkeyEngine.
the class IrUtils method convertIrMeshToJmeMesh.
/**
* Convert IrMesh to jME3 mesh.
*/
public static Mesh convertIrMeshToJmeMesh(IrMesh mesh) {
Map<IrVertex, Integer> vertexToVertexIndex = new HashMap<IrVertex, Integer>();
List<IrVertex> vertices = new ArrayList<IrVertex>();
List<Integer> indexes = new ArrayList<Integer>();
int vertexIndex = 0;
for (IrPolygon polygon : mesh.polygons) {
if (polygon.vertices.length != 3) {
throw new UnsupportedOperationException("IrMesh must be triangulated first");
}
for (IrVertex vertex : polygon.vertices) {
// Is this vertex already indexed?
Integer existingIndex = vertexToVertexIndex.get(vertex);
if (existingIndex == null) {
// Not indexed yet, allocate index.
indexes.add(vertexIndex);
vertexToVertexIndex.put(vertex, vertexIndex);
vertices.add(vertex);
vertexIndex++;
} else {
// Index already allocated for this vertex, reuse it.
indexes.add(existingIndex);
}
}
}
Mesh jmeMesh = new Mesh();
jmeMesh.setMode(Mesh.Mode.Triangles);
FloatBuffer posBuf = null;
FloatBuffer normBuf = null;
FloatBuffer tangBuf = null;
FloatBuffer uv0Buf = null;
FloatBuffer uv1Buf = null;
ByteBuffer colorBuf = null;
ByteBuffer boneIndices = null;
FloatBuffer boneWeights = null;
IndexBuffer indexBuf = null;
IrVertex inspectionVertex = vertices.get(0);
if (inspectionVertex.pos != null) {
posBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
}
if (inspectionVertex.norm != null) {
normBuf = BufferUtils.createVector3Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
}
if (inspectionVertex.tang4d != null) {
tangBuf = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Tangent, 4, tangBuf);
}
if (inspectionVertex.tang != null || inspectionVertex.bitang != null) {
throw new IllegalStateException("Mesh is using 3D tangents, must be converted to 4D tangents first.");
}
if (inspectionVertex.uv0 != null) {
uv0Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord, 2, uv0Buf);
}
if (inspectionVertex.uv1 != null) {
uv1Buf = BufferUtils.createVector2Buffer(vertices.size());
jmeMesh.setBuffer(VertexBuffer.Type.TexCoord2, 2, uv1Buf);
}
if (inspectionVertex.color != null) {
colorBuf = BufferUtils.createByteBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.Color, 4, colorBuf);
jmeMesh.getBuffer(VertexBuffer.Type.Color).setNormalized(true);
}
if (inspectionVertex.boneWeightsIndices != null) {
boneIndices = BufferUtils.createByteBuffer(vertices.size() * 4);
boneWeights = BufferUtils.createFloatBuffer(vertices.size() * 4);
jmeMesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, boneIndices);
jmeMesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, boneWeights);
//creating empty buffers for HW skinning
//the buffers will be setup if ever used.
VertexBuffer weightsHW = new VertexBuffer(VertexBuffer.Type.HWBoneWeight);
VertexBuffer indicesHW = new VertexBuffer(VertexBuffer.Type.HWBoneIndex);
//setting usage to cpuOnly so that the buffer is not send empty to the GPU
indicesHW.setUsage(VertexBuffer.Usage.CpuOnly);
weightsHW.setUsage(VertexBuffer.Usage.CpuOnly);
jmeMesh.setBuffer(weightsHW);
jmeMesh.setBuffer(indicesHW);
}
if (vertices.size() >= 65536) {
// too many verticies: use intbuffer instead of shortbuffer
IntBuffer ib = BufferUtils.createIntBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, ib);
indexBuf = new IndexIntBuffer(ib);
} else {
ShortBuffer sb = BufferUtils.createShortBuffer(indexes.size());
jmeMesh.setBuffer(VertexBuffer.Type.Index, 3, sb);
indexBuf = new IndexShortBuffer(sb);
}
jmeMesh.setStatic();
int maxBonesPerVertex = -1;
for (IrVertex vertex : vertices) {
if (posBuf != null) {
posBuf.put(vertex.pos.x).put(vertex.pos.y).put(vertex.pos.z);
}
if (normBuf != null) {
normBuf.put(vertex.norm.x).put(vertex.norm.y).put(vertex.norm.z);
}
if (tangBuf != null) {
tangBuf.put(vertex.tang4d.x).put(vertex.tang4d.y).put(vertex.tang4d.z).put(vertex.tang4d.w);
}
if (uv0Buf != null) {
uv0Buf.put(vertex.uv0.x).put(vertex.uv0.y);
}
if (uv1Buf != null) {
uv1Buf.put(vertex.uv1.x).put(vertex.uv1.y);
}
if (colorBuf != null) {
colorBuf.putInt(vertex.color.asIntABGR());
}
if (boneIndices != null) {
if (vertex.boneWeightsIndices != null) {
if (vertex.boneWeightsIndices.length > 4) {
throw new UnsupportedOperationException("Mesh uses more than 4 weights per bone. " + "Call trimBoneWeights() to allieviate this");
}
for (int i = 0; i < vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) (vertex.boneWeightsIndices[i].boneIndex & 0xFF));
boneWeights.put(vertex.boneWeightsIndices[i].boneWeight);
}
for (int i = 0; i < 4 - vertex.boneWeightsIndices.length; i++) {
boneIndices.put((byte) 0);
boneWeights.put(0f);
}
} else {
boneIndices.putInt(0);
boneWeights.put(0f).put(0f).put(0f).put(0f);
}
maxBonesPerVertex = Math.max(maxBonesPerVertex, vertex.boneWeightsIndices.length);
}
}
for (int i = 0; i < indexes.size(); i++) {
indexBuf.put(i, indexes.get(i));
}
jmeMesh.updateCounts();
jmeMesh.updateBound();
if (boneIndices != null) {
jmeMesh.setMaxNumWeights(maxBonesPerVertex);
jmeMesh.prepareForAnim(true);
jmeMesh.generateBindPose(true);
}
return jmeMesh;
}
use of com.jme3.scene.VertexBuffer in project jmonkeyengine by jMonkeyEngine.
the class TangentBinormalGenerator method genTangentLines.
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);
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;
}
use of com.jme3.scene.VertexBuffer in project jmonkeyengine by jMonkeyEngine.
the class TangentBinormalGenerator method splitVertices.
//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);
//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;
}
use of com.jme3.scene.VertexBuffer in project jmonkeyengine by jMonkeyEngine.
the class TangentBinormalGenerator method linkVertices.
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;
//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;
}
Aggregations