2017-01-25 11 views
2

Как обычно, когда я пытаюсь намочить мои пальцы с помощью современного OpenGL, используя одну из умных демонстраций, которые можно найти в некоторых блогах, что-то пошло не так.Данные о цвете, которые не используются в OpenGL «Hello world»

Ожидаемое поведение: Нарисуйте треугольник, и цвета должны быть интерполированы между тремя вершинами.

Поведение: Треугольник красный. И неважно, какие цвета я пишу в массив цветов.

Код сначала (извините 160 строк - современный OpenGL - спам ...).

open System 
open System.Drawing 
open System.Collections.Generic 

open OpenTK 
open OpenTK.Graphics 
open OpenTK.Graphics.OpenGL 
open OpenTK.Input 

module Shaders = 
    let vertexShader = 
     """#version 330 

in vec3 vPosition; 
in vec3 vColor; 
out vec4 color; 
uniform mat4 modelview; 

void 
main() 
{ 
    gl_Position = modelview * vec4(vPosition, 1.0); 

    color = vec4(vColor, 1.0); 
} 
""" 
    let fragmentShader = 
     """#version 330 

in vec4 color; 
out vec4 outputColor; 

void 
main() 
{ 
    outputColor = color; 
} 
""" 
    let initShaders() : int = 
     let makeShader shaderType src = 
      let sh = GL.CreateShader(shaderType) 
      GL.ShaderSource(sh,src) 
      GL.CompileShader(sh) 
      sh 
     let pgmId = GL.CreateProgram() 
     let vsh = makeShader ShaderType.VertexShader vertexShader 
     let fsh = makeShader ShaderType.FragmentShader fragmentShader 
     GL.AttachShader(pgmId,vsh) 
     GL.AttachShader(pgmId,fsh) 
     GL.LinkProgram(pgmId) 
     pgmId 

let failMinusOne = function 
    | -1 -> failwith "Something is -1 which should not be -1!" 
    | x -> x 

type Game(width,height) = 
    inherit GameWindow(width, height, GraphicsMode.Default, "F# OpenTK Sample") 
    do base.VSync <- VSyncMode.On 

    let mutable shaderProgramId = -1 
    let mutable attribute_vcol = -1 
    let mutable attribute_vpos = -1 
    let mutable uniform_mview = -1 

    let mutable vbo_col = 0 
    let mutable vbo_pos = 0 

    let vertex_data = 
     [| 
      Vector3(-0.8f, -0.8f, 0.f) 
      Vector3(0.8f, -0.8f, 0.f) 
      Vector3(0.f, 0.8f, 0.f) 
     |] 

    let col_data = 
     [| 
      Vector3(1.f, 1.f, 1.f) 
      Vector3(0.f, 0.f, 1.f) 
      Vector3(0.f, 1.f, 0.f) 
     |] 

    let mview_data = [| Matrix4.Identity |] 

    /// <summary>Load resources here.</summary> 
    /// <param name="e">Not used.</param> 
    override o.OnLoad e = 
     base.OnLoad(e) 
     o.Title <- "Hello OpenTK!" 
     shaderProgramId <- Shaders.initShaders() 

     GL.ClearColor(Color.CornflowerBlue) 
     GL.Enable(EnableCap.DepthTest) 

     attribute_vpos <- GL.GetAttribLocation(shaderProgramId, "vPosition") |> failMinusOne 
     attribute_vcol <- GL.GetAttribLocation(shaderProgramId, "vColor") |> failMinusOne 
     uniform_mview <- GL.GetUniformLocation(shaderProgramId, "modelview") |> failMinusOne 

     vbo_col <- GL.GenBuffer() 
     vbo_pos <- GL.GenBuffer() 

    /// <summary> 
    /// Called when your window is resized. Set your viewport here. It is also 
    /// a good place to set up your projection matrix (which probably changes 
    /// along when the aspect ratio of your window). 
    /// </summary> 
    /// <param name="e">Not used.</param> 
    override o.OnResize e = 
     base.OnResize e 
     GL.Viewport(base.ClientRectangle.X, base.ClientRectangle.Y, base.ClientRectangle.Width, base.ClientRectangle.Height) 
     let projection = Matrix4.CreatePerspectiveFieldOfView(float32 (Math.PI/4.), float32 base.Width/float32 base.Height, 1.f, 64.f) 
     GL.MatrixMode(MatrixMode.Projection) 
     GL.LoadMatrix(ref projection) 


    /// <summary> 
    /// Called when it is time to setup the next frame. Add you game logic here. 
    /// </summary> 
    /// <param name="e">Contains timing information for framerate independent logic.</param> 
    override o.OnUpdateFrame e = 
     base.OnUpdateFrame e 
     if base.Keyboard.[Key.Escape] then base.Close() 
     else 
      GL.BindBuffer(BufferTarget.ArrayBuffer,vbo_col) 
      GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,Array.length col_data * Vector3.SizeInBytes,col_data,BufferUsageHint.StaticDraw) 
      GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, false, 0, 0) 

      GL.BindBuffer(BufferTarget.ArrayBuffer,vbo_pos) 
      GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,Array.length vertex_data * Vector3.SizeInBytes,vertex_data,BufferUsageHint.StaticDraw) 
      GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0) 

      GL.UniformMatrix4(uniform_mview,false,ref mview_data.[0]) 
      GL.BindBuffer(BufferTarget.ArrayBuffer,0) 

      GL.UseProgram(shaderProgramId) 

    /// <summary> 
    /// Called when it is time to render the next frame. Add your rendering code here. 
    /// </summary> 
    /// <param name="e">Contains timing information.</param> 
    override o.OnRenderFrame(e) = 
     base.OnRenderFrame e 
     GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit); 
     GL.EnableVertexArrayAttrib(attribute_vpos,0) 
     GL.EnableVertexArrayAttrib(attribute_vcol,0) 

     GL.DrawArrays(PrimitiveType.Triangles,0,Array.length vertex_data) 

     GL.DisableVertexArrayAttrib(attribute_vpos,0) 
     GL.DisableVertexArrayAttrib(attribute_vcol,0) 

     GL.Flush() 
     base.SwapBuffers() 

