为每个帧绑定多个网格的OpenGL顶点缓冲区

时间:2014-11-28 07:14:29

标签: c# opengl 3d opentk

我正在制作具有 MULTIPLE 网格的OpenGL应用程序,这些网格被描述为位置,法线和uv的列表。我将这些数据绑定到顶点缓冲区,但我想知道如何在不重新绑定顶点缓冲区的情况下每帧绘制这些网格物体。如果我错了,请纠正我,但是不要将~100KB的数据复制到顶点缓冲区?如何使用单独的变换(位置,旋转,缩放)绘制每个网格。谢谢:)这是我的网格代码:

using System;
using System.IO;
using OpenTK;
using OpenTK.Graphics.OpenGL;

public class Mesh
{
    public Vector3[] positions;
    public Vector3[] normals;
    public Vector2[] uvs;
    public Triangle[] triangles;
    public int buffer;
    public Mesh()
    {
        this.positions = new Vector3[0];
        this.normals = new Vector3[0];
        this.uvs = new Vector2[0];
        this.triangles = new Triangle[0];
        this.buffer = 0;
    }
    public Mesh(Vector3[] positions, Vector3[] normals, Vector2[] uvs, Triangle[] triangles, int buffer)
    {
        this.positions = positions;
        this.normals = normals;
        this.uvs = uvs;
        this.triangles = triangles;
        this.buffer = buffer;
    }
    public static Mesh fromFile(string fileName)
    {
        Mesh mesh = new Mesh();
        BinaryReader binaryReader = new BinaryReader(new FileStream(fileName, FileMode.Open));
        int positionCount = binaryReader.ReadInt32();
        mesh.positions = new Vector3[positionCount];
        for (int i = 0; i < positionCount; i++)
        {
            mesh.positions[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
        }
        int normalCount = binaryReader.ReadInt32();
        mesh.normals = new Vector3[normalCount];
        for (int i = 0; i < normalCount; i++)
        {
            mesh.normals[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
        }
        int uvCount = binaryReader.ReadInt32();
        mesh.uvs = new Vector2[uvCount];
        for (int i = 0; i < uvCount; i++)
        {
            mesh.uvs[i] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
        }
        int triangleCount = binaryReader.ReadInt32();
        mesh.triangles = new Triangle[triangleCount];
        for (int i = 0; i < triangleCount; i++)
        {
            mesh.triangles[i] = new Triangle(binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32());
        }
        binaryReader.Close();
        return mesh;
    }
    public void toFile(string fileName)
    {
        BinaryWriter binaryWriter = new BinaryWriter(new FileStream(fileName, FileMode.OpenOrCreate));
        binaryWriter.Write(positions.Length);
        for (int i = 0; i < positions.Length; i++)
        {
            binaryWriter.Write(positions[i].X);
            binaryWriter.Write(positions[i].Y);
            binaryWriter.Write(positions[i].Z);
        }
        binaryWriter.Write(normals.Length);
        for (int i = 0; i < normals.Length; i++)
        {
            binaryWriter.Write(normals[i].X);
            binaryWriter.Write(normals[i].Y);
            binaryWriter.Write(normals[i].Z);
        }
        binaryWriter.Write(uvs.Length);
        for (int i = 0; i < uvs.Length; i++)
        {
            binaryWriter.Write(uvs[i].X);
            binaryWriter.Write(uvs[i].Y);
        }
        binaryWriter.Write(triangles.Length);
        for (int i = 0; i < triangles.Length; i++)
        {
            binaryWriter.Write(triangles[i].positionIndex0);
            binaryWriter.Write(triangles[i].normalIndex0);
            binaryWriter.Write(triangles[i].uvIndex0);
            binaryWriter.Write(triangles[i].positionIndex1);
            binaryWriter.Write(triangles[i].normalIndex1);
            binaryWriter.Write(triangles[i].uvIndex1);
            binaryWriter.Write(triangles[i].positionIndex2);
            binaryWriter.Write(triangles[i].normalIndex2);
            binaryWriter.Write(triangles[i].uvIndex2);
        }
        binaryWriter.Close();
    }
    public void draw(Transform transform)
    {
        float[] data = new float[triangles.Length * 24];
        for (int i = 0; i < triangles.Length; i++)
        {
            data[(i * 9) + 0] = positions[triangles[i].positionIndex0].X;
            data[(i * 9) + 1] = positions[triangles[i].positionIndex0].Y;
            data[(i * 9) + 2] = positions[triangles[i].positionIndex0].Z;
            data[(i * 9) + 3] = positions[triangles[i].positionIndex1].X;
            data[(i * 9) + 4] = positions[triangles[i].positionIndex1].Y;
            data[(i * 9) + 5] = positions[triangles[i].positionIndex1].Z;
            data[(i * 9) + 6] = positions[triangles[i].positionIndex2].X;
            data[(i * 9) + 7] = positions[triangles[i].positionIndex2].Y;
            data[(i * 9) + 8] = positions[triangles[i].positionIndex2].Z;
            data[(triangles.Length * 9) + (i * 9) + 0] = normals[triangles[i].normalIndex0].X;
            data[(triangles.Length * 9) + (i * 9) + 1] = normals[triangles[i].normalIndex0].Y;
            data[(triangles.Length * 9) + (i * 9) + 2] = normals[triangles[i].normalIndex0].Z;
            data[(triangles.Length * 9) + (i * 9) + 3] = normals[triangles[i].normalIndex1].X;
            data[(triangles.Length * 9) + (i * 9) + 4] = normals[triangles[i].normalIndex1].Y;
            data[(triangles.Length * 9) + (i * 9) + 5] = normals[triangles[i].normalIndex1].Z;
            data[(triangles.Length * 9) + (i * 9) + 6] = normals[triangles[i].normalIndex2].X;
            data[(triangles.Length * 9) + (i * 9) + 7] = normals[triangles[i].normalIndex2].Y;
            data[(triangles.Length * 9) + (i * 9) + 8] = normals[triangles[i].normalIndex2].Z;
            data[(triangles.Length * 18) + (i * 6) + 0] = uvs[triangles[i].uvIndex0].X;
            data[(triangles.Length * 18) + (i * 6) + 1] = uvs[triangles[i].uvIndex0].Y;
            data[(triangles.Length * 18) + (i * 6) + 2] = uvs[triangles[i].uvIndex1].X;
            data[(triangles.Length * 18) + (i * 6) + 3] = uvs[triangles[i].uvIndex1].Y;
            data[(triangles.Length * 18) + (i * 6) + 4] = uvs[triangles[i].uvIndex2].X;
            data[(triangles.Length * 18) + (i * 6) + 5] = uvs[triangles[i].uvIndex2].Y;
        }
        buffer = GL.GenBuffer();
        GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(triangles.Length * 96), data, BufferUsageHint.StaticDraw);
        //------------------------
        //----------TODO----------
        //------------------------
    }
}

最后一个函数draw是我正在研究的函数。

1 个答案:

答案 0 :(得分:2)

关键是要为每个网格添加一个VBO,然后根据需要重新加载。

如果您使用的是openGL 3.3+,则可以在每个网格的VAO中为每个网格收集所有需要的绑定:(伪伪代码)

class MeshBuffer{
    int vao;
    int vbo;
    int numVertices;

