-1
\$\begingroup\$

I am trying to create an AABB but I need to know how to store min/max from a mesh.

Here is my code(I got it from thin matrix) :

package com.chimpro.london.objLoader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;

import com.chimpro.london.MainComp;
import com.chimpro.london.gfx.Loader;
import com.chimpro.london.models.TexturedModel;

public class OBJFileLoader {

public static TexturedModel loadOBJ(String objFileName,String textureLoc) throws IOException {
    InputStreamReader fis = new InputStreamReader(MainComp.class.getResourceAsStream(objFileName));
    BufferedReader reader = new BufferedReader(fis);
    String line;
    List<Vertex> vertices = new ArrayList<Vertex>();
    List<Vector2f> textures = new ArrayList<Vector2f>();
    List<Vector3f> normals = new ArrayList<Vector3f>();
    List<Integer> indices = new ArrayList<Integer>();
    try {
        while (true) {
            line = reader.readLine();
            if (line.startsWith("v ")) {
                String[] currentLine = line.split(" ");
                Vector3f vertex = new Vector3f((float) Float.valueOf(currentLine[1]),
                        (float) Float.valueOf(currentLine[2]),
                        (float) Float.valueOf(currentLine[3]));
                Vertex newVertex = new Vertex(vertices.size(), vertex);
                vertices.add(newVertex);

            } else if (line.startsWith("vt ")) {
                String[] currentLine = line.split(" ");
                Vector2f texture = new Vector2f((float) Float.valueOf(currentLine[1]),
                        (float) Float.valueOf(currentLine[2]));
                textures.add(texture);
            } else if (line.startsWith("vn ")) {
                String[] currentLine = line.split(" ");
                Vector3f normal = new Vector3f((float) Float.valueOf(currentLine[1]),
                        (float) Float.valueOf(currentLine[2]),
                        (float) Float.valueOf(currentLine[3]));
                normals.add(normal);
            } else if (line.startsWith("f ")) {
                break;
            }
        }
        while (line != null && line.startsWith("f ")) {
            String[] currentLine = line.split(" ");
            String[] vertex1 = currentLine[1].split("/");
            String[] vertex2 = currentLine[2].split("/");
            String[] vertex3 = currentLine[3].split("/");
            processVertex(vertex1, vertices, indices);
            processVertex(vertex2, vertices, indices);
            processVertex(vertex3, vertices, indices);
            line = reader.readLine();
        }
        reader.close();
    } catch (IOException e) {
        System.err.println("Error reading the file");
    }
    removeUnusedVertices(vertices);
    float[] verticesArray = new float[vertices.size() * 3];
    float[] texturesArray = new float[vertices.size() * 2];
    float[] normalsArray = new float[vertices.size() * 3];
    float furthest = convertDataToArrays(vertices, textures, normals, verticesArray,
            texturesArray, normalsArray);
    int[] indicesArray = convertIndicesListToArray(indices);
    TexturedModel model = new TexturedModel(Loader.loadToVao(verticesArray, texturesArray, normalsArray, indicesArray),0,vertices,furthest, textureLoc);
    return model;

}

private static void processVertex(String[] vertex, List<Vertex> vertices, List<Integer> indices) {
    int index = Integer.parseInt(vertex[0]) - 1;
    Vertex currentVertex = vertices.get(index);
    int textureIndex = Integer.parseInt(vertex[1]) - 1;
    int normalIndex = Integer.parseInt(vertex[2]) - 1;
    if (!currentVertex.isSet()) {
        currentVertex.setTextureIndex(textureIndex);
        currentVertex.setNormalIndex(normalIndex);
        indices.add(index);
    } else {
        dealWithAlreadyProcessedVertex(currentVertex, textureIndex, normalIndex, indices,
                vertices);
    }
}

private static int[] convertIndicesListToArray(List<Integer> indices) {
    int[] indicesArray = new int[indices.size()];
    for (int i = 0; i < indicesArray.length; i++) {
        indicesArray[i] = indices.get(i);
    }
    return indicesArray;
}

private static float convertDataToArrays(List<Vertex> vertices, List<Vector2f> textures,
        List<Vector3f> normals, float[] verticesArray, float[] texturesArray,
        float[] normalsArray) {
    float furthestPoint = 0;
    for (int i = 0; i < vertices.size(); i++) {
        Vertex currentVertex = vertices.get(i);
        if (currentVertex.getLength() > furthestPoint) {
            furthestPoint = currentVertex.getLength();
        }
        Vector3f position = currentVertex.getPosition();
        Vector2f textureCoord = textures.get(currentVertex.getTextureIndex());
        Vector3f normalVector = normals.get(currentVertex.getNormalIndex());
        verticesArray[i * 3] = position.x;
        verticesArray[i * 3 + 1] = position.y;
        verticesArray[i * 3 + 2] = position.z;
        texturesArray[i * 2] = textureCoord.x;
        texturesArray[i * 2 + 1] = 1 - textureCoord.y;
        normalsArray[i * 3] = normalVector.x;
        normalsArray[i * 3 + 1] = normalVector.y;
        normalsArray[i * 3 + 2] = normalVector.z;
    }
    return furthestPoint;
}

private static void dealWithAlreadyProcessedVertex(Vertex previousVertex, int newTextureIndex,
        int newNormalIndex, List<Integer> indices, List<Vertex> vertices) {
    if (previousVertex.hasSameTextureAndNormal(newTextureIndex, newNormalIndex)) {
        indices.add(previousVertex.getIndex());
    } else {
        Vertex anotherVertex = previousVertex.getDuplicateVertex();
        if (anotherVertex != null) {
            dealWithAlreadyProcessedVertex(anotherVertex, newTextureIndex, newNormalIndex,
                    indices, vertices);
        } else {
            Vertex duplicateVertex = new Vertex(vertices.size(), previousVertex.getPosition());
            duplicateVertex.setTextureIndex(newTextureIndex);
            duplicateVertex.setNormalIndex(newNormalIndex);
            previousVertex.setDuplicateVertex(duplicateVertex);
            vertices.add(duplicateVertex);
            indices.add(duplicateVertex.getIndex());
        }

    }
}

private static void removeUnusedVertices(List<Vertex> vertices){
    for(Vertex vertex:vertices){
        if(!vertex.isSet()){
            vertex.setTextureIndex(0);
            vertex.setNormalIndex(0);
        }
    }
}

}
\$\endgroup\$
  • 3
    \$\begingroup\$ Create two Vector3f variables to store the min and max corners respectively, then just loop through your vertices and set the x,y and z components as necessary using min/max functions. \$\endgroup\$ – Daniel Canlin Masterson Mar 14 '18 at 13:18
  • \$\begingroup\$ What have you tried and what went wrong? Also I would recommend removing the parts of the code that is not relevant to your question. \$\endgroup\$ – Charanor Mar 14 '18 at 13:28
  • \$\begingroup\$ @AlexandreVaillancourt the tutorial I use didn't show how to calculate min/max \$\endgroup\$ – Macky ben Jonah Mar 14 '18 at 13:49
  • 4
    \$\begingroup\$ Well, how would you calculate the min/max? If you're to develop games, you have to keep in mind that not everything is taught in tutorials. \$\endgroup\$ – Vaillancourt Mar 14 '18 at 13:51
  • \$\begingroup\$ If you're having trouble doing things like this, I recommend starting out more basic and learning what you are writing is actually doing \$\endgroup\$ – Jason Mar 14 '18 at 14:01
