• openTK学习


    简介

    the Open Tool Kit (OpenTK), 是对 OpenGL、OpenAL、OpenCL 的跨平台的封装,使用 C# 编写,它可以用在Mono、dotNet的语言:c#、VB、C++/CLI、F#、Boo等。

    什么是Mono

    参考:http://baike.baidu.com/subview/26639/9339264.htm?fr=aladdin

    Mono是一个由Novell公司(由Ximian发起,并由Miguel de lcaza领导的,一个致力于开创.NET在Linux上使用的开源工程。它包含了一个C#语言的编译器,一个CLR的运行时,和一组类库,并实现了 ADO NET和ASP NET。能够使得开发人员在Linux用C#开发程序。)主持的项目.该项目的目标是创建一系列符合标准ECMA (Ecma-334和Ecma-335)的.Net 工具, 包括C #编译器和共同语言(CL 即 Common Language)执行平台(Platform).与微软的.Net不同, Mono项目不仅可以运行于Windows系统内,还可以运行于Linux, FreeBSD, Unix, Mac OS X和Solaris.

    什么是C++/CLI

    参考:http://baike.baidu.com/link?url=QPwZ5Jga7wKJJKn_NWkbvIucYtgvCHtZ3UZ9sRKD7i-eNGXg8m0nYpWVNSyt0yjQ

    简而言之就是如何用C++在·NET中编程

    什么是OpenAL

    参考:http://baike.baidu.com/view/1355367.htm?fr=aladdin

    是开源的跨平台音效API

    什么是OpenCL

    参考:http://baike.baidu.com/view/2056591.htm

    是第一个面向异构系统通用目的并行编程的开放式、免费标准,也是一个统一的编程环境


    使用

    环境

    dotNet IDE可以使用Visual Studio或 MonoDevelop http://monodevelop.com/Download

    添加OpenTK.dll:右键“Project”,选择“Add Reference”,找到OpenTK.dll并添加它。

    Windows.Forms+GLControl

    参考:http://www.opentk.com/doc/chapter/2/glcontrol

    向工具箱中添加GLControl控件

    在工具箱的空白处右键,选择“Choose Item……”,浏览到OpenTK.GLControl.dll,添加。

    创建顺序

    he fact that glControl1'sGLContext is created in runtime is important to remember however, since you cannot access or changeglControl1's properties reliably until theGLContext has been created. The same is true for anyGL.* commands (orGlu for that matter!).

    1.运行Windows.Form的构造函数

    2.加载form的事件

    3.加载GLControl的事件,OK to touch glControl/GL

    4.运行事件处理函数 ,ny event handler may touch glControl/GL.

    解决这个问题的一种方法是定义bool loaded=false;在GLControl加载时设置为true。

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1.  using OpenTK.Graphics;  
    2.  using OpenTK.Graphics.OpenGL;  
    3.   
    4. public partial class Form1 : Form  
    5. {  
    6.   bool loaded = false;  
    7.   
    8.   public Form1()  
    9.   {  
    10.     InitializeComponent();  
    11.   }  
    12.   
    13.   private void glControl1_Load(object sender, EventArgs e)  
    14.   {  
    15.     loaded = true;  
    16.   }  
    17. }  


    由OpenTK还没有开发GLControl.Load事件,所以可以使用Form.Load事件

    然后在你想使用glControl/GL的事件处理函数中检查loaded

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. private void glControl1_Resize(object sender, EventArgs e)  
    2.    {  
    3.      if (!loaded)  
    4.        return;  
    5.    }  


    在VS中事件处理函数是很简单的:

    1.在Designer中选择GLControl

    2.在属性框中选择事件

    3.在相应的事件中设置处理函数

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. private void glControl1_Paint(object sender, PaintEventArgs e)  
    2.    {  
    3.      if (!loaded) // Play nice  
    4.        return;  
    5.   
    6.      GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);  
    7.      glControl1.SwapBuffers();  
    8.    }  

    视口初始

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1.  private void glControl1_Load(object sender, EventArgs e)  
    2. {  
    3.   loaded = true;  
    4.   GL.ClearColor(Color.SkyBlue);  
    5.   SetupViewport();  
    6. }  
    7.   
    8. private void SetupViewport()  
    9. {  
    10.   int w = glControl1.Width;  
    11.   int h = glControl1.Height;  
    12.   GL.MatrixMode(MatrixMode.Projection);  
    13.   GL.LoadIdentity();  
    14.   GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)  
    15.   GL.Viewport(0, 0, w, h); // Use all of the glControl painting area  
    16. }  

    键盘输入

    有两种常用的方法:(1)使用Windows.Forms的按键事件(2)使用OpenTK的KeyboardDevice。

    glControl1 is not painted all the time,操作系统的窗口管理器会确保绘制事件尽可能少的发生,一般只有在resize、窗口模糊等情况下才会触发绘制事件。如果我们想手动调用重绘,使用Invalidate()

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. private void glControl1_KeyDown(object sender, KeyEventArgs e)  
    2.   
    3.  if (!loaded)  
    4.    return;  
    5.  if (e.KeyCode == Keys.Space)  
    6.  {  
    7.    x++;  
    8.    glControl1.Invalidate();  
    9.  }  

    窗口大小的改变

    当GLControl的大小发生变化,我们需要更新的是viewport和projection matrix。

    如果我们从右下角缩小窗口时,并不会解发重绘,这是因为窗口管理器认为(0,0)像素还存在(所以如果从左上角缩小就会重绘),解决的方法就是调用Invalidate()

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. private void glControl1_Resize(object sender, EventArgs e)  
    2.     {  
    3.       SetupViewport();  
    4.       glControl1.Invalidate();  
    5.     }  

    添加动画

    有两种方法:(1)添加一个Timer 控件,使用的其Tick事件(2)使用Thread。

    这里使用第三种方式,使用Windows.Forms的Application.idle事件

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1.  private void glControl1_Load(object sender, EventArgs e)  
    2. {  
    3.   loaded = true;  
    4.   GL.ClearColor(Color.SkyBlue);  
    5.   SetupViewport();  
    6.   Application.Idle += Application_Idle; // press TAB twice after +=  
    7. }  
    8.   
    9. void Application_Idle(object sender, EventArgs e)  
    10. {  
    11. }  

    当窗口比较大时,渲染(render)比较慢

    原因是窗口的3d rendering比full-screen rendering一般要慢。那么可以使用一种frame-rate independent animation的技术,思想很简单:根据当前的渲染速度调整变化量,比如旋转量(渲染慢的使用的量大)。可以使用StopWatch来测量一个frame的渲染时间。StopWatch的用法:

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. Stopwatch sw = new Stopwatch();  
    2.    sw.Start();  
    3.    MyAdvancedAlgorithm();  
    4.    sw.Stop();  
    5.    double milliseconds = sw.Elapsed.TotalMilliseconds;  

    (不要使用DataTime.Now,因为它的大小是10ms级的,和frame的渲染时间是一个数量级)

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. Stopwatch sw = new Stopwatch(); // available to all event handlers  
    2.  private void glControl1_Load(object sender, EventArgs e)  
    3.  {  
    4.    ...  
    5.    sw.Start(); // start at application boot  
    6.  }  
    7.   
    8.  float rotation = 0;  
    9.  void Application_Idle(object sender, EventArgs e)  
    10.  {  
    11.    // no guard needed -- we hooked into the event in Load handler  
    12.   
    13.    sw.Stop(); // we've measured everything since last Idle run  
    14.    double milliseconds = sw.Elapsed.TotalMilliseconds;  
    15.    sw.Reset(); // reset stopwatch  
    16.    sw.Start(); // restart stopwatch  
    17.   
    18.    // increase rotation by an amount proportional to the  
    19.    // total time since last Idle run  
    20.    float deltaRotation = (float)milliseconds / 20.0f;  
    21.    rotation += deltaRotation;  
    22.   
    23.    glControl1.Invalidate();  
    24.  }  

    FPS计数器

    我们怎么知道1s已经过去了呢?

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. void Application_Idle(object sender, EventArgs e)  
    2.     {  
    3.       double milliseconds = ComputeTimeSlice();  
    4.       Accumulate(milliseconds);  
    5.       Animate(milliseconds);  
    6.     }  
    7.    
    8.     private double ComputeTimeSlice()  
    9.     {  
    10.       sw.Stop();  
    11.       double timeslice = sw.Elapsed.TotalMilliseconds;  
    12.       sw.Reset();  
    13.       sw.Start();  
    14.       return timeslice;  
    15.     }  
    16.    
    17.     float rotation = 0;  
    18.     private void Animate(double milliseconds)  
    19.     {  
    20.       float deltaRotation = (float)milliseconds / 20.0f;  
    21.       rotation += deltaRotation;  
    22.       glControl1.Invalidate();  
    23.     }  
    24.    
    25.     double accumulator = 0;  
    26.     int idleCounter = 0;  
    27.     private void Accumulate(double milliseconds)  
    28.     {  
    29.       idleCounter++;  
    30.       accumulator += milliseconds;  
    31.       if (accumulator > 1000)  
    32.       {  
    33.         label1.Text = idleCounter.ToString();  
    34.         accumulator -= 1000;  
    35.         idleCounter = 0; // don't forget to reset the counter!  
    36.       }  
    37.     }  


    使用多个GLControl

    假如说我们有glCtrl1和glCtrl2,想要在Paint事件处理函数中使用它们,具体看代码:

    [csharp] view plain copy 在CODE上查看代码片派生到我的代码片
    1. private void glCtrl1_Paint(object sender, PaintEventArgs e)  
    2.   
    3.  if (!loaded)  
    4.    return;  
    5.   
    6.  glCtrl1.MakeCurrent(); // Ohh.. It's that simple?  
    7.   
    8.  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);  
    9.  ...  
    10. }  

    尽管每个GLControl有它们自己的GraphicsContext,OpenTK默认是共享OpenGL资源的。你也可以禁止这个行为,能过设置属性GraphicsContext.ShareContexts。


    参考:http://www.cnblogs.com/beginor/archive/2009/10/17/1585040.html

    http://www.opentk.com/

  • 相关阅读:
    mass Framework event模块 v9
    关于开源的网络爬虫/网络蜘蛛larbin结构分析
    socketaddr和socketaddr_in的区别于联系
    C语言中.h和.c文件解析
    [原]变参函数原理详解
    fopen和open有什么区别?
    C语言的那些小秘密之变参函数的实现
    c语言中逗号运算符和逗号表达式
    关于REST API设计的一些小经验
    Linux信号说明列表
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/5774944.html
Copyright © 2020-2023  润新知