之前我们已经提及了如何在空间中绘制三条线段,使它们相互组合看起来像是一个三角形。这里我们来画一个真正意义上的三角形。

  1. 创建主程序中的类
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;

namespace OpenTK_Tutorials
{
public static class Program
{
private static void Main()
{
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
Title = "Draw Triangle",
};

using (var game = new Game(GameWindowSettings.Default, nativeWindowSettings))
{
game.Run();
}
}
}
}
  1. 构建主程序中调用的​​GUI​​窗口界面的类
using OpenTK_Tutorials.Common;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTK.Windowing.Desktop;

namespace OpenTK_Tutorials
{
public class Game : GameWindow
{
private readonly float[] _vertices =
{
-0.5f, -0.5f, 0.0f, // 左下角端点
0.5f, -0.5f, 0.0f, // 右下角端点
0.0f, 0.5f, 0.0f // 顶部端点
};

private int _vertexBufferObject;

private int _vertexArrayObject;

private Shader _shader;

public Game(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
: base(gameWindowSettings, nativeWindowSettings)
{
}

protected override void OnLoad()
{
GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);

_vertexBufferObject = GL.GenBuffer();

GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);

GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);

_vertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(_vertexArrayObject);

GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0);

GL.EnableVertexAttribArray(0);

_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");

_shader.Use();

base.OnLoad();
}

protected override void OnRenderFrame(FrameEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit);

_shader.Use();

GL.BindVertexArray(_vertexArrayObject);

// 注意此时我们选择渲染图元的类型为PrimitiveType.Triangles,这样绘图才会完成对三角形的填充效果
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

SwapBuffers();

base.OnRenderFrame(e);
}

protected override void OnUpdateFrame(FrameEventArgs e)
{
var input = KeyboardState;

if (input.IsKeyDown(Keys.Escape))
{
Close();
}

base.OnUpdateFrame(e);
}

protected override void OnResize(ResizeEventArgs e)
{
GL.Viewport(0, 0, Size.X, Size.Y);
base.OnResize(e);
}

protected override void OnUnload()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindVertexArray(0);
GL.UseProgram(0);

GL.DeleteBuffer(_vertexBufferObject);
GL.DeleteVertexArray(_vertexArrayObject);

GL.DeleteProgram(_shader.Handle);
base.OnUnload();
}
}
}
  1. 着色器类
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;

namespace OpenTK_Tutorials.Common
{
public class Shader
{
public readonly int Handle;

private readonly Dictionary<string, int> _uniformLocations;

public Shader(string vertPath, string fragPath)
{
var shaderSource = File.ReadAllText(vertPath);

var vertexShader = GL.CreateShader(ShaderType.VertexShader);

GL.ShaderSource(vertexShader, shaderSource);

CompileShader(vertexShader);

shaderSource = File.ReadAllText(fragPath);
var fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragmentShader, shaderSource);
CompileShader(fragmentShader);

Handle = GL.CreateProgram();

GL.AttachShader(Handle, vertexShader);
GL.AttachShader(Handle, fragmentShader);

LinkProgram(Handle);

GL.DetachShader(Handle, vertexShader);
GL.DetachShader(Handle, fragmentShader);
GL.DeleteShader(fragmentShader);
GL.DeleteShader(vertexShader);

GL.GetProgram(Handle, GetProgramParameterName.ActiveUniforms, out var numberOfUniforms);

_uniformLocations = new Dictionary<string, int>();

for (var i = 0; i < numberOfUniforms; i++)
{
var key = GL.GetActiveUniform(Handle, i, out _, out _);

var location = GL.GetUniformLocation(Handle, key);

_uniformLocations.Add(key, location);
}
}

private static void CompileShader(int shader)
{
GL.CompileShader(shader);

GL.GetShader(shader, ShaderParameter.CompileStatus, out var code);
if (code != (int)All.True)
{
var infoLog = GL.GetShaderInfoLog(shader);
throw new Exception($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}");
}
}

private static void LinkProgram(int program)
{
GL.LinkProgram(program);

GL.GetProgram(program, GetProgramParameterName.LinkStatus, out var code);
if (code != (int)All.True)
{
throw new Exception($"Error occurred whilst linking Program({program})");
}
}

public void Use()
{
GL.UseProgram(Handle);
}

public int GetAttribLocation(string attribName)
{
return GL.GetAttribLocation(Handle, attribName);
}

public void SetInt(string name, int data)
{
GL.UseProgram(Handle);
GL.Uniform1(_uniformLocations[name], data);
}

public void SetFloat(string name, float data)
{
GL.UseProgram(Handle);
GL.Uniform1(_uniformLocations[name], data);
}

public void SetMatrix4(string name, Matrix4 data)
{
GL.UseProgram(Handle);
GL.UniformMatrix4(_uniformLocations[name], true, ref data);
}

public void SetVector3(string name, Vector3 data)
{
GL.UseProgram(Handle);
GL.Uniform3(_uniformLocations[name], data);
}
}
}
  1. 端点着色器
#version 330 core

layout(location = 0) in vec3 aPosition;

void main(void)
{
gl_Position = vec4(aPosition, 1.0);
}
  1. 片段着色器
#version 330

out vec4 outputColor;

void main()
{
outputColor = vec4(1.0, 1.0, 0.0, 1.0);
}

对比之前的文章,端点着色器以及片段着色器中的内容没有变化。

运行程序可以得到下面的结果:

OpenTK---空间中三角形的绘制_着色器


码字不易,如果大家觉得有用,请高抬贵手给一个赞让我上推荐让更多的人看到吧~