I've been trying to implement GLSL into my program, however given that i have never used GLSL before, i decided I would try following a tutorial. Unfortunately following tutorials aren't my forte, and I am stuck here with my program crashing when 'RenderTerrain()' is called (in the second line of code of the function (GL.DrawElements))
Now this obviously all the code in the program, there is A LOT more, there's no chance any of you would go through 20k lines to find my problem :P But if you need to ask questions about any of it, please comment :)
So my question simply is, is there anything wrong with this code? Why would it be crashing?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK.Graphics.OpenGL;
using OpenTK;
namespace HoardOfUpgrades
{
public class Shaders
{
private static string TerrainVertexShaderText = #"
#version 140
// object space to camera space transformation
uniform mat4 modelview_matrix;
// camera space to clip coordinates
uniform mat4 projection_matrix;
// incoming vertex position
in vec3 vertex_position;
// incoming vertex normal
in vec3 vertex_normal;
// incoming vertex_color
in vec3 vertex_color
// transformed vertex normal
out vec3 normal;
void main(void)
{
//not a proper transformation if modelview_matrix involves non-uniform scaling
normal = ( modelview_matrix * vec4( vertex_normal, 0 ) ).xyz;
// transforming the incoming vertex position
gl_Position = projection_matrix * modelview_matrix * vec4( vertex_position, 1 );
}
";
private static string TerrainFragmentShaderText = #"
#version 140
precision highp float;
const vec3 ambient = vec3( 0.1, 0.1, 0.1 );
const vec3 lightVecNormalized = normalize( vec3( 0.5, 0.5, 2 ) );
const vec3 lightColor = vec3( 1.0, 0.8, 0.2 );
in vec3 normal;
out vec4 out_frag_color;
void main(void)
{
float diffuse = clamp( dot( lightVecNormalized, normalize( normal ) ), 0.0, 1.0 );
out_frag_color = vec4( ambient + diffuse * lightColor, 1.0 );
}
";
public static int TerrainFragmentShaderHandle, TerrainVertexShaderHandle, TerrainProgramHandle, ProjectionMatrixLocation, ModelviewMatrixLocation, TerrainNormHandle, TerrainPosHandle, TerrainColorHandle, TerrainIndicesHandle, TerrainIndiceCount;
public static void Load(Vector3[] position, Vector3[] normals, Vector3[] colors, int[] indices)
{
LoadShaders();
LoadProgram();
LoadVertexPositions(position);
LoadVertexNormals(normals);
LoadVertexColors(colors);
LoadIndexer(indices);
}
static void LoadProgram()
{
TerrainProgramHandle = GL.CreateProgram();
GL.AttachShader(TerrainProgramHandle, TerrainVertexShaderHandle);
GL.AttachShader(TerrainProgramHandle, TerrainVertexShaderHandle);
GL.LinkProgram(TerrainProgramHandle);
}
static void LoadShaders()
{
TerrainVertexShaderHandle = GL.CreateShader( ShaderType.VertexShader );
TerrainFragmentShaderHandle = GL.CreateShader( ShaderType.FragmentShader );
GL.ShaderSource(TerrainVertexShaderHandle, TerrainVertexShaderText);
GL.ShaderSource(TerrainFragmentShaderHandle, TerrainFragmentShaderText);
GL.CompileShader(TerrainVertexShaderHandle);
GL.CompileShader(TerrainFragmentShaderHandle);
}
private static void QueryMatrixLocations()
{
ProjectionMatrixLocation = GL.GetUniformLocation(TerrainProgramHandle, "projection_matrix");
ModelviewMatrixLocation = GL.GetUniformLocation(TerrainProgramHandle, "modelview_matrix");
}
public static void SetModelviewMatrix(Matrix4 matrix)
{
GL.UniformMatrix4(ModelviewMatrixLocation, false, ref matrix);
}
public static void SetProjectionMatrix(Matrix4 matrix)
{
GL.UniformMatrix4(ProjectionMatrixLocation, false, ref matrix);
}
private static void LoadVertexPositions(Vector3[] data)
{
GL.GenBuffers(1, out TerrainPosHandle);
GL.BindBuffer(BufferTarget.ArrayBuffer, TerrainPosHandle);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
new IntPtr(data.Length * Vector3.SizeInBytes),
data, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.BindAttribLocation(TerrainProgramHandle, 0, "vertex_position");
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);
}
private static void LoadVertexNormals(Vector3[] data)
{
GL.GenBuffers(1, out TerrainNormHandle);
GL.BindBuffer(BufferTarget.ArrayBuffer, TerrainNormHandle);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
new IntPtr(data.Length * Vector3.SizeInBytes),
data, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(1);
GL.BindAttribLocation(TerrainProgramHandle, 1, "vertex_normal");
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);
}
private static void LoadVertexColors(Vector3[] data)
{
GL.GenBuffers(1, out TerrainColorHandle);
GL.BindBuffer(BufferTarget.ArrayBuffer, TerrainColorHandle);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
new IntPtr(data.Length * Vector3.SizeInBytes),
data, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(1);
GL.BindAttribLocation(TerrainProgramHandle, 1, "vertex_color");
GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);
}
private static void LoadIndexer(int[] data)
{
TerrainIndiceCount = data.Length;
GL.GenBuffers(1, out TerrainIndicesHandle);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, TerrainIndicesHandle);
GL.BufferData<int>(BufferTarget.ElementArrayBuffer,
new IntPtr(data.Length * sizeof(int)),
data, BufferUsageHint.StaticDraw);
}
public static void RenderTerrain()
{
GL.UseProgram(TerrainProgramHandle);
GL.DrawElements(BeginMode.Triangles, TerrainIndiceCount,
DrawElementsType.UnsignedInt, IntPtr.Zero);
GL.UseProgram(0);
}
}
}
These lines of code must be included:
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
Arrays were enabled, they must be disabled to use the GL.DrawElements() function
Related
I'm using OpenTK's GLFW wrapper and OpenGL wrapper. I've run it with both x86 and x64 builds just in case. Installed nuget packages are OpenTK.Graphics and OpenTK.Windowing.GraphicsLibraryFramework and whatever dependencies Visual Studio installs with them.
When I run the code a window opens but is unresponsive. The window crashes a few seconds after opening. OpenGL outputs no debug information to the console nor does C#.
If I comment out GL.DrawElements the window doesn't crash and will properly clear to a black screen and respond to input, but nothing draws to the screen.
This issue persists whether I set the profile to OpenGlProfile.Core or OpenGlProfile.Compat.
GL.DrawArrays does work (in comapat only).
Code
using Engine2D;
namespace Sandbox;
public static class Program
{
public static void Main()
{
var app = new Application();
app.Run();
}
}
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTK.Graphics.OpenGL;
namespace Engine2D;
public unsafe sealed class Application
{
private readonly Window* _window;
private static readonly float[] _vertices =
{
-0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f
};
private static readonly int[] _indices =
{
0, 1, 2,
3, 0, 2
};
public Application()
{
GLFW.Init();
GLFW.WindowHint(WindowHintOpenGlProfile.OpenGlProfile, OpenGlProfile.Core);
GLFW.WindowHint(WindowHintInt.ContextVersionMajor, 4);
GLFW.WindowHint(WindowHintInt.ContextVersionMinor, 3);
_window = GLFW.CreateWindow(1200, 800, "Engine2D", null, null);
GLFW.MakeContextCurrent(_window);
GL.LoadBindings(new GLFWBindingsContext());
GL.Enable(EnableCap.DebugOutput);
GL.DebugMessageCallback((source, type, id, severity, length, message, userParam) =>
{
if (severity != DebugSeverity.DebugSeverityMedium || severity != DebugSeverity.DebugSeverityHigh)
{
return;
}
string msg = System.Text.Encoding.Default.GetString((byte*)message.ToPointer(), length);
Console.WriteLine(msg);
}, IntPtr.Zero);
}
public void Run()
{
var vao = GL.GenVertexArray();
GL.BindVertexArray(vao);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(float) * 2, 0);
var vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * _vertices.Length, _vertices, BufferUsageHint.StaticDraw);
var ibo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * _indices.Length, _indices, BufferUsageHint.StaticDraw);
var vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, File.ReadAllText(#"C:\Dev\Engine2D\Sandbox\Standard.vert"));
GL.CompileShader(vertShader);
GL.GetShaderInfoLog(vertShader, out var info);
if (!string.IsNullOrWhiteSpace(info))
{
Console.WriteLine(info);
Console.Read();
}
var fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, File.ReadAllText(#"C:\Dev\Engine2D\Sandbox\Standard.frag"));
GL.CompileShader(fragShader);
GL.GetShaderInfoLog(fragShader, out info);
if (!string.IsNullOrWhiteSpace(info))
{
Console.WriteLine(info);
Console.Read();
}
var program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
GL.ValidateProgram(program);
GL.GetProgramInfoLog(program, out info);
if (!string.IsNullOrWhiteSpace(info))
{
Console.WriteLine(info);
Console.Read();
}
GL.DeleteShader(vertShader);
GL.DeleteShader(fragShader);
while (!GLFW.WindowShouldClose(_window))
{
if (GLFW.GetKey(_window, Keys.Escape) == InputAction.Press)
{
GLFW.SetWindowShouldClose(_window, true);
}
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.BindVertexArray(vao);
GL.UseProgram(program);
GL.DrawElements(PrimitiveType.Triangles, _indices.Length, DrawElementsType.UnsignedInt, 0);
GLFW.SwapBuffers(_window);
GLFW.PollEvents();
}
GLFW.Terminate();
GL.DeleteVertexArray(vao);
GL.DeleteBuffer(vbo);
GL.DeleteBuffer(ibo);
GL.DeleteProgram(program);
}
}
Shaders
#version 330 core
layout (location = 0) in vec2 aPos;
void main()
{
gl_Position = vec4(aPos, 0.0, 1.0);
}
#version 330 core
out vec4 oColor;
void main()
{
oColor = vec4(1.0, 1.0, 0.0, 1.0);
}
I've been stuck on this for 2 days now. Some help, even a lead, would be greatly appreciated.
Edit
I needed to set the vertex attributes after generating the buffers. For some reason I thought the order didn't matter.
You invoked VertexAttribPointer before creating buffers.
From the document,
If pointer is not NULL, a non-zero named buffer object must be bound to the GL_ARRAY_BUFFER target
Just change the order.
GL.BindVertexArray(vao);
var vbo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * _vertices.Length, _vertices, BufferUsageHint.StaticDraw);
var ibo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo);
GL.BufferData(BufferTarget.ElementArrayBuffer, sizeof(int) * _indices.Length, _indices, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(float) * 2, 0);
I am writing a program in WPF, using SharpGL, to draw some cubes. In my software, a large number of cubes need to be drawn. Initially, I used the immediate mode rendering method, which makes the app too slow. After that I use the VAO method, the app speed improved a lot. The only problem is that all the cubes are drawn in white. I think the problem is the Shader part. Please help me fix this problem.
private void openGLControl_OpenGLInitialized(object sender, SharpGL.WPF.OpenGLRoutedEventArgs args)
{
OpenGL gL = openGLControl.OpenGL;
gL.Enable(OpenGL.GL_DEPTH_TEST);
gL.ClearColor(0, 0, 0, 0);
gL.MatrixMode(OpenGL.GL_PROJECTION);
gL.LoadIdentity();
myShader = new MyShader(gL);
}
public void SetUpCamera(OpenGL gL)
{
gL.Viewport(0, 0, (int)openGLControl.ActualWidth, (int)openGLControl.ActualHeight);
gL.MatrixMode(OpenGL.GL_PROJECTION);
gL.LoadIdentity();
gL.Perspective(45.0, openGLControl.ActualWidth / openGLControl.ActualHeight, 0.1, 10000.0);
gL.LookAt(0.0, 0.0, 0.1,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
}
private void openGLControl_OpenGLDraw(object sender, SharpGL.WPF.OpenGLRoutedEventArgs args)
{
if (Camera.IsDrawSkip)
{
return;
}
Camera.IsDrawSkip = true;
OpenGL gL = openGLControl.OpenGL;
gL.ClearColor(Colors.DarkGray.ScR, Colors.DarkGray.ScG , Colors.DarkGray.ScB, 0);
gL.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
SetUpCamera(gL);
gL.MatrixMode(OpenGL.GL_MODELVIEW);
gL.LoadIdentity();
gL.Translate(Camera.XTransition, Camera.YTransition, Camera.Zoom);
gL.Rotate(Camera.XRotationAngle, 1, 0, 0);
gL.Rotate(Camera.YRotationAngle, 0, 1, 0);
myShader.Bind();
if (Camera.DrawState == DrawState.Draw)
{
drawObjects(gL);
}
VBOManager.Render(gL);
myShader.Unbind();
gL.EnableVertexAttribArray(1);
gL.Flush();
}
private void drawObjects(OpenGL gL)
{
if(int.TryParse(txtCount.Text, out int count))
{
VBOManager.Vertices.Clear();
int index = cbxShape.SelectedIndex;
if (index == 0)
{
for (int z = 0; z < count; z++)
{
for (int y = 0; y < count; y++)
{
for (int x = 0; x < count; x++)
{
VBOManager.AddCubeValues(x * 5, y * 5, z * 5, Colors.OrangeRed);
}
}
}
}
VBOManager.GenerateGeometry(gL);
}
}
public class MyShader
{
public MyShader(OpenGL gl)
{
gL = gl;
init();
}
#region Property
public OpenGL gL { get; set; }
public uint shader_id;
public uint shader_vp;
public uint shader_fp;
#endregion
public void init()
{
shader_vp = gL.CreateShader(OpenGL.GL_VERTEX_SHADER);
shader_fp = gL.CreateShader(OpenGL.GL_FRAGMENT_SHADER);
gL.ShaderSource(shader_vp, Shader_VERTEX_Text());
gL.ShaderSource(shader_fp, Shader_FRAGMENT_Text());
gL.CompileShader(shader_vp);
gL.CompileShader(shader_fp);
shader_id = gL.CreateProgram();
gL.AttachShader(shader_id, shader_fp);
gL.AttachShader(shader_id, shader_vp);
gL.LinkProgram(shader_id);
gL.BindAttribLocation(shader_id, 0, "in_Position"); // Bind a constant attribute location for positions of vertices
gL.BindAttribLocation(shader_id, 1, "in_Color"); // Bind another constant attribute location, this time for color
}
public void Bind()
{
gL.UseProgram(shader_id);
}
public void Unbind()
{
gL.UseProgram(0);
}
private string Shader_FRAGMENT_Text()
{
return #"#version 150 core
in vec3 pass_Color;
out vec4 out_Color;
void main(void)
{
out_Color = vec4(pass_Color, 1.0);
}";
}
private string Shader_VERTEX_Text()
{
return #"##version 150 core
in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
void main(void)
{
gl_Position = vec4(in_Position, 1.0);
pass_Color = in_Color;
}";
}
}
public static class VBOManager
{
private static VertexBufferArray m_vertexBuffer = new VertexBufferArray();
public static List<float> Vertices = new List<float>();
public static List<float> Colores = new List<float>();
public static void GenerateGeometry(SharpGL.OpenGL gl)
{
m_vertexBuffer.Create(gl);
m_vertexBuffer.Bind(gl);
GenerateVertexBuffer(gl);
GenerateColourBuffer(gl);
m_vertexBuffer.Unbind(gl);
}
private static void GenerateColourBuffer(SharpGL.OpenGL gl)
{
var vertexDataBuffer = new VertexBuffer();
vertexDataBuffer.Create(gl);
vertexDataBuffer.Bind(gl);
vertexDataBuffer.SetData(gl, 1, Colores.ToArray(), false, 3);
}
private static void GenerateVertexBuffer(SharpGL.OpenGL gl)
{
var vertexDataBuffer = new VertexBuffer();
vertexDataBuffer.Create(gl);
vertexDataBuffer.Bind(gl);
vertexDataBuffer.SetData(gl, 0, Vertices.ToArray(), true, 3);
}
public static void Render(SharpGL.OpenGL gl)
{
m_vertexBuffer.Bind(gl);
gl.DrawArrays(SharpGL.OpenGL.GL_QUADS, 0, Vertices.Count);
m_vertexBuffer.Unbind(gl);
}
#region Cube Part
public static List<VertexV2> Vertexs;
public static void GenerateVertex()
{
float value = 2 / 2.0f;
Vertexs = new List<VertexV2>();
Vertexs.Add(new VertexV2(-value, value, value)); //V1
Vertexs.Add(new VertexV2(value, value, value)); //V2
Vertexs.Add(new VertexV2(value, -value, value)); //V3
Vertexs.Add(new VertexV2(-value, -value, value)); //V4
Vertexs.Add(new VertexV2(-value, value, -value)); //V5
Vertexs.Add(new VertexV2(value, value, -value)); //V6
Vertexs.Add(new VertexV2(value, -value, -value)); //V7
Vertexs.Add(new VertexV2(-value, -value, -value)); //V8
}
public static void AddVertex(int i, float x_Trans, float y_Trans, float z_Trans, Color color)
{
Vertices.Add(Vertexs[i].X + x_Trans);
Vertices.Add(Vertexs[i].Y + y_Trans);
Vertices.Add(Vertexs[i].Z + z_Trans);
Colores.Add(color.ScR);
Colores.Add(color.ScG);
Colores.Add(color.ScB);
}
public static void AddCubeValues(float x_Trans, float y_Trans, float z_Trans, Color color)
{
AddVertex(0, x_Trans,y_Trans,z_Trans, color); //V1
AddVertex(1, x_Trans,y_Trans,z_Trans, color); //V2
AddVertex(2, x_Trans,y_Trans,z_Trans, color); //V3
AddVertex(3, x_Trans, y_Trans, z_Trans, color); //V4
AddVertex(4, x_Trans,y_Trans,z_Trans, color); //V5
AddVertex(5, x_Trans,y_Trans,z_Trans, color); //V6
AddVertex(6, x_Trans,y_Trans,z_Trans, color); //V7
AddVertex(7, x_Trans,y_Trans,z_Trans, color); //V8
AddVertex(0, x_Trans,y_Trans,z_Trans, color); //V1
AddVertex(3, x_Trans,y_Trans,z_Trans, color); //V4
AddVertex(7, x_Trans,y_Trans,z_Trans, color); //V5
AddVertex(4, x_Trans,y_Trans,z_Trans, color); //V8
AddVertex(0, x_Trans,y_Trans,z_Trans, color); //V1
AddVertex(1, x_Trans,y_Trans,z_Trans, color); //V4
AddVertex(5, x_Trans,y_Trans,z_Trans, color); //V5
AddVertex(4, x_Trans,y_Trans,z_Trans, color); //V8
AddVertex(1, x_Trans,y_Trans,z_Trans, color); //V1
AddVertex(2, x_Trans,y_Trans,z_Trans, color); //V4
AddVertex(6, x_Trans,y_Trans,z_Trans, color); //V5
AddVertex(5, x_Trans,y_Trans,z_Trans, color); //V8
AddVertex(2, x_Trans,y_Trans,z_Trans, color); //V3
AddVertex(3, x_Trans,y_Trans,z_Trans, color); //V4
AddVertex(7, x_Trans,y_Trans,z_Trans, color); //V8
AddVertex(6, x_Trans, y_Trans, z_Trans, color); //V7
}
}
This is.. disastrous. Almost completely hopelessly so. But I'll give a shot at explaining some of the problems (it's impossible to detail all the problems with your code, there's so incredibly many).
Stop using the fixed pipeline, your random glMatrixMode and whatnot calls do literally nothing. Set up uniforms in your shaders and pass the projection and world (and view) transform matrices, then use them to transform your vertices.
You have a random glEnableVertexAttribArray in your render function, why? Set up your vertex buffer once and set it up correctly.
When you initialize OpenGL, request a specific version and a specific context type. There's no reason why you wouldn't set it as a 4.6 core context, but who knows what you have?
Detach and delete compiled shaders from your program, you're leaking memory. And for god's sake, check your error codes, because:
Your vertex shader has an invalid #version pre-processor instruction at the beginning, you wrote ##version. Check your error messages! And use a modern OpenGL version context, like #version 460 core.
glUseProgram(0) is undefined behaviour. Just write correct code instead and use DSA to not pollute your OpenGL state machine.
Your vertex buffer is completely wrong, you initialize it twice and set up once the position argument and once the color argument, and at the end your vertex buffer only knows about the color argument. Set it up correctly. What are those two lists doing? Data in OpenGL buffers is laid out interleaved, not in different buffers or one after the other or whatever else you imagine is happening here.
Don't use GL_QUADS, triangulate your data correctly, set up an index buffer and use GL_TRIANGLES.
Everything related to creating the cube vertices, just delete it. You do not understand how cubes work or how lists work (you randomly re-initialize your Vertexs every call, and by the way it's spelled vertexes or vertices), or again how OpenGL buffers work.
Lastly, instantiating an OpenGL context in a Win32 island in a WPF app is extremely inefficient. Both OpenGL and D3d (which is what WPF uses) provide functions to interop with eachother. Hook into WPF's D3D context and render directly into it. And don't use SharpGL, use a modern, portable (.Net5) OpenGL binding library, like OpenTK.
I want to rotate an image which is shown in my GLControl to 10 degree. For that I have rotated the bitmap using c# code and passed this rotated bitmap to opengl shader code. But the resulted image is seems like the rotated part is hiding/cut like below. Shall I need to do any changes on it's view port while rotating? or is it good to rotate the image in shader code itself?
public void DrawImage(int image, int glcontrolWidth, int glcontrolHeight,Matrix4 **transformMatrix**)
{
GL.Viewport(new Rectangle(0, 0, glcontrolWidth, glcontrolHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);
RunShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
}
public void RunShaders()
{
GL.UseProgram(program);
**GL.UniformMatrix4(transformLocation, false, ref transformMatrix);**
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
ErrorCode ec = GL.GetError();
if (ec != 0)
System.Console.WriteLine(ec.ToString());
Console.Read();
}
public void Init()
{
CreateShaders();
CreateProgram();
InitBuffers();
}
public void CreateProgram()
{
program = GL.CreateProgram();
GL.AttachShader(program, vertShader);
GL.AttachShader(program, fragShader);
GL.LinkProgram(program);
}
public void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
**transformLocation = GL.GetUniformLocation(program, "u_transform");**
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
public void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
**uniform mat4 u_transform;**
void main() {
vTexCoord = (a_position.xy+1)/2 ;
**gl_Position = u_transform * vec4(a_position, 1);**
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture_2;varying vec2 vTexCoord;
void main ()
{
vec4 color = texture2D (sTexture_2, vec2(vTexCoord.x, vTexCoord.y));
gl_FragColor =color;
}"); GL.CompileShader(fragShader);
}
Do not rotate the image, but rotate and scale the vertex coordinates.
Add a transformation matrix to the vertex shader:
attribute vec3 a_position;
varying vec2 vTexCoord;
uniform mat4 u_transform;
void main()
{
vTexCoord = (a_position.xy+1)/2;
gl_Position = u_transform * vec4(a_position, 1);
}
Get the location of the transformation matrix uniform (``u_transform´) (after the program is linked).
int transformLocation = GL.GetUniformLocation(program, "u_transform");
Compute the scale dependent on the angle:
double diagonal = Math.Sqrt(bmp.Width * bmp.Width + bmp.Height * bmp.Height);
double dia_angle1 = Math.Atan2(bmp.Height, bmp.Width) + angle * Math.PI / 180;
double dia_angle2 = Math.Atan2(bmp.Height, -bmp.Width) + angle * Math.PI / 180;
double rot_w = Math.Max(Math.Abs(diagonal * Math.Cos(dia_angle1)), Math.Abs(diagonal * Math.Cos(dia_angle2)));
double rot_h = Math.Max(Math.Abs(diagonal * Math.Sin(dia_angle1)), Math.Abs(diagonal * Math.Sin(dia_angle2)));
double scale = Math.Min(bmp.Width / rot_w, bmp.Height / rot_h);
Define a transformation matrix that scales and rotates the image taking into account the aspect ratio:
Matrix4 transformMatrix =
Matrix4.CreateScale((float)scale) *
Matrix4.CreateScale(this.Width, this.Height, 1.0f) *
Matrix4.CreateRotationZ((float)(angle * Math.PI / 180)) *
Matrix4.CreateScale(1.0f / this.Width, 1.0f / this.Height, 1.0f);
Set the matrix uniform, after the program is installed (after GL.UseProgram):
GL.UniformMatrix4(transformLocation, false, ref transformMatrix);
I am trying to understand and apply modern OpenGL matrix transformations. I already read a lot of different sources but I am not sure what I am actually doing wrong.
The issue I have is also commented in the code: If I set the eye coordinates of the Matrix4.LookAt to a z value that is greater or equal 0 or lower -2 the triangle is not visible anymore.
Can someone explain why? As far as I understood the method the triangle should just be visible just from the other side (explicitly disabling face culling does not change anything).
Another thing is strange: if i rotate the triangle it seems to get clipped if I use eye-z = -2; if I use -1 it looks "smoother". Any ideas?
Here is the complete program:
using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL4;
namespace OGL420_Matrices
{
// OpenTK version 3.1.0
internal class Program
{
public static void Main(string[] args)
{
var program = new Program();
program.Run();
}
private GameWindow _gameWindow;
private Matrix4 _projectionMatrix;
private Matrix4 _viewMatrix;
private Matrix4 _viewProjectionMatrix;
private Matrix4 _modelMatrix;
private int _vbaId, _programId, _viewProjectionUniformId, _modelMatrixUniformId;
private void Run()
{
// 4, 2 is OpenGL 4.2
using (_gameWindow = new GameWindow(800, 600, GraphicsMode.Default, "", GameWindowFlags.Default,
DisplayDevice.Default, 4, 2, GraphicsContextFlags.Default))
{
_gameWindow.Load += OnLoad;
_gameWindow.Resize += OnResize;
_gameWindow.RenderFrame += OnRenderFrame;
_gameWindow.Run();
}
}
private void OnResize(object sender, EventArgs e)
{
var clientArea = _gameWindow.ClientRectangle;
GL.Viewport(0, 0, clientArea.Width, clientArea.Height);
}
private void OnLoad(object sender, EventArgs e)
{
_projectionMatrix = Matrix4.CreateOrthographic(3, 3, 0.001f, 50);
// change -1 to -2.1f you dont see anything
// change -1 to -2f you still see the same
// change -1 to >= 0 you dont see anything; of course 0 doesn't make sense but 1 would
_viewMatrix = Matrix4.LookAt(
new Vector3(0, 0, -1f), // eye
new Vector3(0, 0, 0), // target
new Vector3(0, 1, 0)); // up
_modelMatrix = Matrix4.Identity;
var data = new float[]
{
0, 0, 0,
1, 0, 0,
0, 1, 0
};
var vboId = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vboId);
GL.BufferData(BufferTarget.ArrayBuffer, data.Length * sizeof(float), data, BufferUsageHint.StaticDraw);
_vbaId = GL.GenVertexArray();
GL.BindVertexArray(_vbaId);
GL.BindBuffer(BufferTarget.ArrayBuffer, vboId);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
var vertexShaderId = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertexShaderId, #"#version 420
layout(location = 0) in vec3 position;
uniform mat4 viewProjection;
uniform mat4 model;
out vec3 outColor;
void main()
{
gl_Position = viewProjection * model * vec4(position, 1);
outColor = vec3(1,1,1);
}");
GL.CompileShader(vertexShaderId);
GL.GetShader(vertexShaderId, ShaderParameter.CompileStatus, out var result);
if (result != 1)
throw new Exception("compilation error: " + GL.GetShaderInfoLog(vertexShaderId));
var fragShaderId = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShaderId, #"#version 420
in vec3 outColor;
out vec4 fragmentColor;
void main()
{
fragmentColor = vec4(outColor, 1);
}");
GL.CompileShader(fragShaderId);
GL.GetShader(fragShaderId, ShaderParameter.CompileStatus, out result);
if (result != 1)
throw new Exception("compilation error: " + GL.GetShaderInfoLog(fragShaderId));
_programId = GL.CreateProgram();
GL.AttachShader(_programId, vertexShaderId);
GL.AttachShader(_programId, fragShaderId);
GL.LinkProgram(_programId);
GL.GetProgram(_programId, GetProgramParameterName.LinkStatus, out var linkStatus);
if (linkStatus != 1) // 1 for true
throw new Exception("Shader program compilation error: " + GL.GetProgramInfoLog(_programId));
GL.DeleteShader(vertexShaderId);
GL.DeleteShader(fragShaderId);
_viewProjectionUniformId = GL.GetUniformLocation(_programId, "viewProjection");
_modelMatrixUniformId = GL.GetUniformLocation(_programId, "model");
}
private void OnRenderFrame(object sender, FrameEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit);
_viewProjectionMatrix = _projectionMatrix * _viewMatrix;
GL.UniformMatrix4(_viewProjectionUniformId, false, ref _viewProjectionMatrix);
GL.UniformMatrix4(_modelMatrixUniformId, false, ref _modelMatrix);
GL.UseProgram(_programId);
GL.BindVertexArray(_vbaId);
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
_gameWindow.SwapBuffers();
}
}
}
First I'll quote a comment to the OpenTK issue: Problem with matrices #687:
Because of how matrices are treated in C# and OpenTK, multiplication order is inverted from what you might expect in C/C++ and GLSL. This is an old artefact in the library, and it's too late to change now, unfortunately.
In compare to glsl, where column major order matrices have to be multiplied form the right to the left, where the right matrix is the matrix which is applied "first", in OpenTK the matrices have to be multiplied from the left to the right.
This means, if you want to calculate the viewProjectionMatrix in glsl, which does the view transformation followed by the projection, then in glsl it is (for column major order matrices):
mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;
If you want to do the same in in OpenTK, by the use of Matrix4, then you've to do:
_viewProjectionMatrix = _viewMatrix * _projectionMatrix;
I am trying to draw VAO from separate VBO. My goal is to get different colors for each vertex of my geometry. But with my code it still all red.
I think my error is this code fragment. Please, help me to find it. (I have skipped program and matrices set ups)
Set up
vao = new int[1];
buffers = new int[2];
GL.GenVertexArrays(1, vao);
GL.GenBuffers(2, buffers);
GL.BindVertexArray(vao[0]);
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
unsafe
{
fixed (void* verts = quad_strip3)
{
var prt = new IntPtr(verts);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(quad_strip3.Length * sizeof(float)), prt,
BufferUsageHint.StaticDraw);
}
}
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, new IntPtr(0));
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[1]);
var r = new Random();
var colors = new float[quad_strip3.Length];
for (int i = 0; i < colors.Length; i++)
{
colors[i] = (float)r.NextDouble();
}
unsafe
{
fixed (void* verts = colors)
{
var prt = new IntPtr(verts);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(colors.Length * sizeof(float)), prt,
BufferUsageHint.StaticDraw);
}
}
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 0, new IntPtr(0));
Draw code
GL.BindVertexArray(vao[0]);
GL.DrawArrays(PrimitiveType.QuadStrip, 0, 26);
Vertex shader
#version 150 core
in vec3 in_Position;
in vec3 in_color;
out vec3 pass_Color;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
pass_Color = in_color;
}
Fragment shader
#version 150 core
in vec3 pass_Color;
out vec4 out_Color;
void main(void) {
out_Color = vec4(pass_Color, 1.0);
}
Khm... the solution was really simple. I just have missed to EnableVertexAttribArray for colors.
I insert
GL.EnableVertexAttribArray(1);
Before
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[1]);
And everything gets worked.