написание загрузчика .3ds или .obj в java

Я экспортировал модель в блендере в файл .obj. Мне удалось создать очень простой класс, загружающий вершины и индексы в массивы. Моя проблема в том, что мне нужны координаты текстуры (vt) и нормали (vn). Так, например, мне нужно 4 вершины * 6 граней для простого куба, чтобы иметь возможность использовать текстуру, но я получаю только 8 в моем файле .obj, а также я не знаю, как обрабатывать индексы для vt, так как у меня может быть только один массив/буфер для индексов, но я получаю два разных v/vt в файле .obj.

Есть ли какой-нибудь загрузчик, который возвращает только массивы или что-то подобное для вершин, текстур, нормалей и одного массива индексов? Или примеры того, как написать один? Пока я нашел загрузчики только в полных 3D-движках, и это не то, что мне нужно.


person Henrik    schedule 05.05.2011    source источник


Ответы (2)


4 вершины * 6 граней — это больше, чем нужно. На самом деле это будет неэффективно. Экспортированные вершины, которые у вас есть, оптимизированы с помощью индексов. Используя Opengl-es, вы можете указать, откуда взять вершины (массив), а затем нарисовать вершины, используя их индексы в другом массиве. В результате вы получаете 8 вершин против возможных 24 вершин, вам нужно меньше памяти для хранения. Таким образом, эффективность составляет 16/24 * 100%. Представьте, что у вас есть модель с 1000 вершин.

Индекс вершины означает, что в другом массиве с правильным смещением GPU получит вершину (size_of_vertex(3 float)*index) и правильное смещение для координат UV (size_of_UVcoord(2 float)*index)

этот код для opengl ES 2.0, но вы можете получить представление:

GLES20.glUseProgram(programTextured);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
sqTex.getVertexBuffer().position(sqTex.VERT_OFFSET);
GLES20.glVertexAttribPointer(GLES20.glGetAttribLocation(programTextured, "aPosition") 3,                                    GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());               GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(programTextured, "aPosition"));

sqTex.getVertexBuffer().position(sqTex.TEXT_OFFSET);
GLES20.glVertexAttribPointer(
                                GLES20.glGetAttribLocation(programTextured, "aTextureCoord"), 2,
                                GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, sqTex.getIndexBuffer());

а sqTEx — это экземпляр TexturedSquare:

public class TexturedSquare {

        // private float[] vertices=new float[4];

        float vertices[] = { -1.0f, -1.0f, 0.0f,0.0f,0.0f, // 0, Top Left  //x,y,z,u,v
                        1.0f, -1.0f, 0.0f,0.0f,1.0f, // 1, Bottom Left
                        1.0f, 1.0f, 0.0f,1.0f,1.0f, // 2, Bottom Right
                        -1.0f, 1.0f, 0.0f,1.0f,0.0f, // 3, Top Right
        };

        public static int VERT_OFFSET=0;
        public static int TEXT_OFFSET=3;

        short[] indices = { 0, 1, 2, 2, 3, 0 };;

        // Our vertex buffer.
        private FloatBuffer vertexBuffer;

        // Our index buffer.
        private ShortBuffer indexBuffer;

        public TexturedSquare()
        {
                ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
                vbb.order(ByteOrder.nativeOrder());
                vertexBuffer = vbb.asFloatBuffer();
                vertexBuffer.put(vertices);
                vertexBuffer.position(0);

                // short is 2 bytes, therefore we multiply the number if
                // vertices with 2.
                ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
                ibb.order(ByteOrder.nativeOrder());
                indexBuffer = ibb.asShortBuffer();
                indexBuffer.put(indices);
                indexBuffer.position(0);

        }

        FloatBuffer getVertexBuffer(){
                return vertexBuffer;
        }

        ShortBuffer getIndexBuffer(){
                return indexBuffer;
        }



}
person Yuriy Vikulov    schedule 05.05.2011
comment
Спасибо за объяснение. Итак, я понимаю, что мне действительно не нужны все эти вершины. Тем не менее, я до сих пор не совсем понимаю, как я должен обрабатывать тот факт, что я получаю 2 разных массива индексов. Так как я могу ссылаться только на один элемент в gl.glDrawElement или gl.glDrawArray. Я знаю, что так и должно быть. Но означает ли это, что мне придется изменить порядок vt (UV-координаты) так, чтобы, если одно лицо равно (1/4...), я должен переместить vt: 4 в положение 1 (vt: 1)? -- РЕДАКТИРОВАТЬ: Большое спасибо, Юрий, это действительно помогло! - person Henrik; 05.05.2011
comment
Вы анализируете obj-файл, вы получаете разные массивы, тогда у вас будет N граней, вы можете создавать массивы вершин и координат uv в соответствии со значениями индексов граней obj-файла. Эти новые созданные массивы будут иметь N элементов, каждый массив будет иметь N элементов. Вы устанавливаете glEnable определенные массивы, а затем вызываете Draw N элементов - person Yuriy Vikulov; 05.05.2011

Посмотрите на jPCT (или jPCT-AE), это отличная 3D-библиотека для Java (и/или Android). Он поддерживает загрузку 3ds/obj из коробки.

person HammerNL    schedule 04.10.2013