0
\$\begingroup\$

Same solution as Macky ben Jonah's but a little neater:

private static Vector3f getExtreme(final List<Vertex> vertices,
        final BinaryOperator<Float> op) {
    final float x = vertices.stream().map(v -> v.getPosition().x).reduce(op).orElse(0f);
    final float y = vertices.stream().map(v -> v.getPosition().y).reduce(op).orElse(0f);
    final float z = vertices.stream().map(v -> v.getPosition().z).reduce(op).orElse(0f);
    return new Vector3f(x, y, z);
}

Then you can use it like this:

Vector3f min = getExtreme(vertices, Math::min);
Vector3f max = getExtreme(vertices, Math::max);

This requires Java 8 because it makes use of Streams and it is also a lot more performance friendly than the original solution since it does not have to create new lists and loop through them every time it is called.

\$\endgroup\$
  • \$\begingroup\$ would it work for java 9 \$\endgroup\$ – Macky ben Jonah Mar 26 '18 at 17:26
  • \$\begingroup\$ @MackybenJonah Yes, Java is 100% (or close enough) backwards compatible so this will work for all java version >= 8. \$\endgroup\$ – Charanor Mar 26 '18 at 18:08
  • \$\begingroup\$ Try running this code on a java debugger. I'm getting an error. Stream has already been operated on or closed. It is an illegal state exception. For a reference see my code above. \$\endgroup\$ – Macky ben Jonah Apr 8 '18 at 15:09
  • \$\begingroup\$ @MackybenJonah My bad. Just change steam to vertices.stream() (I edited my answer). \$\endgroup\$ – Charanor Apr 8 '18 at 17:14
5
\$\begingroup\$

Set each component of the initial maximum coordinate to the minimum value of a float. Similarly, set each component of the initial minimum to the maximum value of a float.

Iterate over every vertex in the mesh. With each vertex, set the maximum, component-wise, to the larger of the current maximum or the current vertex. Similarly, for the minimum, set it component-wise to the smaller of the current maximum or the vertex.

In pseudo-code, this might look like:

Vector minimum(Float.Maximum, Float.Maximum, Float.Maximum);
Vector maximum(Float.Minimum, Float.Minimum, Float.Minimum);
foreach(Vertex vertex in mesh) {
  minimum = componentwiseMinimum(minimum, vertex.position);
  maximum = componentwiseMaximum(maximum, vertex.position);
}
\$\endgroup\$
-1
\$\begingroup\$

Here is my solution:

    private static Vector3f min(List<Vertex> vertices) {
    List<Float>  xArray= new ArrayList<>();
    List<Float> yArray = new ArrayList<>();
    List<Float> zArray = new ArrayList<>();
    for(Vertex vertex : vertices) {
        xArray.add(vertex.getPosition().x);
        yArray.add(vertex.getPosition().y);
        zArray.add(vertex.getPosition().z);
    }
    return new Vector3f(Collections.min(xArray),Collections.min(yArray),Collections.min(zArray));
}

private static Vector3f max(List<Vertex> vertices) {
    List<Float>  xArray= new ArrayList<>();
    List<Float> yArray = new ArrayList<>();
    List<Float> zArray = new ArrayList<>();
    for(Vertex vertex : vertices) {
        xArray.add(vertex.getPosition().x);
        yArray.add(vertex.getPosition().y);
        zArray.add(vertex.getPosition().z);
    }
    return new Vector3f(Collections.max(xArray),Collections.max   (yArray),Collections.max(zArray));
}
\$\endgroup\$
  • 2
    \$\begingroup\$ While this approach will work (it's doing everything you need it to), it's not very efficient. You're creating a total of six new array objects (you don't need to create any) and you're looping through arrays eight times (you only need to loop through the vertices array once). \$\endgroup\$ – Josh Mar 15 '18 at 18:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.