本文基础: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); } } }