[<EntryPoint>] 
let main argv = 
    use game = new Game(800,600) 
    do game.Run(30.,30.) 
    0 // return an integer exit code 

Спустя несколько часов, пытаясь найти то, что происходит, у меня кончились идеи. Добавление большего количества треугольников также кажется на флопе. Но тогда тот факт, что треугольник показывает, как показывают вершины, заставляет меня думать, что загрузка данных в gpu в порядке.

Но для вас, ребята, которые делают этот день в день, вероятно, будет легко обнаружить, где все пошло не так.

+1

Это работает для меня на рабочем столе NVidia после изменения синтаксиса кода текущей версии OTK. Это может быть типичная, адски багги поддержка OpenGL. Проверьте, какие графические процессоры, драйверы и версии OTK происходят. Будьте готовы, чтобы современный OpenGL-код мог отображать пять разных результатов на пяти «типичных» компьютерах. Особенно старые драйверы AMD и Intel могут настолько ошибочно, что вызов современного OpenGL «поддерживается» является пограничным мошенничеством. Какой GPU, версия драйвера и версия OpenTK вы используете? – Vandroiy

+1

My OpenTK - это текущий пакет nuget, который я получил только вчера (версия 2.0.0). Мой графический процессор NVIDIA немного старше (GTX 650). 3D-приложения обычно работают с обычной шаткой надежностью современной 3D-драйверов, багги и неустойчивостью. Я не знаю, что такое OTK (я ссылался на OpenTK.dll и ничего больше). Версия драйвера: 21.21.13.7290 (думаю, он поставляется с обновлениями Windows 10) – BitTickler

+1

Oh! Мой плохой, по-видимому, обновление 2.0 удалило устаревшее предупреждение, поэтому я ошибочно предположил, что вы на старой версии. А я был. Похоже, что ошибка связана с индексом активации массива вершин; дайте мне минутку, чтобы ответить. – Vandroiy

ответ

4

Вы используете функцию OpenGL 4.5, EnableVertexArrayAttrib, чтобы включить свой массив атрибутов вершины на объект массива вершин (VAO) с идентификатором 0. Это характерно, так как ваши шейдеры имеют версию 330, которая намного старше, но, что более важно, недействительна, поскольку вы не используете какое-либо VAO.

Вы можете включить/отключить вершину ATTRIB массивы классическим способом, как это:

GL.EnableVertexAttribArray(attribute_vpos) 
GL.EnableVertexAttribArray(attribute_vcol) 

GL.DisableVertexAttribArray(attribute_vpos) 
GL.DisableVertexAttribArray(attribute_vcol) 

Это приводит к правильной цветной треугольник на моем рабочем столе NVidia GTX 760, так как он действует на текущем активном массиве вершин Информация.

Я бы посоветовал вам взглянуть на то, как вы используете конечный автомат. Включение вершинных массивов и определение их структуры с помощью VertexAttribPointer зависит от программы и принадлежит вместе. Обычно вы должны использовать VAO для группировки этой информации и отсоединения ее после завершения рисования. Если массивы атрибутов вершин должны быть глобальными, нет смысла их отключать, и этот факт должен быть хорошо документирован. Как и в случае с кодом, возникает опасность создания ложных взаимодействий между кажущимися несвязанными функциями, поскольку он разделяет сложное состояние конечного автомата OpenGL.

Возможный подход будет:

  • Настройки

    • Создания шейдеров, держать шейдер программу ручки и место ATTRIB

    • Создание буферов, инициализировать данные, а затем сохранить их ручки и оставить их несвязанными

    • Создайте структуру массива вершин как VAO, затем сохраните ее ручку и оставьте ее незаблокированной.

      • Для каждого массива вершин включите и укажите (например,VertexAttribPointer)
  • Рисунок

    • Bind ВАО
    • изменения Bind/дополнительные буферы (при необходимости)
    • Bind программа
    • вызов отрисовки
    • UNBIND все снова (быстро сбой, если что-то ошибочно полагается на состояние OpenGL)

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

Нет необходимости в различных изменяемых значениях и их инициализации до -1. Они могут быть привязаны по порядку, непосредственно назначая правильный дескриптор (при условии, что контекст OpenGL уже присутствует, см. Комментарии.)

+0

Да, это была проблема. Большое спасибо! Теперь я вижу, что я ожидал увидеть! – BitTickler

+0

Что касается прямых привязок привязки ... Я не был уверен, могу ли я сделать это, учитывая, что, возможно, до вызова OnLoad(), opengl может даже не инициализироваться. Кроме того, в этот момент программа шейдеров еще не создана. – BitTickler

+1

@BitTickler Я * думаю * контекст должен быть там; он должен быть создан с помощью GameWindow, и если я правильно помню строгий порядок, это должно сработать. Хотя я не использую наследование, но вместо этого использую события GameWindow для взаимодействия с ним, что лучше для инкапсуляции. К сожалению, документация OpenTK находится в довольно хаотичном состоянии. Сначала можно создать программу шейдеров, если вам нужно прочитать индексы. Если я изменил определение на 'let shaderProgramId = Shaders.initShaders()' в вашем коде, он отлично работает. – Vandroiy