最近项目中有用到sharpgl相关内容,发现网上相关资料较少,希望能对大家有所帮助
下面首先介绍着色器的使用,在红宝书(第七版)15章中,有相关介绍。我们可以编写相应着色应用程序,从而使gpu调用我们自己写的顶点着色和片段着色器。
下面测试程序中,shaderhelper为编写的顶点着色器和片段着色器代码。其中顶点着色器接收位置、颜色、法线信息、位置偏移、灯光方向信息。
注意事项:
1、红宝书中15.9节中,介绍到GSGL 1.3版本内置了众多全局变量,可以很方便供我们使用,但是这些变量再高版本GSGL如330或430中无法使用。
如果想继续使用,可将改为兼容模式,即可使用。或者自行计算相关矩阵或向量
#version 430 compatibility
2、着色器代码的编译很容易产生问题,所以错误信息的输出尤为重要。
3、SharpGL类库中也提供了相应的顶点着色器类
ShaderBuilder为编译着色器代码类。主要完成着色器代码的编译链接生成
using SharpGL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MultiSurveyLib
{
public class ShaderHelper
{
/// <summary>
/// 顶点着色器代码
/// </summary>
public static string VertexShaderSource =
"#version 430 compatibility\n" +
"uniform vec4 offset;\n" +
"uniform vec3 lightDir;\n" +
"layout(location=0) in vec3 position;\n" +
"layout(location=1) in vec3 color;\n" +
"layout(location=2) in vec3 normal;\n" +
"out vec4 colorOut;\n" +
"void main()\n" +
"{\n" +
"vec4 pos = vec4(position,1) - offset;" +
"gl_Position = gl_ModelViewProjectionMatrix * pos;\n" +
"vec3 N = normalize(gl_NormalMatrix * normal);" +
"vec4 V = gl_ModelViewMatrix * pos;" +
"float diffuse = max(0.0, dot(N, lightDir));" +
"colorOut = diffuse*vec4(color,1) * vec4(0.75,0.75,0.75,1);" +
"}\n";
/// <summary>
/// 片段着色器代码
/// </summary>
public static string FragmentShaderSource =
"#version 430 compatibility\n" +
"in vec4 colorOut;\n" +
"out vec4 color1;\n" +
"void main()\n" +
"{" +
"color1 = colorOut;" +
"}\n";
}
public class ShaderBuilder
{
private uint program = 0;
private uint vertexShader = 0;
private uint fragmentShader = 0;
public ShaderBuilder()
{
}
public uint BuildProgram(OpenGL gl, string vertexShaderSource = null, string fragmentShaderSource = null)
{
if (vertexShaderSource == null && fragmentShaderSource == null)
{
vertexShader = gl.CreateShader(OpenGL.GL_VERTEX_SHADER);
gl.ShaderSource(vertexShader, ShaderHelper.VertexShaderSource);
gl.CompileShader(vertexShader);
string compileInfo = GetShaderCompilorStatus(gl, vertexShader);
fragmentShader = gl.CreateShader(OpenGL.GL_FRAGMENT_SHADER);
gl.ShaderSource(fragmentShader, ShaderHelper.FragmentShaderSource);
gl.CompileShader(fragmentShader);
GetShaderCompilorStatus(gl, fragmentShader);
program = gl.CreateProgram();
gl.AttachShader(program, vertexShader);
gl.AttachShader(program, fragmentShader);
gl.LinkProgram(program);
GetProgramLinkedInfoLog(gl, program);
gl.ValidateProgram(program);
}
return program;
}
/// <summary>
/// 查看GLSL程序着色器编译信息
/// </summary>
/// <param name="gl"></param>
/// <param name="shader">片段着色器或顶点着色器</param>
/// <returns></returns>
private string GetShaderCompilorStatus(OpenGL gl, uint shader)
{
int[] status = { -1 };
gl.GetShader(shader, OpenGL.GL_COMPILE_STATUS, status);
if (status[0] == 0)
{
StringBuilder sb = new StringBuilder(100);
gl.GetShaderInfoLog(shader, 500, IntPtr.Zero, sb);
Console.WriteLine(sb);
return sb.ToString();
}
else
return "";
}
/// <summary>
/// 获取GLSL程序链接信息
/// </summary>
/// <param name="gl"></param>
/// <param name="program"></param>
/// <returns></returns>
private string GetProgramLinkedInfoLog(OpenGL gl, uint program)
{
int[] status = { -1 };
gl.GetProgram(program, OpenGL.GL_LINK_STATUS, status);
if (status[0] == 0)
{
StringBuilder sb = new StringBuilder(100);
gl.GetProgramInfoLog(program, 500, IntPtr.Zero, sb);
Console.WriteLine(sb.ToString());
return sb.ToString();
}
else
return "";
}
public void Dispose(OpenGL gl)
{
if (program != 0)
{
gl.DeleteShader(vertexShader);
gl.DeleteShader(fragmentShader);
gl.DeleteProgram(program);
}
}
}
}
下面为上面的测试程序
ShaderBuilder sb = new ShaderBuilder();//初始化着色器
uint program = sb.BuildProgram(gl);//gl为自己创建的OpenGL对象
初始化一次即可。
下面为绘制代码
int offsetLocation = -1;
if (Win32.wglGetCurrentContext().ToInt32() != 0)
{
gl.UseProgram(program);
offsetLocation = gl.GetUniformLocation(program, "offset");
int lightindex = gl.GetUniformLocation(program, "lightDir");
if (lightindex != -1)
{
glRedrawGrid.Uniform3(lightindex, 1, new float[] { 1, 1, 1 });//设置平行光源方向
}
}
else
{
Console.WriteLine("context error "+ " "+gl.GetErrorCode());
}
//设置偏移位置,主要针对于大坐标频繁计算,此次传入偏移坐标即可
gl.Uniform4(offsetLocation, 1, new float[] { ofx, ofy, 0, 0 });//ofx ofy为偏移坐标
modelObj.Draw(gl);//vao方式绘制数据
}