    void Dispose(){
        if(vao==0)return;
        GL.DeleteVertexArrays(1, ref vao);
        GL.DeleteBuffers(1, ref vbo);
        vao = 0;
        vbo = 0;
    }

    void Bind(){
        GL.BindVertexArray(vao);
    }

    void Unbind(){
        GL.BindVertexArray(0);
    }

    void FillVBO(Mesh mesh){
        Dispose();
        GL.GenVertexArrays(1, out vao);
        GL.GenBuffers(1, out vbo);
        float[] data = new float[mesh.triangles.Length * 24];
        //your for loop
        GL.BindVertexArray(vao);
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(triangles.Length * 96), data, BufferUsageHint.StaticDraw);

        GL.VertexAttribPointer(0, 3,  VertexAttribPointerType.Float, 0, 0);
        GL.VertexAttribPointer(1, 3,  VertexAttribPointerType.Float, 0, triangles.Length * 9*4);
        GL.VertexAttribPointer(2, 3,  VertexAttribPointerType.Float, 0, triangles.Length * 18*4);

        GL.BindVertexArray(0);
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    }
}

然后绘制你只需绑定MeshBuffer并将转换矩阵加载到相关的制服中。

int mvpMat = GL.GetUniformLocation(prog, "mvp");

GL.UseProgram(prog);
meshBuffer.Bind();
GL.UniformMatrix4(mvpMat, transform.Mat4());
GL.DrawArrays(GL_TRIANGLES, 0, meshBuffer.numVertices);