Add .obj file loading.
This commit is contained in:
parent
3da44ff2cd
commit
2e2b2c2604
4 changed files with 7613 additions and 61 deletions
|
@ -2,6 +2,9 @@ package com.okseby.core;
|
||||||
|
|
||||||
import com.okseby.core.entity.Model;
|
import com.okseby.core.entity.Model;
|
||||||
import com.okseby.core.utils.Utils;
|
import com.okseby.core.utils.Utils;
|
||||||
|
import org.joml.Vector2f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.opengl.GL20;
|
import org.lwjgl.opengl.GL20;
|
||||||
|
@ -20,6 +23,117 @@ public class ObjectLoader {
|
||||||
private List<Integer> vbos = new ArrayList<>();
|
private List<Integer> vbos = new ArrayList<>();
|
||||||
private List<Integer> textures = new ArrayList<>();
|
private List<Integer> textures = new ArrayList<>();
|
||||||
|
|
||||||
|
public Model loadOBJModel(String fileName) {
|
||||||
|
List<String> lines = Utils.readAllLines(fileName);
|
||||||
|
|
||||||
|
List<Vector3f> vertices = new ArrayList<>();
|
||||||
|
List<Vector3f> normals = new ArrayList<>();
|
||||||
|
List<Vector2f> textures = new ArrayList<>();
|
||||||
|
List<Vector3i> faces = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String line : lines) {
|
||||||
|
String[] tokens = line.split("\\s+");
|
||||||
|
switch (tokens[0]) {
|
||||||
|
case "v":
|
||||||
|
// vertices
|
||||||
|
Vector3f verticesVector = new Vector3f(
|
||||||
|
Float.parseFloat(tokens[1]),
|
||||||
|
Float.parseFloat(tokens[2]),
|
||||||
|
Float.parseFloat(tokens[3])
|
||||||
|
);
|
||||||
|
vertices.add(verticesVector);
|
||||||
|
break;
|
||||||
|
case "vn":
|
||||||
|
// vertex normals
|
||||||
|
Vector3f normalsVector = new Vector3f(
|
||||||
|
Float.parseFloat(tokens[1]),
|
||||||
|
Float.parseFloat(tokens[2]),
|
||||||
|
Float.parseFloat(tokens[3])
|
||||||
|
);
|
||||||
|
normals.add(normalsVector);
|
||||||
|
break;
|
||||||
|
case "vt":
|
||||||
|
// vertex textures
|
||||||
|
Vector2f texturesVector = new Vector2f(
|
||||||
|
Float.parseFloat(tokens[1]),
|
||||||
|
Float.parseFloat(tokens[2])
|
||||||
|
);
|
||||||
|
textures.add(texturesVector);
|
||||||
|
break;
|
||||||
|
case "f":
|
||||||
|
// vertex faces
|
||||||
|
processFaces(tokens[1], faces);
|
||||||
|
processFaces(tokens[2], faces);
|
||||||
|
processFaces(tokens[3], faces);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Integer> indices = new ArrayList<>();
|
||||||
|
float[] verticesArray = new float[vertices.size() * 3];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (Vector3f position : vertices) {
|
||||||
|
verticesArray[i * 3] = position.x;
|
||||||
|
verticesArray[i * 3 + 1] = position.y;
|
||||||
|
verticesArray[i * 3 + 2] = position.z;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] textureCoordinatesArray = new float[vertices.size() * 2];
|
||||||
|
float[] normalArray = new float[vertices.size() * 3];
|
||||||
|
|
||||||
|
for (Vector3i face : faces) {
|
||||||
|
processVertexes(face.x, face.y, face.z, textures, normals, indices, textureCoordinatesArray, normalArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] indicesArray = indices.stream().mapToInt((Integer v) -> v).toArray();
|
||||||
|
|
||||||
|
return loadModel(verticesArray, textureCoordinatesArray, indicesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processVertexes(int position, int textureCoordinate, int normal, List<Vector2f> textureCoordinateList, List<Vector3f> normalList, List<Integer> indicesList, float[] textureCoordinatesArray, float[] normalArray) {
|
||||||
|
indicesList.add(position);
|
||||||
|
|
||||||
|
if (textureCoordinate >= 0) {
|
||||||
|
Vector2f textureCoordinatesVector = textureCoordinateList.get(textureCoordinate);
|
||||||
|
|
||||||
|
textureCoordinatesArray[position * 2] = textureCoordinatesVector.x;
|
||||||
|
textureCoordinatesArray[position * 2 + 1] = 1 - textureCoordinatesVector.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normal >= 0) {
|
||||||
|
Vector3f normalVector = normalList.get(normal);
|
||||||
|
|
||||||
|
normalArray[position * 3] = normalVector.x;
|
||||||
|
normalArray[position * 3 + 1] = normalVector.y;
|
||||||
|
normalArray[position * 3 + 2] = normalVector.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processFaces(String token, List<Vector3i> faces) {
|
||||||
|
String[] lineToken = token.split("/");
|
||||||
|
|
||||||
|
int length = lineToken.length;
|
||||||
|
int position = -1, coordinates = -1, normal = -1;
|
||||||
|
|
||||||
|
position = Integer.parseInt(lineToken[0]) - 1;
|
||||||
|
|
||||||
|
if (length > 1) {
|
||||||
|
String textureCoordinates = lineToken[1];
|
||||||
|
coordinates = textureCoordinates.length() > 0 ? Integer.parseInt(textureCoordinates) - 1 : -1;
|
||||||
|
|
||||||
|
if (length > 2)
|
||||||
|
normal = Integer.parseInt(lineToken[2]) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3i facesVector = new Vector3i(position, coordinates, normal);
|
||||||
|
|
||||||
|
faces.add(facesVector);
|
||||||
|
}
|
||||||
|
|
||||||
public Model loadModel(float[] vertices, float[] textureCoordinates, int[] indices) {
|
public Model loadModel(float[] vertices, float[] textureCoordinates, int[] indices) {
|
||||||
int id = createVAO();
|
int id = createVAO();
|
||||||
storeIndicesBuffer(indices);
|
storeIndicesBuffer(indices);
|
||||||
|
@ -30,7 +144,7 @@ public class ObjectLoader {
|
||||||
return new Model(id, indices.length);
|
return new Model(id, indices.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int loadTexture(String filename) throws Exception {
|
public int loadTexture(String fileName) throws Exception {
|
||||||
int width, height;
|
int width, height;
|
||||||
ByteBuffer buffer;
|
ByteBuffer buffer;
|
||||||
|
|
||||||
|
@ -39,9 +153,9 @@ public class ObjectLoader {
|
||||||
IntBuffer h = stack.mallocInt(1);
|
IntBuffer h = stack.mallocInt(1);
|
||||||
IntBuffer c = stack.mallocInt(1);
|
IntBuffer c = stack.mallocInt(1);
|
||||||
|
|
||||||
buffer = STBImage.stbi_load(filename, w, h, c, 4);
|
buffer = STBImage.stbi_load(fileName, w, h, c, 4);
|
||||||
if (buffer == null)
|
if (buffer == null)
|
||||||
throw new Exception("Image File " + filename + " not loaded " + STBImage.stbi_failure_reason());
|
throw new Exception("Image File " + fileName + " not loaded " + STBImage.stbi_failure_reason());
|
||||||
|
|
||||||
width = w.get();
|
width = w.get();
|
||||||
height = h.get();
|
height = h.get();
|
||||||
|
|
|
@ -32,62 +32,7 @@ public class TestGame implements ILogic {
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
renderer.init();
|
renderer.init();
|
||||||
|
|
||||||
float[] vertices = {
|
Model model = loader.loadOBJModel("/models/bunny.obj");
|
||||||
-0.5f, 0.5f, 0.5f,
|
|
||||||
-0.5f, -0.5f, 0.5f,
|
|
||||||
0.5f, -0.5f, 0.5f,
|
|
||||||
0.5f, 0.5f, 0.5f,
|
|
||||||
-0.5f, 0.5f, -0.5f,
|
|
||||||
0.5f, 0.5f, -0.5f,
|
|
||||||
-0.5f, -0.5f, -0.5f,
|
|
||||||
0.5f, -0.5f, -0.5f,
|
|
||||||
-0.5f, 0.5f, -0.5f,
|
|
||||||
0.5f, 0.5f, -0.5f,
|
|
||||||
-0.5f, 0.5f, 0.5f,
|
|
||||||
0.5f, 0.5f, 0.5f,
|
|
||||||
0.5f, 0.5f, 0.5f,
|
|
||||||
0.5f, -0.5f, 0.5f,
|
|
||||||
-0.5f, 0.5f, 0.5f,
|
|
||||||
-0.5f, -0.5f, 0.5f,
|
|
||||||
-0.5f, -0.5f, -0.5f,
|
|
||||||
0.5f, -0.5f, -0.5f,
|
|
||||||
-0.5f, -0.5f, 0.5f,
|
|
||||||
0.5f, -0.5f, 0.5f,
|
|
||||||
};
|
|
||||||
|
|
||||||
float[] textureCoordinates = {
|
|
||||||
0.0f, 0.0f,
|
|
||||||
0.0f, 0.5f,
|
|
||||||
0.5f, 0.5f,
|
|
||||||
0.5f, 0.0f,
|
|
||||||
0.0f, 0.0f,
|
|
||||||
0.5f, 0.0f,
|
|
||||||
0.0f, 0.5f,
|
|
||||||
0.5f, 0.5f,
|
|
||||||
0.0f, 0.5f,
|
|
||||||
0.5f, 0.5f,
|
|
||||||
0.0f, 1.0f,
|
|
||||||
0.5f, 1.0f,
|
|
||||||
0.0f, 0.0f,
|
|
||||||
0.0f, 0.5f,
|
|
||||||
0.5f, 0.0f,
|
|
||||||
0.5f, 0.5f,
|
|
||||||
0.5f, 0.0f,
|
|
||||||
1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f,
|
|
||||||
1.0f, 0.5f,
|
|
||||||
};
|
|
||||||
|
|
||||||
int[] indices = {
|
|
||||||
0, 1, 3, 3, 1, 2,
|
|
||||||
8, 10, 11, 9, 8, 11,
|
|
||||||
12, 13, 7, 5, 12, 7,
|
|
||||||
14, 15, 6, 4, 14, 6,
|
|
||||||
16, 18, 19, 17, 16, 19,
|
|
||||||
4, 6, 7, 5, 4, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
Model model = loader.loadModel(vertices, textureCoordinates, indices);
|
|
||||||
model.setTexture(new Texture(loader.loadTexture("res/textures/grassblock.jpg")));
|
model.setTexture(new Texture(loader.loadTexture("res/textures/grassblock.jpg")));
|
||||||
|
|
||||||
entity = new Entity(model, new Vector3f(0, 0, -5), new Vector3f(0, 0, 0), 1);
|
entity = new Entity(model, new Vector3f(0, 0, -5), new Vector3f(0, 0, 0), 1);
|
||||||
|
|
|
@ -2,10 +2,15 @@ package com.okseby.core.utils;
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
@ -23,9 +28,9 @@ public class Utils {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String loadResource(String filename) throws Exception {
|
public static String loadResource(String fileName) throws Exception {
|
||||||
String result;
|
String result;
|
||||||
try (InputStream in = Utils.class.getResourceAsStream(filename)) {
|
try (InputStream in = Utils.class.getResourceAsStream(fileName)) {
|
||||||
assert in != null;
|
assert in != null;
|
||||||
try (Scanner scanner = new Scanner(in, StandardCharsets.UTF_8)) {
|
try (Scanner scanner = new Scanner(in, StandardCharsets.UTF_8)) {
|
||||||
result = scanner.useDelimiter("\\A").next();
|
result = scanner.useDelimiter("\\A").next();
|
||||||
|
@ -33,4 +38,18 @@ public class Utils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> readAllLines(String fileName) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(Class.forName(Utils.class.getName()).getResourceAsStream(fileName)))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
list.add(line);
|
||||||
|
}
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
7474
src/main/resources/models/bunny.obj
Normal file
7474
src/main/resources/models/bunny.obj
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue