texture loading from model files
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-29 19:32:00 -04:00
parent 32d9725f1e
commit 7f557d40c0
8 changed files with 158 additions and 25 deletions

View File

@ -21,6 +21,28 @@
"path" : "Models/foliage/flowers/Flower_3_Group.gltf" "path" : "Models/foliage/flowers/Flower_3_Group.gltf"
} }
} }
},
{
"id" : "mushroom1",
"tokens" : [
"FLAMMABLE"
],
"hitboxes" : [
{
"type": "hurt",
"offset": [0, 0.6, 0],
"radius": 0.35
}
],
"healthSystem" : {
"maxHealth" : 5,
"onDamageIFrames" : 0
},
"graphicsTemplate": {
"model": {
"path" : "Models/foliage/mushroom1.glb"
}
}
} }
], ],
"files" : [ "files" : [

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

View File

@ -1599,6 +1599,7 @@ Refactor ProceduralChunkGenerator
NoiseVoxelGen work to make elevation values align with voxel values that are generated NoiseVoxelGen work to make elevation values align with voxel values that are generated
Non-procedural voxel generation fix Non-procedural voxel generation fix
Flower foliage item Flower foliage item
Texture loading from model files (ie can load texture path from model file)
@ -1725,9 +1726,6 @@ Light Manager
- Eventually support spot lights? - Eventually support spot lights?
- Point shadows ??? - Point shadows ???
gltf Support
- Texture loading from gltf file
Security Security
- FileUtils sanitation function check if requested file is in game root dir - FileUtils sanitation function check if requested file is in game root dir

View File

@ -125,7 +125,8 @@ public class AssetManager {
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures");
for(String currentPath : texturesInQueue){ for(String currentPath : texturesInQueue){
texturesInQueue.remove(currentPath); texturesInQueue.remove(currentPath);
texturesLoadedIntoMemory.put(currentPath, new Texture(Globals.renderingEngine.getOpenGLState(), currentPath)); Texture tex = new Texture(Globals.renderingEngine.getOpenGLState(), currentPath);
texturesLoadedIntoMemory.put(currentPath, tex);
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//audio from disk //audio from disk

View File

@ -1,14 +1,26 @@
package electrosphere.renderer.model; package electrosphere.renderer.model;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState; import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.texture.Texture; import electrosphere.renderer.texture.Texture;
import electrosphere.util.FileUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.assimp.AIMaterial; import org.lwjgl.assimp.AIMaterial;
import org.lwjgl.assimp.AIScene;
import org.lwjgl.assimp.AIString;
import org.lwjgl.assimp.AITexture;
import org.lwjgl.assimp.Assimp;
import org.lwjgl.opengl.GL40; import org.lwjgl.opengl.GL40;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0; import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import java.io.File;
import java.nio.IntBuffer;
import java.nio.file.Path;
/** /**
* A material * A material
*/ */
@ -31,7 +43,6 @@ public class Material {
* A material that contains textures * A material that contains textures
*/ */
public Material(){ public Material(){
} }
/** /**
@ -42,21 +53,104 @@ public class Material {
this.diffuse = diffuse; this.diffuse = diffuse;
} }
//basically useless because blender doesn't support exporting mats with fbx /**
public static Material load_material_from_aimaterial(AIMaterial input){ * Loads materials from the ai material object
* @param path The path to the file we're loading materials from
* @param input The input scene
* @param input The input ai material
* @return The resulting engine material
*/
public static Material load_material_from_aimaterial(String path, AIScene scene, AIMaterial input){
Material rVal = new Material(); Material rVal = new Material();
// if(input.mNumProperties() > 0){
// PointerBuffer property_buffer = input.mProperties(); AIString aiPathString = AIString.calloc();
// while(property_buffer.hasRemaining()){
// AIMaterialProperty new_property = AIMaterialProperty.create(property_buffer.get()); //read props
// // System.out.println("Property: " + new_property.mKey().dataString());
// } //read textures
// } PointerBuffer texturePtrBuff = scene.mTextures();
String[] texPaths = new String[scene.mNumTextures()];
for(int i = 0; i < scene.mNumTextures(); i++){
AITexture tex = AITexture.create(texturePtrBuff.get());
texPaths[i] = tex.mFilename().dataString();
}
//discover diffuse
int textureCount = Assimp.aiGetMaterialTextureCount(input, Assimp.aiTextureType_DIFFUSE);
if(textureCount > 0){
//for the time being, only load the first diffuse
int textureIndex = 0;
int retCode = Assimp.aiGetMaterialTexture(input, Assimp.aiTextureType_DIFFUSE, textureIndex, aiPathString, (IntBuffer)null, null, null, null, null, null);
if(retCode != Assimp.aiReturn_SUCCESS){
throw new Error("Failed to read diffuse! " + textureCount + " " + Assimp.aiGetErrorString());
}
String texturePath = aiPathString.dataString();
if(texturePath == null || texturePath.length() <= 0){
throw new Error("Texture path is empty " + texturePath);
}
if(texturePath.length() == 2 && texturePath.startsWith("*")){
//older versions of Assimp require you to read the INDEX of the texture from the material, then look up that texture in the scene itself
//format looks like "*<index>" ie "*0"
int indexInLoadedTexturePaths = Integer.parseInt(texturePath.substring(1));
if(indexInLoadedTexturePaths >= texPaths.length){
throw new Error("Index discovered is outside the array's length " + indexInLoadedTexturePaths + " " + texPaths.length);
}
String resolved = Material.resolveTexturePath(path, texPaths[indexInLoadedTexturePaths]);
if(resolved != null && resolved.length() > 0){
rVal.usesFetch = true;
rVal.diffuse = resolved;
Globals.assetManager.addTexturePathtoQueue(rVal.diffuse);
}
} else {
throw new Error("Probably got an actual texture path, haven't written code to handle this.. " + texturePath);
}
}
//free mem
aiPathString.free();
return rVal; return rVal;
} }
/**
* Resolves the filepath of the texture
* @param path The path of the ai scene itself
* @param filename The name of the file
* @return The full path to load
*/
private static String resolveTexturePath(String path, String filename){
File fileObj = FileUtils.getAssetFile(path);
File parentDir = fileObj.getParentFile();
File[] contents = parentDir.listFiles();
File discovered = null;
for(File child : contents){
String name = child.getName();
String nameNoExt = child.getName().replaceFirst("[.][^.]+$", "");
if(name.equals(filename) || nameNoExt.equals(filename)){
discovered = child;
}
}
if(discovered == null){
LoggerInterface.loggerRenderer.WARNING("Failed to find texture " + filename + " for model " + path);
return null;
} else {
Path relative = new File("./assets").toPath().relativize(discovered.toPath());
return relative.toString().replace("\\","/");
}
}
/**
* Gets the path for the diffuse of the material
* @return The path for the diffuse texture
*/
public String get_diffuse(){ public String get_diffuse(){
return diffuse; return diffuse;
} }
/**
* Gets the path for the specular of the material
* @return The path for the specular texture
*/
public String get_specular(){ public String get_specular(){
return specular; return specular;
} }

View File

@ -101,6 +101,19 @@ public class Model {
if(modelMetadata != null){ if(modelMetadata != null){
globalTransform = modelMetadata.getGlobalTransform(); globalTransform = modelMetadata.getGlobalTransform();
} }
//
//Load materials
//
if(scene.mNumMaterials() > 0){
rVal.materials = new ArrayList<Material>();
PointerBuffer material_buffer = scene.mMaterials();
while(material_buffer.hasRemaining()){
rVal.materials.add(Material.load_material_from_aimaterial(path,scene,AIMaterial.create(material_buffer.get())));
}
}
// //
//load meshes //load meshes
@ -120,6 +133,16 @@ public class Model {
if(currentMesh.getBoundingSphere().r > rVal.boundingSphere.r){ if(currentMesh.getBoundingSphere().r > rVal.boundingSphere.r){
rVal.boundingSphere.r = currentMesh.getBoundingSphere().r; rVal.boundingSphere.r = currentMesh.getBoundingSphere().r;
} }
//conditionally add material
int materialIndex = aiMesh.mMaterialIndex();
if(materialIndex < rVal.materials.size()){
Material mat = rVal.materials.get(materialIndex);
//only assign if the diffuse is actually set (ie we've actually loaded it properly)
if(mat.get_diffuse() != null){
currentMesh.setMaterial(rVal.materials.get(materialIndex));
}
}
} }
// //
@ -196,17 +219,6 @@ public class Model {
rVal.animMap.put(newAnim.name,newAnim); rVal.animMap.put(newAnim.name,newAnim);
} }
//
//Load materials
//
if(scene.mNumMaterials() > 0){
rVal.materials = new ArrayList<Material>();
PointerBuffer material_buffer = scene.mMaterials();
while(material_buffer.hasRemaining()){
rVal.materials.add(Material.load_material_from_aimaterial(AIMaterial.create(material_buffer.get())));
}
}
return rVal; return rVal;
} }

View File

@ -232,6 +232,12 @@ public class Texture {
*/ */
public Texture(OpenGLState openGlState, String path){ public Texture(OpenGLState openGlState, String path){
LoggerInterface.loggerRenderer.DEBUG("Create texture " + path); LoggerInterface.loggerRenderer.DEBUG("Create texture " + path);
if(path == null){
throw new Error("Path is null");
}
if(path.length() == 0){
throw new Error("Path is empty");
}
this.path = path; this.path = path;
if(!Globals.HEADLESS){ if(!Globals.HEADLESS){
LoggerInterface.loggerRenderer.DEBUG("Setup texture object"); LoggerInterface.loggerRenderer.DEBUG("Setup texture object");