本文基礎:編程
C#+OpenGL編程之OpenGL 紋理載入windows
小桃子The Tao FrameworkTao提供的全部庫都是徹底開源的。其中的多數庫均可以避免費用在商業項目中,該框架較其它框架實現更簡單、容易,代碼也簡潔易讀。app
很遺憾的是這個框架已經再也不開發了,做爲程序猿不得不想點其餘的框架了。框架
下面的課程,咱們將使用另一個框架,OpenGL DotNet 官方網站:http://www.taylaninan.com/opengl-dotnetide
做爲咱們的開發框架,比起 小桃子的後繼者OpenTK更接近C代碼風格,要知道,作什麼事都要跟隨大流。如今市面上的遊戲引擎都是C或者C++,而不少OpenGL教程也是基於C或者C++,標新立異等於在裝酷。函數
首先咱們實現最先的基礎實例吧:工具
using System; using System.Collections.Generic; using System.Text; using OpenGLDotNet; namespace OpenGLTK { ///OpenGLDotNet須要修改 ///glut32.dll ->freeglut.dll ///GLUT最初是《OpenGL紅皮書(第二版)》[注2]中的示例程序。自那之後,GLUT簡單、跨平臺的特色,使其在各類實際應用中普遍應用。 ///目前最後版本GLUT v3.7的歷史可追溯至1998年8月,且該項目彷佛已經被廢棄。它的許可證禁止任何人發佈修改後的庫代碼。 ///毋庸置疑GLUT已經很老了,真的須要改善。此外,GLUT的許可證與一些軟件發行不兼容(如XFree86的)。 ///一個輕量級的,開源的,跨平臺的library。支持OpenGL及OpenGL ES,用來管理窗口,讀取輸入,處理事件等。由於OpenGL沒有窗口管理的功能,因此不少熱心的人寫了工具來支持這些功能,好比早期的glut,如今的freeglut等。 ///修改代碼位置 GLU.Functions.cs ///找不到glu32.dll解決方法: ///glu32.dll 改成->GLU32.dll,具體文件名大小寫能夠去 系統目錄搜索這個文件個人是server2012 ///修改代碼位置 GLUT.Functions.cs ///tao->OpenGLDotNet 須要修改的地方 ///函數去掉glu和gl部分,例如 ///GL.glPopMatrix();->GL.PopMatrix(); ///Gl.gl->GL. ///Gl.GL_->GL.GL_ /// Glu.glu->GLU. ///固然你能夠修改源代碼private ->public ///修改代碼位置 GL.CoreDelegates.cs /// <summary> /// 第二章 Opengl程序框架 C# by 大師♂羅莊 /// /// </summary> class Examplefirst : IDisposable { String title = "第二章 Opengl程序框架"; ///窗口大小 internal int windowWidth, windowHeight; //當前幀 internal float currentTime, startTime; //鼠標位置 internal int mouseX, mouseY, button, state; //鍵盤按下 internal byte key; public Examplefirst() { GLConfig.Init(0, 0, title, 25, 25, 1024, 768); GL.Init(true); GLUT.KeyboardFunc(Keyboard); GLUT.MouseFunc(Mouse); GLUT.IdleFunc(Idle); GLUT.ReshapeFunc(Reshape); GLUT.MotionFunc(Motion); GLUT.DisplayFunc(Display); } /// <summary> /// glut鍵盤迴調函數 /// </summary> /// <param name="key"></param> /// <param name="x"></param> /// <param name="y"></param> public virtual void Keyboard(byte key, int x, int y) { this.key = key; } /// <summary> /// glut鼠標按下與釋放回調函數 /// </summary> /// <param name="button"></param> /// <param name="state"></param> /// <param name="x"></param> /// <param name="y"></param> public virtual void Mouse(int button, int state, int x, int y) { this.button = button; this.state = state; this.mouseX = x; this.mouseY = y; return; } /// <summary> /// glut空閒處理回調函數 /// </summary> public void Idle() { currentTime = System.Environment.TickCount; Update(currentTime - startTime); startTime = currentTime; return; } /// <summary> /// glut窗口重置回調函數 /// </summary> /// <param name="width"></param> /// <param name="height"></param> public void Reshape(int width, int height) { windowWidth = width; windowHeight = height; //防止除零問題 windowHeight = windowWidth > 0 ? windowHeight : 1; InitGL(windowWidth, windowHeight); } /// <summary> /// glut鼠標移動回調函數 /// </summary> /// <param name="x"></param> /// <param name="y"></param> public void Motion(int x, int y) { return; } /// <summary> /// glut描繪回調函數 /// </summary> public void Display() { //我感受用這個得從新設置下lookUP才行 iniView(windowWidth, windowHeight); DrawGLScene(); } /// <summary> /// 入口點 /// </summary> public void Run() { GLUT.MainLoop(); } /// <summary> /// 更新用 /// </summary> public virtual void Update(float milliseconds) { if (key == 27) // Escape 按下,退出 { this.Dispose(); } return; } /// <summary> /// 原書的初始化方法,C# by 大師♂羅莊 /// </summary> /// <param name="windowWidth">窗口寬</param> /// <param name="windowHeight">窗口高</param> /// <returns></returns> Boolean InitGL(int windowWidth, int windowHeight) { // 設置視口 viewport GL.Viewport(0, 0, windowWidth, windowHeight); //啓用陰影平滑 GL.ShadeModel(GL.GL_SMOOTH); //啓用反走樣 GL.Hint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // 設置投影模式 projection matrix GL.MatrixMode(GL.GL_PROJECTION); GL.LoadIdentity(); GL.Disable(GL.GL_DITHER); return true; } /// <summary> /// 初始化視口投影,本例子沒有采用原書例子,自定義的視口 /// </summary> public virtual void iniView(int windowWidth, int windowHeight) { GLU.Perspective(65, windowWidth / (double)windowHeight, 1, 100); // 選擇模型觀察矩陣 modelview matrix GL.MatrixMode(GL.GL_MODELVIEW); //重置模型觀察矩陣 GL.LoadIdentity(); GLU.LookAt(0, 1, 0, // 眼睛位置 0, 20, 0, // 觀察點 0, 0, 1); // 怎麼看 } /// <summary> /// 原書的繪製方法 C# by 大師♂羅莊 /// <param name="currentTime">當前幀</param> /// </summary> public virtual void DrawGLScene() { // 重置黑色背景 GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL.Clear(GL.GL_COLOR_BUFFER_BIT); // 畫三角形 GL.Translatef(0, 14, 0); GL.Begin(GL.GL_TRIANGLES); GL.Color3f(1, 0, 0); GL.Vertex3f(-5, 0, -4); GL.Color3f(0, 1, 0); GL.Vertex3f(5, 0, -4); GL.Color3f(0, 0, 1); GL.Vertex3f(0, 0, 6); GL.End(); GLUT.SwapBuffers(); } public void Dispose() { GLUT.KeyboardFunc(null); GLUT.MouseFunc(null); GLUT.IdleFunc(null); GLUT.ReshapeFunc(null); GLUT.MotionFunc(null); GLUT.DestroyWindow(GLUT.GetWindow()); } } }
OpenGL DotNet也非十全十美,須要咱們修改源代碼:oop
一、首先一個問題就是使用glut32.dll,這個庫已是上個世紀的庫了,咱們須要修改GLU.Functions.cs 裏面把glut32.dll改成freeglut.dll性能
二、找不到glu32.dll,這個要你們本身去windows目錄看文件名大小寫,在個人2012上面文件名爲GLU32.dll
而後就能夠把桃子框架代碼移植過來了。
上面的代碼就和C很類似了,使用GLUT函數實現窗口管理,代碼量從160行升至220行。
下面咱們移植下多重紋理吧。
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; using OpenGLDotNet; namespace OpenGLTK { /// <summary> /// 自制的紋理載入類 C# by 大師♂羅莊 /// </summary> class TextureLoad : IDisposable { public uint[] ID = new uint[3]; Bitmap image; public bool Load(String fileName) { ///原則上材質只應該在初始化時候載入一次,不然會影響性能 if (image != null) { return true; } FileInfo file = new FileInfo(fileName); if (file.Exists == false) { MessageBox.Show("沒法載入" + fileName); return false; } try { if (file.Extension.ToUpper() == ".TGA") { ///http://blog.csdn.net/zgke/article/details/4667499 ///C# 載入TGA 類,自行參考,這裏再也不列出 ImageTGA tga = new ImageTGA(fileName); image = tga.Image; } else { image = new Bitmap(fileName); } } catch (System.ArgumentException) { MessageBox.Show("沒法載入" + fileName); return false; } if (image != null) { image.RotateFlip(RotateFlipType.RotateNoneFlipY); System.Drawing.Imaging.BitmapData bitmapdata; Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); ///Nearest Linear MipMapped三個紋理實現,本文暫時不考慮 //bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); //GL.GenTextures(3, this.texture); //// Create Nearest Filtered Texture //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[0]); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); //GL.TexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGB, image.Width, image.Height, 0, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0); //// Create Linear Filtered Texture //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[1]); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); //GL.TexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGB, image.Width, image.Height, 0, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0); //// Create MipMapped Texture //GL.BindTexture(GL.GL_TEXTURE_2D, this.texture[2]); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); //GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_NEAREST); //GL.uBuild2DMipmaps(GL.GL_TEXTURE_2D, (int)GL.GL_RGB, image.Width, image.Height, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0); //image.UnlockBits(bitmapdata); /** 生成紋理對象名稱 */ GL.GenTextures(3, ID); /** 建立紋理對象 */ GL.BindTexture(GL.GL_TEXTURE_2D, ID[0]); /** 控制濾波 */ GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, (int)GL.GL_LINEAR); GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, (int)GL.GL_LINEAR); GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, (int)GL.GL_REPEAT); GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, (int)GL.GL_REPEAT); bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); /** 建立紋理 */ GLU.Build2DMipmaps(GL.GL_TEXTURE_2D, (int)GL.GL_RGB, image.Width, image.Height, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapdata.Scan0); image.UnlockBits(bitmapdata); } return true; } public void FreeImage() { /** 釋放內存 */ if (image != null) { image.Dispose(); } } public void Dispose() { FreeImage(); } } }
using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Windows.Forms; using OpenGLDotNet; namespace OpenGLTK { /// <summary> /// 第四章 OpenGl 多重紋理載入 C# by 大師♂羅莊 /// </summary> class OpenGLMultiTexture : Examplefirst { TextureLoad[] m_texture = new TextureLoad[4]; bool multitexturing=false; /** 檢查是否支持擴展 */ string title = "第四章 OpenGl 多重紋理載入"; public OpenGLMultiTexture() : base() { for (int i = 0; i < 4; i++) { m_texture[i] = new TextureLoad();//對象數組必須初始化 } LoadTexture(); GLUT.SetWindowTitle(title); /** 初始化 */ if (!initMultiTexture())//和原來不同,GL.GetString這個函數不能放入動畫事件 { MessageBox.Show("您的硬件和驅動不支持多重紋理"); return; } } /// <summary> /// 檢查多重紋理支持 /// </summary> /// <param name="input"></param> /// <returns></returns> bool isExtensionSupported(string input) { string extension = GL.GetString(GL.GL_EXTENSIONS); return extension.IndexOf(input)>=0; } bool initMultiTexture() { /** 檢查是否支持擴展 */ if (isExtensionSupported("GL_ARB_multitexture")) { return true; } else return false; } /** 載入紋理數據 */ bool LoadTexture() { /// 文件名 String[] fileName = new String[4] { "wall.bmp", "lightmap.bmp", "bitmap.bmp", "fog.bmp" }; /// 載入四幅位圖 for (int i = 0; i < 4; i++) { if (m_texture[i].Load(Path.Combine(Application.StartupPath, @"Image\" + fileName[i]).ToString()) == false) /**< 載入位圖文件 */ { MessageBox.Show("沒法載入" + fileName[i]); return false; } } return true; } /// <summary> /// 初始化視口投影,恢復原書的視口 /// </summary> public override void iniView(int windowWidth, int windowHeight) { GLU.Perspective(45.0f, windowWidth / windowHeight, 1.0f, 100.0f); GL.MatrixMode(GL.GL_MODELVIEW); GL.LoadIdentity(); GLU.LookAt(0, 1, 0, // 眼睛位置 0, 20, 0, // 觀察點 0, 0, 1); // 怎麼看 } /** 用戶自定義的卸載函數 */ public new void Dispose() { base.Dispose(); for (int i = 0; i < 4; i++) { m_texture[i].FreeImage(); GL.DeleteTextures(1, m_texture[i].ID); } } float wrap = 0; /**< 用於霧的流動 */ public override void Keyboard(byte key, int x, int y) { if (key == 27) // Escape 按下,退出 { this.Dispose(); } /////** 當按下空格時,開啓多重紋理 */ if (key == 0x20) { multitexturing = true;//開啓 } else { multitexturing = false;//按下其餘鍵關閉 } } /// <summary> /// 重載 /// </summary> /// <param name="currentTime"></param> public override void Update(float milliseconds) { wrap += milliseconds /1000; //動畫 速度請本身調節 Display(); } /// <summary> /// 重載,使用Draw方法繪圖 /// </summary> /// <param name="mouseX"></param> /// <param name="currentTime"></param> public override void DrawGLScene() { Draw(); GLUT.SwapBuffers(); } /** 繪製函數 */ void Draw() { /** 用戶自定義的繪製過程 */ GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); GL.LoadIdentity(); GL.Translatef(0.0f, 0.0f, -10.0f); /** 激活紋理0,並綁定紋理 */ GL.ActiveTextureARB(GL.GL_TEXTURE0_ARB); GL.Enable(GL.GL_TEXTURE_2D); GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[0].ID[0]); /** 激活紋理1,並綁定紋理 */ GL.ActiveTextureARB(GL.GL_TEXTURE1_ARB); /** 若是多重紋理啓用,則啓用該紋理 */ if (multitexturing) GL.Enable(GL.GL_TEXTURE_2D); else GL.Disable(GL.GL_TEXTURE_2D); GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[1].ID[0]); /** 繪製一個四方形牆面 */ GL.PushMatrix(); GL.Translatef(-2.5f, 0f, 0f); GL.Scalef(2.0f, 2.0f, 2.0f); GL.Begin(GL.GL_QUADS); /** 左上點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 1.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f, 1.0f); GL.Vertex3f(-1, 1, 0); /** 左下點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 0.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f, 0.0f); GL.Vertex3f(-1, -1, 0); /** 右下點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 0.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f, 0.0f); GL.Vertex3f(1, -1, 0); /** 右上點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 1.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f, 1.0f); GL.Vertex3f(1, 1, 0); GL.End(); /**< 繪製結束 */ GL.PopMatrix(); /** 激活紋理0,並綁定紋理 */ GL.ActiveTextureARB(GL.GL_TEXTURE0_ARB); GL.Enable(GL.GL_TEXTURE_2D); GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[2].ID[0]); /** 激活紋理1,並綁定紋理 */ GL.ActiveTextureARB(GL.GL_TEXTURE1_ARB); /** 若是多重紋理啓用,則啓用該紋理 */ if (multitexturing) GL.Enable(GL.GL_TEXTURE_2D); else GL.Disable(GL.GL_TEXTURE_2D); GL.BindTexture(GL.GL_TEXTURE_2D, m_texture[3].ID[0]); GL.Translatef(2.5f, 0, 0); GL.Scalef(2.0f, 2.0f, 2.0f); GL.Begin(GL.GL_QUADS); /** 左上點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 1.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f - wrap, 1.0f); GL.Vertex3f(-1, 1, 0); /** 左下點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 0.0f, 0.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 0.0f - wrap, 0.0f); GL.Vertex3f(-1, -1, 0); /** 右下點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 0.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f - wrap, 0.0f); GL.Vertex3f(1, -1, 0); /** 右上點 */ GL.MultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, 1.0f, 1.0f); GL.MultiTexCoord2fARB(GL.GL_TEXTURE1_ARB, 1.0f - wrap, 1.0f); GL.Vertex3f(1, 1, 0); GL.End(); } } }
移植只要改改幾個地方就很方便了。
這裏我再次提醒你們,由於咱們用到非託管庫,freeglut.dll。須要把這個DLL拷貝到應用程序目錄,因爲系統分32位和64位,而默認VS生成項目模板是Any CPU,也就是3二、64位自適應的EXE,而OpenGLDotNet和tao 自帶freeglut.dll都是32位。
須要本身設置爲X86 32位EXE,或者自行下載freeglut 編譯一個64位DLL,而後作兩個版本EXE。