1
\$\begingroup\$

Using Assimp.net I did load obj file. assimp returns back Mesh object that contains vertexes, normals, faces, colors and texture. when I don't use VBO the object will load complete. like this :

enter image description here

But when I use VBO, rendering of object is incomplete. like this :

enter image description here

Here is my source code :

public class VBO : GameWindow
{
    public Mesh InputMesh { get; set; }
    Vbo vbo = new Vbo();
    int textureID;

    public VBO() : base(800, 600)
    {
        Keyboard.KeyDown += OnKeyDownInternal;
    }

    public VBO(Mesh mesh) : this()
    {
        this.InputMesh = mesh;
    }

    private void OnKeyDownInternal(object sender, KeyboardKeyEventArgs e) { OnKeyDown(e); }

    protected virtual void OnKeyDown(KeyboardKeyEventArgs e)
    {
        switch (e.Key)
        {
            // Lighting
            case OpenTK.Input.Key.L:
                if (GL.IsEnabled(EnableCap.Lighting)) GL.Disable(EnableCap.Lighting);
                else GL.Enable(EnableCap.Lighting);
                break;

            // Texture
            case OpenTK.Input.Key.T:
                if (GL.IsEnabled(EnableCap.Texture2D)) GL.Disable(EnableCap.Texture2D);
                else GL.Enable(EnableCap.Texture2D);
                break;

            // Dynamic Update
            case OpenTK.Input.Key.D:
                dynamicUpdate = !dynamicUpdate;
                break;

            // Exit
            case OpenTK.Input.Key.Escape:
                Exit();
                break;
        }
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        GL.ClearColor(0.1f, 0.1f, 0.5f, 0.0f);
        GL.Enable(EnableCap.DepthTest);

        // Vertex Buffers
        vbo = LoadVBO(InputMesh);

        // Lighting
        GL.Enable(EnableCap.Light0);
        GL.Enable(EnableCap.Lighting);

        // Texture
        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Fastest);

