Android и OpenGL «как отображать лица»

1

Я хочу отобразить, например, файл *.obj. и нормально, в OpenGL я использую инструкцию:

glBegin(Traing..);
glVertex3f(Face[i].VertexIndex);
glTexcoords2f(Face[i].TexcoordIndex);
glNormal(Face[i].NormalIndex);
glEnd();

Но в Android OpenGL у меня нет этих функций... У меня есть DrawElements (...); но когда я хочу рисовать лицо 34/54/3 (vertex/texcord/normal index массивов), он рисует линейный 34/34/34...

так как я могу нарисовать файл *.obj?


Я ищу в Интернете, и я нашел эту тему: http://www.anddev.org/android-2d-3d-graphics-opengl-problems-f55/obj-import-to-opengl-trouble-t48883.html Итак. Я пишу Редактор моделей в С# в свою игру, и я написал что-то вроде теста:

   public void display2()
    {
        GL.EnableClientState(ArrayCap.VertexArray);
        GL.EnableClientState(ArrayCap.TextureCoordArray);
        GL.EnableClientState(ArrayCap.NormalArray);


        double[] vertexBuff = new double[faces.Count * 3 * 3];
        double[] normalBuff = new double[faces.Count * 3 * 3];
        double[] texcorBuff = new double[faces.Count * 3 * 2];


        foreach (face f in faces)
        {
            for (int i = 0; i < f.vector.Length; i++)
            {
                vertexBuff[i_3] = mesh[f.vector[i]].X;
                vertexBuff[i_3 + 1] = mesh[f.vector[i]].Y;
                vertexBuff[i_3 + 2] = mesh[f.vector[i]].Z;

                normalBuff[i_3] = normal[f.normal[i]].X;
                normalBuff[i_3 + 1] = normal[f.normal[i]].Y;
                normalBuff[i_3 + 2] = normal[f.normal[i]].Z;


                texcorBuff[i_2] = texture[f.texCord[i]].X;
                texcorBuff[i_2 + 1] = texture[f.texCord[i]].Y;
                i_3 += 3;
                i_2 += 2;
            }

        }
        GL.VertexPointer<double>(3, VertexPointerType.Double, 0, vertexBuff);
        GL.TexCoordPointer<double>(2, TexCoordPointerType.Double, 0, texcorBuff);
        GL.NormalPointer<double>(NormalPointerType.Double, 0, normalBuff);


        GL.DrawArrays(BeginMode.Triangles, 0, faces.Count * 3);

        GL.DisableClientState(ArrayCap.VertexArray);
        GL.DisableClientState(ArrayCap.TextureCoordArray);
        GL.DisableClientState(ArrayCap.NormalArray);
    }

и он работает.. но я думаю, что это может быть более оптимизировано?... Я не хочу менять свои данные модели на arraysbuffer, потому что это занимает слишком много места в памяти.. любое предложение?

Теги:
opengl-es

2 ответа

3
Лучший ответ

Я не программист на Android, но я предполагаю, что он использует OpenGL-ES, в котором эти функции устарели (и, кстати, отсутствуют).

Учебники, объясняющие хорошее решение, нарисованы среди множества других, которые показывают, как рисовать треугольники с функциями glVertex3f (потому что они дают легкие и быстрые результаты, но совершенно бессмысленны). Я нахожу это трагическим, поскольку НИКТО не должен использовать эти вещи.

glBegin/glEnd, glVertex3f, glTexcoords2f, и такие функции теперь устарели для производительности (они "медленны", потому что мы должны ограничить количество вызовов в графической библиотеке). Я не буду много говорить об этом, так как вы можете искать его, если хотите. Вместо этого используйте буферы Vertex и Indices. Извините, потому что у меня нет "идеальной" ссылки, чтобы рекомендовать, но вы должны легко получить то, что вам нужно в google :)


Тем не менее, я выкопал некоторые из древнего проекта С#:

  • Примечание. Имя функции изменения привязки OpenTK, но они остаются очень близкими к OGL, например glVertex3f становится GL.Vertex3.

Определение вершины

Простая структура для хранения пользовательских сведений о вершинах (положение, нормальное (если необходимо), цвет...)

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
public struct Vertex
{
  public Core.Math.Vector3 Position;
  public Core.Math.Vector3 Normal;
  public Core.Math.Vector2 UV;
  public uint Coloring;


