[WindowsMobile]OpenGLES绘制3D图形
1. 簡介
想要在 Windows Mobile 畫3維圖形~就會想到 DirectX
OpenGL~而想在 Windows Mobile 使用 OpenGL~則必須使用 OpenGL ES ( OpenGL for Embedded Systems )~OpenGL ES 為 OpenGL 三維圖形 API 的子集~主要針
手機、PDA 等嵌入式裝置所設計。而 OpenGL ES 可以算是 OpenGL 精簡版~捨去了 glBegin/glEnd~四邊形;GL_QUADS,、多邊形;GL_POLYGONS,等複雜圖形繪製函式。
本文介紹如何使用.NET Compact Framework wrapper for OpenGL ES 函式庫~以 C# 撰寫程式~而程式功能一個旋轉的三角形~執行結果請參考為畫
以下影片。
2. OpenGL ES
2.1 初始化 EGL
要使用 OpenGL ES 於
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
單中~必須與要顯示的視做關聯~而這部是有標窗份
準~其標準 為EGL~初始化過程如下所示
接著介紹 EGL 標準會使用 EGL 函式與
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
(1) 獲取 Display ( EGLDisplay )
Display 代表顯示器~在有些系統上可以有多個顯示器~也就會有多個
Display。獲得 Display 使用以下程式碼
1egl.GetDisplay(new EGLNativeDisplayType(this));(2) 初始化 EGL
使用以下程式碼進行初始化動作~回傳 並EGL 版本 ( major.minor )1egl.Initialize(myDisplay, out major, out minor);(3) 設定 EGLConfig ( EGLConfig )
設定 EGLConfig 其實是指定 FrameBuffer 的參數~透過
egl.ChooseConfig(EGLDisplay myDisplay, const EGLint * attribList, 1EGLConfig * configs, EGLint config.Length, EGLint *numConfig)
其中 attribList 是以EGL_NONE 結束的參數群組~以 id, value 依次存放~
對於個別標識性的屬性可以只有 id~沒有value~系統的總共的 Config 個數
儲存在 numConfig 中。Config 有多的屬性~這些屬性決定 眾FrameBuffer 的格式和能力~以下設定 為EGLConfig 的程式碼。
01EGLConfig[] configs = new EGLConfig[10];
int[] attribList 02= new int[]
03{
04 egl.EGL_RED_SIZE, 5,
05 egl.EGL_GREEN_SIZE, 6,
egl.EGL_BLU06E_SIZE, 5,
egl.EGL_DEPTH_SIZE, 0716 ,
egl.EGL_SURFACE_TYPE, 08egl.EGL_WINDOW_BIT,
09 egl.EGL_STENCIL_SIZE, egl.EGL_DONT_CARE,
egl.EGL_NONE, 10egl.EGL_NONE
11};
12
13int numConfig;
if (!egl.ChooseConfig(myDisplay, attribList, configs, 14configs.Length, out numConfig) || numConfig < 1)15 throw new InvalidOperationException("Unable to choose config.");
16
17EGLConfig config = configs[0];
(4) 構造 Surface ( EGLSurface )
Surface 是一個 FrameBuffer~透過 CreateWindowSurface 創建可實際顯示的 Surface
1egl.CreateWindowSurface(myDisplay, config, Handle, null);
(5) 創建 Context ( EGLContext )
OpenGL 的 pipeline 從程式的角度看就是一個狀態機~有目前的色、紋理顏、變化矩陣等狀態~這些狀態作用於程式提交的頂點坐標等圖形元素~從而形成緩衝區內的像素。在 OpenGL 中~Context 就代表這個狀態機~程式的主要工作就是像 Context 提供圖型元素、設定狀態~偶爾從 Context 裡獲取一些訊息。使用 CreateContext 來創建一個 Context
1egl.CreateContext(myDisplay, config, EGLContext.None, null);
(6) 設定繪製環境 Render Context
主要
上述設定之 EGL~透過 MakeCurrent 設定繪製環境~接著就可以透過 OpenGL API 進行繪製。
1egl.MakeCurrent(myDisplay, mySurface, mySurface, myContext);
2.2 進行繪製
(1) 初始化 OpenGL ES
開始繪製前~必須先做初始化~設定像背景~深度測試等參數
01void InitGL()
02{
gl.ShadeModel(gl.GL_SMOOTH); 03 // 設定陰影模式為平滑
04 // gl.ClearColor(1.0f, 1.0f, 1.0f, 0.5f); // 白色背景
05 gl.ClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
gl.ClearDepthf(1.0f); // 設置06深度緩衝
gl.Enable(gl.GL_DEPTH_TEST); /07/ 使用深度測試
gl.BlendFunc(gl.GL_SRC_ALPHA, 08gl.GL_ONE_MINUS_SRC_ALPHA); // 設定混合函數~設定並為源因子
GL_SRC_ALPHA~目的因子為GL_ONE_MINUS_SRC_ALPHA09
gl.DepthFunc(gl.GL_LEQUAL); // 所做的深度測試為 GL_LEQUAL 深度小或相等的时候也渲染
10
gl.Hint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_NICEST); // 系統
測試進行修正
11}
(2) OpenGL ES 繪圖部分的函式
以下程式碼 為OpenGL ES 繪圖部分的函式~並且在 OnPaint 重繪事件時調用此函式~假如
Color 部分的程式碼註解掉~則顯示之三角型為白色
float myRotation 01= 0;
02unsafe void DrawGLScene()
03{
gl.Viewport(ClientRectangle.Left, ClientRectangle.Top, 04ClientRectangle.Width, ClientRectangle.Height); // 設定圖形要顯示的區域05
gl.MatrixMode(gl.GL_PROJECTION); // 設定目前工作矩陣 為Projection
矩陣
06
gl.LoadIdentity(); //
Projection 矩陣初始化
gluPerspective(45, (float)ClientSize.Width / (float)ClientSize.Height, .1f, 07100); // 設定圖形 gluPerspective 透視投影
08
float[] triangle = new float[] { 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 09-1.0f, 0.0f };
float[] colors = new float[] { 1.0f, 0.0f, 0.0f, 9, 0.0f, 1.0f, 0.0f, 0, 100.0f, 0.0f, 1.0f, 0 };
11
12 gl.Translatef(0.0f, 0.0f, -6.0f); // 平移函式~表示 x,y,z 偏移量
gl.Rotatef(myRotation, 0.0f, 1.0f, 0.0f); // 旋轉函式~參數x,y,z代表13一個向量~指旋轉所繞的軸~參數 myRotation 表示旋轉逆時針的角度14
15 fixed (float* trianglePointer = &triangle[0], colorPointer = &colors[0])16 {
gl.EnableClientState(gl.GL_VERTEX_ARRAY); // 时動 Client 陣列17繪製模式 為GL_VERTEX_ARRAY
gl.VertexPointer(3, gl.GL_FLOAT, 0, (IntPtr)trianglePointer); // 18設定指標陣列 trianglePointer
19 gl.EnableClientState(gl.GL_COLOR_ARRAY); // 时動 Client 陣列
繪製模式 為GL_COLOR_ARRAY
gl.ColorPointer(4, gl.GL_FLOAT, 0, (IntPtr)colorPointer); // 設定20指標陣列 colorPointer
21
22 // gl.DrawArrays(gl.GL_TRIANGLES, 0, 3); // 繪製三角形
gl.DrawArrays(gl.GL_LINE_LOOP, 0, 3); // 繪製連續線段(封閉連23續線段)
gl.DisableClientState(gl.GL_VERTEX_ARRAY); // 關閉 Client 陣24列繪製模式 GL_VERTEX_ARRAY
25
gl.DisableClientState(gl.GL_COLOR_ARRAY); // 關閉 Client 陣列繪製模式 GL_COLOR_ARRAY
26
gl.Flush(); // 立即
目前所有的繪圖指令輸出
27 }
28
29 myRotation += 2f;
30}
31
32// gluPerspective 透視投影
// fovy:可視角~範圍從0到33180度
34// aspect: 設定投影平面寬與高的比例 (double) w/h35// near: 投影近點~表示可視區域的最近距離
// far: 投影遠點~表示36可視區域的最遠距離
37void gluPerspective(float fovy, float aspect, float near, float far)
38{
39 float xmin, xmax, ymin, ymax;40
41 ymax = near * (float)Math.Tan(fovy * 3.1415962f / 360.0);42 ymin = -ymax;43 xmin = ymin * aspect;44 xmax = ymax * aspect;45
46 gl.Frustumf(xmin, xmax, ymin, ymax, near, far); // 透視投影函式47}
(3) 繪圖事件
以下程式碼為覆寫 OnPaint 事件~於並事件中進行圖形繪製
01// OnPaint 重繪事件
02protected override void OnPaint(PaintEventArgs e)03{
04 base.OnPaint(e);
05
06 DrawGLScene(); // 繪圖
egl.SwapBuffers(myDisplay, 07mySurface);
gl.Clear(gl.GL_COLOR_BUFFER_BIT | 08gl.GL_DEPTH_BUFFER_BIT); // 清顏除色緩衝區與深度緩衝區
09 Invalidate();
10
int tickCount = Environment.TickCount; // 取得系統时動後經過的毫秒11數
12 int nextFrame = (myLastFrame + 1) % myFrameTracker.Length;13 // elapsed: 多久重繪 30 Frame14 float elapsed = (tickCount - myFrameTracker[nextFrame]) / 1000f;15 float timePerFrame = elapsed / 30;
myFps = 1 / 16timePerFrame;
myLastFrame = 17nextFrame;
18 myFrameTracker[nextFrame] = tickCount;
19}
(4) 程式關閉時釋放資源
以下程式碼關為閉程式時~釋放 OpenGL ES 相關資源
01protected override void OnClosing(CancelEventArgs e)
02{
if (!egl.DestroySurface(myDisplay, 03mySurface))
04 throw new Exception("Error while destroying surface.");
if (!egl.DestroyContext(myDisplay, 05myContext))
06 throw new Exception("Error while destroying context.");
07 if (!egl.Terminate(myDisplay))08 throw new Exception("Error while terminating display.");
09 base.OnClosing(e);
10}
3. 程式碼
以下為完整程式碼
001using System;
002using System.Collections.Generic;003using System.ComponentModel;
004using System.Data;
005using System.Drawing;
using System.T006ext;
using System.Windows.F007orms;
008using System.Runtime.InteropServices;009
010using OpenGLES;
011
012namespace TestOpenGLES
013{
014 public partial class Form1 : Form
015 {
016 [DllImport("coredll")]017 extern static IntPtr GetDC(IntPtr hwnd);
018
019 EGLDisplay myDisplay; // 創建 EGLDisplay020 EGLSurface mySurface; // 創建 EGLSurface021 EGLContext myContext; // 創建 EGLContext022
023 public Form1()
024 {
025 InitializeComponent();026
// start ========== 027EGL 設定 ==========
myDisplay =
028egl.GetDisplay(new EGLNativeDisplayType(this)); // 獲取 Display
( EGLDisplay )
029
030 int major, minor;03 egl.Initialize(myDisplay, out major, out minor); // 初始化 1EGL
032
EGLConfig[] configs = new EGLConfig[10]; // 設定 033EGLConfig ( EGLConfig )
int[] attribList 034= new int[]
035 {
036 egl.EGL_RED_SIZE, 5,037 egl.EGL_GREEN_SIZE, 6,
egl.EGL_BLUE038_SIZE, 5,
egl.EGL_DEPTH_SIZ039E, 16 ,
040 egl.EGL_SURFACE_TYPE, egl.EGL_WINDOW_BIT,
041 egl.EGL_STENCIL_SIZE, egl.EGL_DONT_CARE,
egl.EGL_NONE, 042egl.EGL_NONE
043 };
044
045 int numConfig;
if (!egl.ChooseConfig(myDisplay, attribList, configs, 046configs.Length, out numConfig) || numConfig < 1)04 throw new InvalidOperationException("Unable to choose
7config.");
048
EGLConfig config = 049configs[0];
mySurface = egl.CreateWindowSurface(myDisplay, config, 050Handle, null); // 構造 Surface ( EGLSurface )
myContext = egl.CreateContext(myDisplay, config, 051EGLContext.None, null); // 創建 Context ( EGLContext )
egl.MakeCurrent(myDisplay, mySurface, mySurface, 052myContext); // 設定繪製環境 Render Context
053 // end ========== EGL 初始化 ==========054
055 gl.ClearColor(0, 0, 0, 0);
InitGL(); // 初始化 056OpenGL ES
057 }
058
059 int[] myFrameTracker = new int[30];
060 int myLastFrame = 0;
061 float myFps = 0;
062
063 // 初始化 OpenGL ES
void InitGL(064)
065 {
066 gl.ShadeModel(gl.GL_SMOOTH); // 設定陰影模式為平滑067 // gl.ClearColor(1.0f, 1.0f, 1.0f, 0.5f); // 白色背景068 gl.ClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
gl.ClearDepthf(1.0f); // 069設置深度緩衝
070 gl.Enable(gl.GL_DEPTH_TEST); // 使用深度測試
gl.BlendFunc(gl.GL_SRC_ALPHA,
071gl.GL_ONE_MINUS_SRC_ALPHA); // 設定混合函數~設定並為源因子
GL_SRC_ALPHA~目的因子為GL_ONE_MINUS_SRC_ALPHA
gl.DepthFunc(gl.GL_LEQUAL); // 所做的深度測試為 072GL_LEQUAL 深度小或相等的时候也渲染
073
gl.Hint(gl.GL_PERSPECTIVE_CORRECTION_HINT, gl.GL_NICEST); // 系統
測試進行修正
074
}
075
076 float myRotation = 0;077 unsafe void DrawGLScene()078 {
gl.Viewport(ClientRectangle.Left, ClientRectangle.Top, 079ClientRectangle.Width, ClientRectangle.Height); // 設定圖形要顯示的區域
gl.MatrixMode(gl.GL_PROJECTION); // 設定目前工作矩陣080為 Projection 矩陣
081
gl.LoadIdentity(); //
Projection 矩陣初始化
082
gluPerspective(45, (float)ClientSize.Width /
(float)ClientSize.Height, .1f, 100); // 設定圖形 gluPerspective 透視投影083
float[] triangle = new float[] { 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0840.0f, 1.0f, -1.0f, 0.0f };
float[] colors = new float[] { 1.0f, 0.0f, 0.0f, 9, 0.0f, 1.0f, 0850.0f, 0, 0.0f, 0.0f, 1.0f, 0 };086
gl.Translatef(0.0f, 0.0f, -6.0f); // 平移函式~表示 x,y,z 偏087移量
gl.Rotatef(myRotation, 0.0f, 1.0f, 0.0f); // 旋轉函式~參數088x,y,z代表一個向量~指旋轉所繞的軸~參數 myRotation 表示旋轉逆時針的
角度
089
fixed (float* trianglePointer = &triangle[0], colorPointer = 090&colors[0])
091 {
09 gl.EnableClientState(gl.GL_VERTEX_ARRAY); // 时動 2Client 陣列繪製模式 為GL_VERTEX_ARRAY
gl.VertexPointer(3, gl.GL_FLOAT, 0, 093(IntPtr)trianglePointer); // 設定指標陣列 trianglePointer09 gl.EnableClientState(gl.GL_COLOR_ARRAY); // 时動 4Client 陣列繪製模式 為GL_COLOR_ARRAY
gl.ColorPointer(4, gl.GL_FLOAT, 0, 095(IntPtr)colorPointer); // 設定指標陣列 colorPointer096
// gl.DrawArrays(gl.GL_TRIANGLES, 0, 3); // 繪製三097角形
gl.DrawArrays(gl.GL_LINE_LOOP, 0, 3); // 繪製連續線098段(封閉連續線段)
09 gl.DisableClientState(gl.GL_VERTEX_ARRAY); // 關閉 9Client 陣列繪製模式 GL_VERTEX_ARRAY
10 gl.DisableClientState(gl.GL_COLOR_ARRAY); // 關閉 0Client 陣列繪製模式 GL_COLOR_ARRAY
101
gl.Flush(); // 立即
目前所有的繪圖指令輸出
102
}
103
104 myRotation += 2f;
105 }
106
// gluPerspective 透107視投影
108 // fovy:可視角~範圍從0到180度
109 // aspect: 設定投影平面寬與高的比例 (double) w/h
// near: 投影近點~表示可視110區域的最近距離
// far: 投影遠點~表示可視區111域的最遠距離
11 void gluPerspective(float fovy, float aspect, float near, float far)2
113 {
114 float xmin, xmax, ymin, ymax;
115
116 ymax = near * (float)Math.Tan(fovy * 3.1415962f / 360.0);
ymin = 117-ymax;
118 xmin = ymin * aspect;119 xmax = ymax * aspect;120
gl.Frustumf(xmin, xmax, ymin, ymax, near, far); // 透視投121影函式
122 }
123
// OnPaintBackground 重繪背景事件~不可拿掉~拿掉後重繪時會124閃爍
12 protected override void OnPaintBackground(PaintEventArgs e)5
126 {
127 }
128
129 // OnPaint 重繪事件130 protected override void OnPaint(PaintEventArgs e)
131 {
132 base.OnPaint(e);133
134 DrawGLScene(); // 繪圖
egl.SwapBuffers(myDispla135y, mySurface);
gl.Clear(gl.GL_COLOR_BUFFER_BIT | 136gl.GL_DEPTH_BUFFER_BIT); // 清顏除色緩衝區與深度緩衝區137 Invalidate();138
int tickCount = Environment.TickCount; // 取得系統时動後經139過的毫秒數
int nextFrame = (myLastFrame + 1) % 140myFrameTracker.Length;
// elapsed: 多久重繪 30 141Frame
float elapsed = (tickCount - myFrameTracker[nextFrame]) / 1421000f;
143 float timePerFrame = elapsed / 30;144 myFps = 1 /
timePerFrame;
myLastFrame = 145nextFrame;
146 myFrameTracker[nextFrame] = tickCount;
147 }
148
149 protected override void OnClosing(CancelEventArgs e)150 {
151 if (!egl.DestroySurface(myDisplay, mySurface))152 throw new Exception("Error while destroying surface.");153 if (!egl.DestroyContext(myDisplay, myContext))154 throw new Exception("Error while destroying context.");
if (!155egl.Terminate(myDisplay))
156 throw new Exception("Error while terminating display.");
157 base.OnClosing(e);
158 }
159
160 // 離開
161 private void myExitMenuItem_Click(object sender, EventArgs e)
162 {
163 Close();
164 }
165 }
166}
4. 執行結果
(1) 使用 gl.DrawArrays(gl.GL_TRIANGLES, 0, 3); // 繪製三角形
(2)
GL_VERTEX_ARRAY 部分註解
(3) 使用 gl.DrawArrays(gl.GL_LINE_LOOP, 0, 3); // 繪製連續線段(封閉連續線段)
(4)
GL_VERTEX_ARRAY 部分註解
(5)
背景設定為白色 gl.ClearColor(1.0f, 1.0f, 1.0f, 0.5f); // 白色背景
5. 參考
.NET Compact Framework wrapper for OpenGL ES
OpenGL ES 系列之基本 -0: 了解 OpenGL ES 社區
OpenGL ES 系列之基本 -1: 初始化 EGL
OpenGL 基礎圖形編程 - 總目錄