        GL.GenTextures(1, out textureID);
        GL.BindTexture(TextureTarget.Texture2D, textureID);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);


        //Bitmap bitmap = new Bitmap("..\\..\\Data\\logo.jpg");
        /*
        Bitmap bitmap = new Bitmap("3Pod_Lorna_001.png");
        BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        {
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
                OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
        }
        bitmap.UnlockBits(data);*/

        GL.Enable(EnableCap.Texture2D);
    }

    protected override void OnResize(EventArgs e)
    {
    }

    protected override void OnUpdateFrame(FrameEventArgs e)
    {
    }

    double counter = 0;
    protected override void OnRenderFrame(FrameEventArgs e)
    {
        base.OnRenderFrame(e);

        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

        GL.PushAttrib(AttribMask.LightingBit);
        GL.Disable(EnableCap.Lighting);
        GL.Color3(Color.White);
        /*
        textPrinter.Begin();
        textPrinter.Draw((1.0 / e.Time).ToString("F2"), font);
        GL.Translate(150, 0, 0);
        textPrinter.Draw("(L)ighting  (T)exture  (D)ynamicUpdate", font);
        textPrinter.End();
        */
        GL.PopAttrib();

        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
        Matrix4 modelview = Matrix4.LookAt(0.0f, 3.5f, 3.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
        GL.LoadMatrix(ref modelview);

        counter += e.Time;
        GL.Rotate(counter * 50, 0, 1, 0);

        Draw(vbo);

        SwapBuffers();
    }

    #region Upload
    private void GenAndFillBuffer(out int outGlBufferId, List<Vector3D> dataBuffer)
    {
        GL.GenBuffers(1, out outGlBufferId);
        GL.BindBuffer(BufferTarget.ArrayBuffer, outGlBufferId);
        var byteCount = dataBuffer.Count * (sizeof(float) * 3);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(byteCount), dataBuffer.ToArray(), BufferUsageHint.StaticDraw);

        VerifyBufferSize(byteCount);
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    }

    private void VerifyBufferSize(int byteCount)
    {
        int bufferSize;
        GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out bufferSize);
        if (byteCount != bufferSize)
        {
            throw new Exception("Vertex data array not uploaded correctly - buffer size does not match upload size");
        }
    }

    private void UploadColors(out int colorBufferId, Mesh mesh)
    {
        GL.GenBuffers(1, out colorBufferId);
        GL.BindBuffer(BufferTarget.ArrayBuffer, colorBufferId);

        var colors = mesh.VertexColorChannels[0];
        // convert to 32Bit RGBA
        var byteCount = colors.Count * 4;
        var byteColors = new byte[byteCount];
        var n = 0;
        foreach (var c in colors)
        {
            byteColors[n++] = (byte)(c.R * 255);
            byteColors[n++] = (byte)(c.G * 255);
            byteColors[n++] = (byte)(c.B * 255);
            byteColors[n++] = (byte)(c.A * 255);
        }

        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(byteCount), byteColors, BufferUsageHint.StaticDraw);

        int bufferSize;
        GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out bufferSize);
        if (byteCount != bufferSize)
        {
            throw new Exception("Vertex array not uploaded correctly");
        }

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

    private void UploadTextureCoords(out int texCoordBufferId, Mesh mesh)
    {
        GL.GenBuffers(1, out texCoordBufferId);
        GL.BindBuffer(BufferTarget.ArrayBuffer, texCoordBufferId);

        var uvs = mesh.TextureCoordinateChannels[0];
        var floatCount = uvs.Count * 2;
        var temp = new float[floatCount];
        var n = 0;
        foreach (var uv in uvs)
        {
            temp[n++] = uv.X;
            temp[n++] = uv.Y;
        }

        var byteCount = floatCount * sizeof(float);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(byteCount), temp, BufferUsageHint.StaticDraw);
        VerifyBufferSize(byteCount);
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    }

    private void UploadFaces(out int elementBufferId, out int indicesCount, out bool is32Bit, Mesh mesh)
    {
        GL.GenBuffers(1, out elementBufferId);
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferId);

        var faces = mesh.Faces;

        // TODO account for other primitives than triangles
        var triCount = 0;
        int byteCount;
        is32Bit = false;
        foreach (var face in faces)
        {
            if (face.IndexCount != 3)
                continue;
            ++triCount;
            if (face.Indices.Any(idx => idx > 0xffff))
                is32Bit = true;
        }

        var intCount = triCount * 3;
        if (is32Bit)
        {
            var temp = new uint[intCount];
            byteCount = intCount * sizeof(uint);
            var n = 0;
            foreach (var idx in faces.Where(face => face.IndexCount == 3).SelectMany(face => face.Indices))
                temp[n++] = (uint)idx;

            GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)byteCount,
                temp, BufferUsageHint.StaticDraw);
        }
        else
        {
            var temp = new ushort[intCount];
            byteCount = intCount * sizeof(ushort);
            var n = 0;
            foreach (var idx in faces.Where(face => face.IndexCount == 3).SelectMany(face => face.Indices))
                temp[n++] = (ushort)idx;

            GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)byteCount, temp, BufferUsageHint.StaticDraw);
        }

        int bufferSize;
        GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out bufferSize);
        if (byteCount != bufferSize)
        {
            throw new Exception("Index data array not uploaded correctly - buffer size does not match upload size");
        }

        GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        indicesCount = triCount * 3;
    }

    Vbo LoadVBO(Mesh mesh)
    {
        Vbo vbo = new Vbo();

        if (mesh.VertexCount == 0) return vbo;
        if (mesh.FaceCount == 0) return vbo;

        // Color Array Buffer
        if (mesh.HasVertexColors(0))
            UploadColors(out vbo.ColorBufferId, mesh);

        // Normal Array Buffer
        if (mesh.HasNormals)
            GenAndFillBuffer(out vbo.NormalBufferId, mesh.Normals);

        // TexCoord Array Buffer
        if (mesh.HasTextureCoords(0))
            UploadTextureCoords(out vbo.TexCoordBufferId, mesh);

        // Vertex Array Buffer
        if (mesh.HasVertices)
            GenAndFillBuffer(out vbo.VertexBufferId, mesh.Vertices);

        // Element Array Buffer
        if (mesh.HasFaces)
            UploadFaces(out vbo.ElementBufferId, out vbo.NumIndices, out vbo.Is32BitIndices, mesh);

        // Store the number of elements for the DrawElements call
        vbo.NumIndices = mesh.FaceCount;

        return vbo;
    }

    #endregion

    void Draw(Vbo vbo)
    {
        // Push current Array Buffer state so we can restore it later
        GL.PushClientAttrib(ClientAttribMask.ClientVertexArrayBit);

        if (vbo.VertexBufferId == 0) return;
        if (vbo.ElementBufferId == 0) return;

        if (GL.IsEnabled(EnableCap.Lighting))
        {
            // Normal Array Buffer
            if (vbo.NormalBufferId != 0)
            {
                GL.BindBuffer(BufferTarget.ArrayBuffer, vbo.NormalBufferId);
                GL.NormalPointer(NormalPointerType.Float, Vector3.SizeInBytes, IntPtr.Zero);
                GL.EnableClientState(ArrayCap.NormalArray);
            }
        }

        // Color Array Buffer (Colors not used when lighting is enabled)
        if (vbo.ColorBufferId != 0)
        {
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo.ColorBufferId);
            GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(int), IntPtr.Zero);
            GL.EnableClientState(ArrayCap.ColorArray);
        }

        // Texture Array Buffer
        if (GL.IsEnabled(EnableCap.Texture2D))
        {
            if (vbo.TexCoordBufferId != 0)
            {
                GL.BindBuffer(BufferTarget.ArrayBuffer, vbo.TexCoordBufferId);
                GL.TexCoordPointer(2, TexCoordPointerType.Float, 8, IntPtr.Zero);
                GL.EnableClientState(ArrayCap.TextureCoordArray);
            }
        }

        // Vertex Array Buffer
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo.VertexBufferId);
        GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, IntPtr.Zero);
        GL.EnableClientState(ArrayCap.VertexArray);

        // Element Array Buffer
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, vbo.ElementBufferId);
        GL.DrawElements(BeginMode.Triangles, vbo.NumIndices, vbo.Is32BitIndices ? DrawElementsType.UnsignedInt : DrawElementsType.UnsignedShort, IntPtr.Zero);

        // Restore the state
        GL.PopClientAttrib();
    }

    struct Vbo
    {
        public int VertexBufferId;
        public int ColorBufferId;
        public int TexCoordBufferId;
        public int NormalBufferId;
        public int ElementBufferId;
        public int NumIndices;
        public bool Is32BitIndices; 
    }
}

Where is my mistake?

\$\endgroup\$
2
  • \$\begingroup\$ I feel I should point out that you should have just kept your original question. AFAIK, I was the only downvoter, and now that this is a suitable question, I would be upvoting regardless. No harm done, though you do now have another "deleted negative question" in your records for no good reason. In the long run, a pattern like this can limit your asking privileges. \$\endgroup\$
    – Gnemlock
    Jan 9, 2017 at 1:14
  • \$\begingroup\$ Thank you for upvoting. My previous question was held off! So I did decide to delete both (SO and GameDev) questions and ask a new question here! \$\endgroup\$ Jan 9, 2017 at 7:56

1 Answer 1

0
\$\begingroup\$

Finally I found the answer!

I changed this line :

GL.DrawElements(BeginMode.Triangles, vbo.NumIndices, vbo.Is32BitIndices ? DrawElementsType.UnsignedInt : DrawElementsType.UnsignedShort, IntPtr.Zero);

to This :

GL.DrawElements(BeginMode.Triangles, vbo.NumIndices * 3, vbo.Is32BitIndices ? DrawElementsType.UnsignedInt : DrawElementsType.UnsignedShort, IntPtr.Zero);

and problem solved.

enter image description here

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .