Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
345 lines
13 KiB
Java
345 lines
13 KiB
Java
package electrosphere.renderer.meshgen;
|
|
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.IntBuffer;
|
|
import java.util.Iterator;
|
|
|
|
import org.joml.Matrix4d;
|
|
import org.joml.Vector4d;
|
|
import org.lwjgl.BufferUtils;
|
|
import org.lwjgl.PointerBuffer;
|
|
import org.lwjgl.assimp.AIBone;
|
|
import org.lwjgl.assimp.AIFace;
|
|
import org.lwjgl.assimp.AIMesh;
|
|
import org.lwjgl.assimp.AIVector3D;
|
|
import org.lwjgl.assimp.AIVertexWeight;
|
|
|
|
import electrosphere.engine.Globals;
|
|
import electrosphere.logger.LoggerInterface;
|
|
import electrosphere.renderer.loading.ModelPretransforms;
|
|
import electrosphere.renderer.model.Bone;
|
|
import electrosphere.renderer.model.Mesh;
|
|
import electrosphere.renderer.shader.VisualShader;
|
|
|
|
/**
|
|
* Main class for loading meshes from assimp scenes
|
|
*/
|
|
public class MeshLoader {
|
|
|
|
public static Mesh createMeshFromAIScene(AIMesh mesh, ModelPretransforms.MeshMetadata metadata){
|
|
boolean has_bones = false;
|
|
boolean apply_lighting = true;
|
|
|
|
Mesh rVal = new Mesh(mesh.mName().dataString());
|
|
|
|
//
|
|
// VAO
|
|
//
|
|
//Check for headless to not call gl functions when not running with gpu
|
|
if(!Globals.HEADLESS){
|
|
rVal.generateVAO();
|
|
}
|
|
|
|
|
|
|
|
//Basic checks
|
|
//check num vertices
|
|
int numVertices = mesh.mNumVertices();
|
|
AIVector3D.Buffer vertexData = mesh.mVertices();
|
|
// while(vertexData.hasRemaining()){
|
|
// vertexData.get();
|
|
// numVertices++;
|
|
// }
|
|
// vertexData = vertexData.rewind();
|
|
//check num normals
|
|
int numNormals = mesh.mNumVertices();
|
|
// AIVector3D.Buffer normalData = mesh.mNormals();
|
|
// while(normalData.hasRemaining()){
|
|
// normalData.get();
|
|
// numNormals++;
|
|
// }
|
|
// normalData.rewind();
|
|
if(numVertices != numNormals){
|
|
LoggerInterface.loggerNetworking.ERROR("Catastrophic failure: Number of vertices =/= Number of normals", new Exception("Catastrophic failure: Number of vertices =/= Number of normals"));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Matrix4d vertexPretransform = new Matrix4d().identity();
|
|
Matrix4d normalPretransform = new Matrix4d().identity();
|
|
if(metadata != null){
|
|
LoggerInterface.loggerRenderer.DEBUG("Pretransforming");
|
|
vertexPretransform.translationRotateScale(metadata.getOffset(), metadata.getRotation(), metadata.getScale());
|
|
normalPretransform.rotate(metadata.getRotation());
|
|
}
|
|
|
|
//
|
|
//Buffer data to GPU
|
|
//
|
|
vertexData.rewind();
|
|
|
|
int vertexCount = 0;
|
|
try {
|
|
vertexCount = mesh.mNumVertices();
|
|
FloatBuffer vertexArrayBufferData = BufferUtils.createFloatBuffer(vertexCount * 3);
|
|
float[] temp = new float[3];
|
|
boolean definedDimensions = false;
|
|
float minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0;
|
|
for (int i = 0; i < vertexCount; i++) {
|
|
AIVector3D vertex = vertexData.get();
|
|
float x = vertex.x();
|
|
float y = vertex.y();
|
|
float z = vertex.z();
|
|
//store dimensions of the model
|
|
if(definedDimensions){
|
|
if(x < minX){ minX = x; }
|
|
if(x > maxX){ maxX = x; }
|
|
if(y < minY){ minY = y; }
|
|
if(y > maxY){ maxY = y; }
|
|
if(z < minZ){ minZ = z; }
|
|
if(z > maxZ){ maxZ = z; }
|
|
} else {
|
|
definedDimensions = true;
|
|
minX = maxX = x;
|
|
minY = maxY = y;
|
|
minZ = maxZ = z;
|
|
}
|
|
//update bounding sphere
|
|
double dist = Math.sqrt(x*x+y*y+z*z);
|
|
if(dist > rVal.getBoundingSphere().r){
|
|
rVal.getBoundingSphere().r = dist;
|
|
}
|
|
//store vertex data
|
|
Vector4d transformedVertex = vertexPretransform.transform(new Vector4d(x,y,z,1.0));
|
|
transformedVertex.w = 1.0;
|
|
temp[0] = (float)transformedVertex.x;
|
|
temp[1] = (float)transformedVertex.y;
|
|
temp[2] = (float)transformedVertex.z;
|
|
vertexArrayBufferData.put(temp);
|
|
}
|
|
if(vertexArrayBufferData.position() > 0){
|
|
vertexArrayBufferData.flip();
|
|
rVal.bufferVertices(vertexArrayBufferData, 3);
|
|
}
|
|
} catch (NullPointerException ex){
|
|
ex.printStackTrace();
|
|
}
|
|
//
|
|
// NORMALS
|
|
//
|
|
AIVector3D.Buffer normals = mesh.mNormals();
|
|
try {
|
|
int normalCount = mesh.mNumVertices();
|
|
FloatBuffer normalArrayBufferData;
|
|
if(normalCount > 0){
|
|
normalArrayBufferData = BufferUtils.createFloatBuffer(normalCount * 3);
|
|
float[] temp = new float[3];
|
|
for (int i = 0; i < normalCount; i++) {
|
|
AIVector3D normal = normals.get(i);
|
|
Vector4d transformedNormal = normalPretransform.transform(new Vector4d(normal.x(),normal.y(),normal.z(),1.0));
|
|
temp[0] = (float)transformedNormal.x();
|
|
temp[1] = (float)transformedNormal.y();
|
|
temp[2] = (float)transformedNormal.z();
|
|
normalArrayBufferData.put(temp);
|
|
}
|
|
if(normalArrayBufferData.position() > 0){
|
|
normalArrayBufferData.flip();
|
|
rVal.bufferNormals(normalArrayBufferData, 3);
|
|
}
|
|
}
|
|
} catch (NullPointerException ex){
|
|
ex.printStackTrace();
|
|
}
|
|
//
|
|
// FACES
|
|
//
|
|
int faceCount = mesh.mNumFaces();
|
|
int elementCount = faceCount * 3;
|
|
IntBuffer elementArrayBufferData = BufferUtils.createIntBuffer(elementCount);
|
|
AIFace.Buffer facesBuffer = mesh.mFaces();
|
|
for(int i = 0; i < faceCount; i++){
|
|
AIFace face = facesBuffer.get(i);
|
|
if(face.mNumIndices() != 3){
|
|
throw new IllegalStateException("AIFace.mNumIndices() != 3");
|
|
}
|
|
elementArrayBufferData.put(face.mIndices());
|
|
}
|
|
if(elementArrayBufferData.position() > 0){
|
|
elementArrayBufferData.flip();
|
|
rVal.bufferFaces(elementArrayBufferData,elementCount);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// TEXTURE COORDINATES
|
|
//
|
|
if(mesh.mTextureCoords().capacity() > 0){
|
|
AIVector3D.Buffer texturecoords = mesh.mTextureCoords(0);
|
|
try {
|
|
if(texturecoords != null){
|
|
int textureCoordCount = texturecoords.capacity();
|
|
FloatBuffer textureArrayBufferData;
|
|
if(textureCoordCount > 0){
|
|
textureArrayBufferData = BufferUtils.createFloatBuffer(textureCoordCount * 2);
|
|
float[] temp = new float[2];
|
|
for (int i = 0; i < textureCoordCount; i++) {
|
|
AIVector3D normal = texturecoords.get(i);
|
|
temp[0] = normal.x();
|
|
temp[1] = normal.y();
|
|
// temp[2] = normal.z();
|
|
textureArrayBufferData.put(temp);
|
|
}
|
|
if(textureArrayBufferData.position() > 0){
|
|
textureArrayBufferData.flip();
|
|
rVal.bufferTextureCoords(textureArrayBufferData, 2);
|
|
}
|
|
}
|
|
}
|
|
} catch (NullPointerException ex){
|
|
LoggerInterface.loggerRenderer.ERROR("Error reading texture coordinates", ex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
//Read in bones
|
|
//AND buffer data (weights) to GPU
|
|
//
|
|
PointerBuffer boneBuffer = mesh.mBones();
|
|
if(boneBuffer != null){
|
|
has_bones = true;
|
|
while(boneBuffer.hasRemaining()){
|
|
long currentAddr = boneBuffer.get();
|
|
AIBone currentBoneData = AIBone.createSafe(currentAddr);
|
|
// System.out.println("Num weights: " + currentBoneData.mNumWeights());
|
|
Bone currentBone = new Bone(currentBoneData);
|
|
currentBone.boneID = currentBoneData.mName().dataString();
|
|
currentBone.setMOffset(electrosphere.util.Utilities.convertAIMatrixd(currentBoneData.mOffsetMatrix()));
|
|
Iterator<AIVertexWeight> weightIterator = currentBoneData.mWeights().iterator();
|
|
while(weightIterator.hasNext()){
|
|
AIVertexWeight currentWeightData = weightIterator.next();
|
|
currentBone.putWeight(currentWeightData.mVertexId(), currentWeightData.mWeight());
|
|
}
|
|
rVal.getBones().add(currentBone);
|
|
rVal.registerBoneId(currentBone.boneID);
|
|
}
|
|
FloatBuffer boneWeightDataBuffer = BufferUtils.createFloatBuffer(4 * vertexCount);//FloatBuffer.allocate(4 * vertexCount);
|
|
FloatBuffer boneIndexDataBuffer = BufferUtils.createFloatBuffer(4 * vertexCount);//IntBuffer.allocate(4 * vertexCount);
|
|
Iterator<Bone> boneIterator;
|
|
for(int i = 0; i < vertexCount; i++){
|
|
float[] weight = new float[4];
|
|
float[] index = new float[4];
|
|
int boneCounter = 0;
|
|
boneIterator = rVal.getBones().iterator();
|
|
while(boneIterator.hasNext()){
|
|
Bone currentBone = boneIterator.next();
|
|
float boneVal = 0;
|
|
if(currentBone.getWeights().get(i) != null){
|
|
boneVal = currentBone.getWeights().get(i);
|
|
}
|
|
if(boneVal > 0){
|
|
if(boneVal > weight[0]){
|
|
weight[3] = weight[2];
|
|
weight[2] = weight[1];
|
|
weight[1] = weight[0];
|
|
weight[0] = boneVal;
|
|
index[3] = index[2];
|
|
index[2] = index[1];
|
|
index[1] = index[0];
|
|
index[0] = boneCounter;
|
|
// if(rVal.nodeID.equals("Torso")){
|
|
// System.out.println(index[3] + " " + index[2] + " " + index[1] + " " + index[0]);
|
|
// }
|
|
} else if(boneVal > weight[1]){
|
|
weight[3] = weight[2];
|
|
weight[2] = weight[1];
|
|
weight[1] = boneVal;
|
|
index[3] = index[2];
|
|
index[2] = index[1];
|
|
index[1] = boneCounter;
|
|
} else if(boneVal > weight[2]){
|
|
weight[3] = weight[2];
|
|
weight[2] = boneVal;
|
|
index[3] = index[2];
|
|
index[2] = boneCounter;
|
|
} else if(boneVal > weight[3]){
|
|
weight[3] = boneVal;
|
|
index[3] = boneCounter;
|
|
}
|
|
}
|
|
boneCounter++;
|
|
}
|
|
float total = weight[0] + weight[1] + weight[2] + weight[3];
|
|
if(total != 1.0f){
|
|
weight[0] = weight[0] * (1.0f / total);
|
|
weight[1] = weight[1] * (1.0f / total);
|
|
weight[2] = weight[2] * (1.0f / total);
|
|
weight[3] = weight[3] * (1.0f / total);
|
|
}
|
|
//If all are 0 (for instance the vertex doesn't have any bones with any weight > 0), the values for each weight will be NaN after the divide immediately above
|
|
//If NaN, set all to 0
|
|
if(Float.isNaN(weight[0])){
|
|
weight[0] = 0;
|
|
weight[1] = 0;
|
|
weight[2] = 0;
|
|
weight[3] = 0;
|
|
}
|
|
boneIndexDataBuffer.put(index);
|
|
boneWeightDataBuffer.put(weight);
|
|
}
|
|
if(boneIndexDataBuffer.position() > 0){
|
|
boneIndexDataBuffer.flip();
|
|
}
|
|
if(boneWeightDataBuffer.position() > 0){
|
|
boneWeightDataBuffer.flip();
|
|
}
|
|
|
|
if(!Globals.HEADLESS){
|
|
rVal.bufferBoneIndices(boneIndexDataBuffer);
|
|
|
|
rVal.bufferBoneWeights(boneWeightDataBuffer);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!Globals.HEADLESS){
|
|
rVal.setShader(VisualShader.smart_assemble_shader(has_bones, apply_lighting));
|
|
rVal.setShader(VisualShader.smart_assemble_shader(has_bones, apply_lighting));
|
|
rVal.setOITShader(VisualShader.smartAssembleOITProgram(has_bones, apply_lighting));
|
|
}
|
|
|
|
|
|
|
|
return rVal;
|
|
}
|
|
|
|
}
|