  public Vertex(float x, float y, float z)
  {
    this.Position = new Core.Math.Vector3(x, y, z);
    this.Normal = new Core.Math.Vector3(0, 0, 0);
    this.UV = new Core.Math.Vector2(0, 0);

    System.Drawing.Color color = System.Drawing.Color.Gray;
    this.Coloring = (uint)color.A << 24 | (uint)color.B << 16 | (uint)color.G << 8 | (uint)color.R;
  }

}

Класс Vertex Buffer

Это класс оболочки вокруг объекта буфера OpenGL для обработки нашего формата вершин.

public class VertexBuffer
{
  public uint Id;
  public int Stride;
  public int Count;

  public VertexBuffer(Graphics.Objects.Vertex[] vertices)
  {
    int size;

    // We create an OpenGL buffer object
    GL.GenBuffers(1, out this.Id); //note: out is like passing an object by reference in C#
    this.Stride = OpenTK.BlittableValueType.StrideOf(vertices); //size in bytes of the VertexType (Vector3 size*2 + Vector2 size + uint size)
    this.Count = vertices.Length;

    // Fill the buffer with our vertices data
    GL.BindBuffer(BufferTarget.ArrayBuffer, this.Id);
    GL.BufferData(BufferTarget.ArrayBuffer, (System.IntPtr)(vertices.Length * this.Stride), vertices, BufferUsageHint.StaticDraw);
    GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size);

    if (vertices.Length * this.Stride != size)
      throw new System.ApplicationException("Vertex data not uploaded correctly");

  }

}

Класс буфера индексов

Очень похож на буфер вершин, он хранит вершинные индексы каждой грани вашей модели.

public class IndexBuffer
{
  public uint Id;
  public int Count;


  public IndexBuffer(uint[] indices)
  {
    int size;
    this.Count = indices.Length;

    GL.GenBuffers(1, out this.Id);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, this.Id);
    GL.BufferData(BufferTarget.ElementArrayBuffer, (System.IntPtr)(indices.Length * sizeof(uint)), indices,
                  BufferUsageHint.StaticDraw);
    GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out size);

    if (indices.Length * sizeof(uint) != size)
        throw new System.ApplicationException("Indices data not uploaded correctly");
  }

}

Буферы рисования

Затем, чтобы отобразить треугольник, вам нужно создать один буфер вершин для хранения позиций вершин. Один буфер Indice, содержащий индексы вершин [0, 1, 2] (обратите внимание на правило против часовой стрелки, но оно то же самое с методом glVertex3f). Когда закончите, просто вызовите эту функцию с указанными буферами. Обратите внимание, что вы можете использовать несколько наборов индексов, содержащих только один буфер вершин, чтобы каждый раз отображать только некоторые грани.

void DrawBuffer(VertexBuffer vBuffer, IndexBuffer iBuffer)
{
  // 1) Ensure that the VertexArray client state is enabled.
  GL.EnableClientState(ArrayCap.VertexArray);
  GL.EnableClientState(ArrayCap.NormalArray);
  GL.EnableClientState(ArrayCap.TextureCoordArray);

  // 2) Bind the vertex and element (=indices) buffer handles.
  GL.BindBuffer(BufferTarget.ArrayBuffer, vBuffer.Id);
  GL.BindBuffer(BufferTarget.ElementArrayBuffer, iBuffer.Id);

  // 3) Set up the data pointers (vertex, normal, color) according to your vertex format.
  GL.VertexPointer(3, VertexPointerType.Float, vBuffer.Stride, new System.IntPtr(0));
  GL.NormalPointer(NormalPointerType.Float, vBuffer.Stride, new System.IntPtr(Vector3.SizeInBytes));
  GL.TexCoordPointer(2, TexCoordPointerType.Float, vBuffer.Stride, new System.IntPtr(Vector3.SizeInBytes * 2));
  GL.ColorPointer(4, ColorPointerType.UnsignedByte, vBuffer.Stride, new System.IntPtr(Vector3.SizeInBytes * 3 + Vector2.SizeInBytes));

  // 4) Call DrawElements. (Note: the last parameter is an offset into the element buffer and will usually be IntPtr.Zero).
  GL.DrawElements(BeginMode.Triangles, iBuffer.Count, DrawElementsType.UnsignedInt, System.IntPtr.Zero);

  //Disable client state
  GL.DisableClientState(ArrayCap.VertexArray);
  GL.DisableClientState(ArrayCap.NormalArray);
  GL.DisableClientState(ArrayCap.TextureCoordArray);
}

Надеюсь, это может помочь;)

1

См. Этот учебник по массивам glVertex

Ещё вопросы

Сообщество Overcoder
Наверх
Меню