本文基础:C#+OpenGL3编程之第一个三角形
教程原文地址:http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
本教程从这里开始,越来越不适合初学者阅读了。。。我也没法,不知道老外是怎么想的。
原Lib BUG有这么几个:
glCreateProgram 没有返回值,不知道老外怎么用啊。
更要命的是,做文字处理时候没有考虑.net string是Unicode问题,直接就转。。。太无语了。
我都在注释里面说了,怎么修改上面两个问题,哎。。。
我的解决方案不是十全十美的,比如不支持X64,这个问题留给大家自己思考吧。
首先我还是再次说明下,为了简化我们的教程,我使用了C# 类继承,把我们主要目标放在教程的范围内容。
谁也不希望一个特性却要去几百行代码里面找吧。
using System;
using System.Diagnostics;
using System.Windows.Forms;
using OpenGLDotNet;
namespace OpenGLTK
{
/// <summary>
///C# by 大师♂罗莊
/// 把C移植到C#,并不是那么简单,从这里开始后......
/// </summary>
class OpenGL3tutorial2shade : OpenGL3tutorial2
{
OpenGL3LoadShaders shade = new OpenGL3LoadShaders();
public OpenGL3tutorial2shade()
: base()
{
// 有的显卡支持在线编译,可能有的显卡只支持二进制格式的shader,检测显卡是否支持在线编译调用函数glGetBooleanv(GL_SHADER_COMPILER),如果支持在线编译shader就可以使用函数glShaderSource来指定shader
bool[] supportSHADER_COMPILER=new bool[1];
GL.GetBooleanv(GL.GL_SHADER_COMPILER,supportSHADER_COMPILER);
if(supportSHADER_COMPILER[0]==false)
{
MessageBox.Show("您的显卡不支持编译Shade");
}
shade.LoadShadersinapplication("SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader");
Debug.WriteLine( "shade.FragmentShaderErrorMessageString");
Debug.WriteLine( shade.FragmentShaderErrorMessageString);
Debug.WriteLine( "shade.getVertexShaderErrorMessageString");
Debug.WriteLine(shade.getVertexShaderErrorMessageString);
Debug.WriteLine(shade.ProgramErrorMessageString);
//ERROR: 0:1: '#version' : syntax error
//首先值得一提的是,OpenGL 3.0/3.1/3.2所附带的GLSL标准版本号分别为1.30/1.40/1.50,而如今直接蹦到了3.3/4.0,目的是为了保持和OpenGL的一致性,方便开发人员区分和使用,显著增强图形质量、加速性能、提升编程弹性。
}
public override void Dispose()
{
shade.Dispose();
base.Dispose();
}
public override void DrawGLScene()
{
shade.useshade();
base.DrawGLScene();
}
}
}
/*
* Created by SharpDevelop.
* User: luozhuang
* Date: 2014/12/31
* Time: 13:38
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using OpenGLDotNet;
using System.IO;
namespace OpenGLTK
{
/// <summary>
/// LoadShader加载类by 大师♂罗莊
/// </summary>
public class OpenGL3LoadShaders:IDisposable
{
#region IDisposable implementation
public void Dispose()
{
GL.DeleteProgram(programID);
}
#endregion
public OpenGL3LoadShaders()
{
}
public uint LoadShadersinapplication(String vertex_file_path, String fragment_file_path)
{
return LoadShaders(Path.Combine(Application.StartupPath, @"shade\" + vertex_file_path).ToString(), Path.Combine(Application.StartupPath, @"shade\" + fragment_file_path).ToString());
}
byte[] VertexShaderErrorMessage, FragmentShaderErrorMessage, ProgramErrorMessage;
uint ProgramID;
public string getVertexShaderErrorMessageString {
get {
if (VertexShaderErrorMessage == null || VertexShaderErrorMessage.Length < 1) {
return string.Empty;
}
return Encoding.UTF8.GetString(VertexShaderErrorMessage);
}
}
public string FragmentShaderErrorMessageString {
get {
if (FragmentShaderErrorMessage == null || FragmentShaderErrorMessage.Length < 1) {
return string.Empty;
}
return Encoding.UTF8.GetString(FragmentShaderErrorMessage);
}
}
public string ProgramErrorMessageString {
get {
if (ProgramErrorMessage == null || ProgramErrorMessage.Length < 1) {
return string.Empty;
}
return Encoding.UTF8.GetString(ProgramErrorMessage);
}
}
public uint LoadShaders(String vertex_file_path, String fragment_file_path)
{
// Create the shaders
//需要修改源代码
// GLAPI GLuint APIENTRY glCreateProgram (void);
// [UnmanagedFunctionPointer(CallingConvention.StdCall)]
// private delegate GLuint TglCreateProgram();
// private static TglCreateProgram glCreateProgram = null;
// // GLAPI GLuint APIENTRY glCreateShader (GLenum type);
// [UnmanagedFunctionPointer(CallingConvention.StdCall)]
// private delegate GLuint TglCreateShader(GLenum type);
// private static TglCreateShader glCreateShader = null;
//原代码没有返回值,不知道以后咋用啊。。
uint VertexShaderID = GL.CreateShader(GL.GL_VERTEX_SHADER);
uint FragmentShaderID = GL.CreateShader(GL.GL_FRAGMENT_SHADER);
// 读取 Vertex Shader文件
//文本编码根据Shader文件决定,不会的自己用EmEditor这些工具查看编码
string[] VertexShaderCode = new string[]{ File.ReadAllText(vertex_file_path, Encoding.ASCII) };
// 读取Fragment Shader文件
string[] FragmentShaderCode = new string[]{ File.ReadAllText(fragment_file_path, Encoding.ASCII) };
int[] Result = new int[1];
int[] InfoLoGLength = new int[1];
//ERROR: 0:1: '' : syntax error: #version is mandatory and should be set before any other token
//.net字符串都是unicode,可是OpenGL都是Ascii,需要转换。
/// GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length)
/// /// MARSHALING FUNCTIONS.net字符串都是unicode,可是OpenGL都是Ascii,需要转换。
///原方法用String转char* 是不行的。
/// GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length)
/// /// MARSHALING FUNCTIONS.net字符串都是unicode,可是OpenGL都是Ascii,需要转换。
///原方法用String转char* 是不行的。
/// 修改过支持ASCII文字by 大师♂罗莊
// public unsafe static void ShaderSourceASCII(GLuint shader, GLsizei count, string[] strings, GLint[] length)
// {
// if (glShaderSource != null) {
// IntPtr strptrtable = BuildStringIntPtrTableASCII(strings);
//
// fixed (GLint* ptr_length = length) {
// glShaderSource(shader, count, (GLchar**)strptrtable, ptr_length);
// }
//
// Marshal.FreeHGlobal(strptrtable);
// }
// }
// ///
//
// ///
// // MARSHALING FUNCTIONS
// ///
// /// 修改过支持ASCII文字by 大师♂罗莊
// private unsafe static IntPtr BuildStringIntPtrTableASCII(string[] strings)
// {
// IntPtr StrPtrTable = IntPtr.Zero;
//
// if (strings != null) {
// StrPtrTable = Marshal.AllocHGlobal(strings.Length * 4);
//
// for (int counter = 0; counter < strings.Length; counter++) {
// //定义是public struct System.Byte GLchar
// GLchar[] code = System.Text.Encoding.UTF8.GetBytes(strings[counter]);
// if (code == null || code.Length < 1) {
// continue;
// }
// fixed (GLchar* StrPtr =&code[0]) {
// IntPtr StrIntPtr = (IntPtr)StrPtr;
// Marshal.WriteInt32(StrPtrTable, counter * 4, StrIntPtr.ToInt32());
// }
// }
// }
//
// return StrPtrTable;
// }
int[] Stringlength = new int[VertexShaderCode.Length];
for (int counter = 0; counter < Stringlength.Length; counter++) {
Stringlength[counter] = VertexShaderCode[counter].Length;
}
// 编译 Vertex Shader
//这里大家要多看SDK文档,因为ShaderSource 最后一个参数传null意思是自动按照null算字符长度,我们需要传多个字符,需要指定长度
GL.ShaderSourceASCII(VertexShaderID, 1, VertexShaderCode, Stringlength);
GL.CompileShader(VertexShaderID);
//(0) : error C0206: invalid token "<null atom>" in version line
//如果提示这个错误,请用下面代码检查一下你传入的代码
//检查传入的代码对不对,只是作为教程时候使用,我自己加的
int buffersize = 2048;//这个根据你写的shade文件大小决定,教程也就1KB不到
//真搞不懂,为什么GetShaderSource用byte[],而ShaderSource用GLchar**....
byte[] returnstring = new byte[buffersize];
GL.GetShaderSource(VertexShaderID, buffersize, Stringlength, returnstring);
string CheckString = System.Text.UTF8Encoding.UTF8.GetString(returnstring);
// 检查 Vertex Shader
GL.GetShaderiv(VertexShaderID, GL.GL_COMPILE_STATUS, Result);
GL.GetShaderiv(VertexShaderID, GL.GL_INFO_LOG_LENGTH, InfoLoGLength);
VertexShaderErrorMessage = new byte[InfoLoGLength[0]];
GL.GetShaderInfoLog(VertexShaderID, InfoLoGLength[0], null, VertexShaderErrorMessage);
Stringlength = new int[FragmentShaderCode.Length];
for (int counter = 0; counter < Stringlength.Length; counter++) {
Stringlength[counter] = FragmentShaderCode[counter].Length;
}
// 编译 Fragment Shader
GL.ShaderSourceASCII(FragmentShaderID, 1, FragmentShaderCode, Stringlength);
GL.CompileShader(FragmentShaderID);
// 检查 Fragment Shader
GL.GetShaderiv(FragmentShaderID, GL.GL_COMPILE_STATUS, Result);
GL.GetShaderiv(FragmentShaderID, GL.GL_INFO_LOG_LENGTH, InfoLoGLength);
FragmentShaderErrorMessage = new byte[InfoLoGLength[0]];
GL.GetShaderInfoLog(FragmentShaderID, InfoLoGLength[0], null, FragmentShaderErrorMessage);
// 链接到 program
ProgramID = GL.CreateProgram();
GL.AttachShader(ProgramID, VertexShaderID);
GL.AttachShader(ProgramID, FragmentShaderID);
GL.LinkProgram(ProgramID);
// 检查 program
GL.GetProgramiv(ProgramID, GL.GL_LINK_STATUS, Result);
GL.GetProgramiv(ProgramID, GL.GL_INFO_LOG_LENGTH, InfoLoGLength);
ProgramErrorMessage = new byte[InfoLoGLength[0]];
GL.GetProgramInfoLog(ProgramID, InfoLoGLength[0], null, ProgramErrorMessage);
GL.DeleteShader(VertexShaderID);
GL.DeleteShader(FragmentShaderID);
return ProgramID;
}
private static string[] ReadAllLines(string path, Encoding encoding)
{
List<string> list = new List<string>();
using (StreamReader streamReader = new StreamReader(path, encoding)) {
string item;
while ((item = streamReader.ReadLine()) != null) {
if (String.IsNullOrEmpty(item)) {
continue;
}
list.Add(item);
}
}
return list.ToArray();
}
public void useshade()
{
GL.UseProgram(ProgramID);
}
}
}
我的机器结果:
Intel HD 4000 显示一个红色的三角形
GT 650m 显示一个红色的三角形
Vmware SVGA 3D 无法显示