This question is based on the Giawa tutorials on OpenGL. I have completed tut6 & tut9 separately, but now I want to combine the two. I.e. I want that cube spinning while a bunch of stars is floating around. However, I'm pretty new two OpenGL but it looks like they use different types of shaders. So I wrote two shaders, but now when I try to run it my cube is transparent and the stars does not display. Is it possible to display both on screen at the same time correctly? Below is my code.
using System;
using Tao.FreeGlut;
using OpenGL;
using System.Windows;
using System.Windows.Forms;
using System.Collections.Generic;
namespace OpenGLTutorial6
{
class Program
{
private static int width = 1280, height = 720;
private static ShaderProgram program, program_2;
private static VBO<Vector3> cube, top_pyramid, bottom_pyramid, cubeNormals, bottom_pyramidNormals, top_pyramidNormals, star;
private static VBO<Vector2> cubeUV, top_pyramidUV, bottom_pyramidUV, starUV;
private static VBO<int> cubeQuads, top_pyramidTrianlges, bottom_pyramidTrianlges, starQuads;
private static bool fullscreen = false;
private static bool left, right, up, down;
private static List<Star> stars = new List<Star>();
private static Random generator = new Random(Environment.TickCount);
private static float theta = (float)Math.PI / 2, phi = (float)Math.PI / 2;
private static Texture crateTexture,
brickTexture,
cracked_glassTexture,
desert_surfaceTexture,
numbersTexture,
ziggyTexture,
starTexture;
private static System.Diagnostics.Stopwatch watch;
private static float angle;
private static int rotate = 1;
private static bool lighting = true;
private class Star
{
public float angle;
public float dist;
public Vector3 color;
public Star(float Angle, float Distance, Vector3 Color)
{
this.angle = Angle;
this.dist = Distance;
this.color = Color;
}
}
static void Main(string[] args)
{
// create an OpenGL window
Glut.glutInit();
Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
Glut.glutInitWindowSize(width, height);
Glut.glutCreateWindow("SCREENSAVER");
// provide the Glut callbacks that are necessary for running this tutorial
Glut.glutIdleFunc(OnRenderFrame);
//Glut.glutIdleFunc(OnRenderFrame_2);
Glut.glutDisplayFunc(OnDisplay);
//<<<<<<<<<<<<< KEYBOARD FUNCTIONS
Glut.glutSpecialFunc(new Glut.SpecialCallback(OnKeyPress));
Glut.glutKeyboardFunc(OnKeyboardDown);
Glut.glutKeyboardUpFunc(OnKeyboardUp);
//<<<<<<<<<<<<< DISPOSE
Glut.glutCloseFunc(OnClose);
// enable depth testing to ensure correct z-ordering of our fragments
Gl.Enable(EnableCap.DepthTest);
Gl.Disable(EnableCap.DepthTest);
Gl.Enable(EnableCap.Blend);
Gl.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);
//<<<<<<<<<<< COMPILE SHADER PROGRAMS
program = new ShaderProgram(VertexShader, FragmentShader);
program_2 = new ShaderProgram(VertexShader_2, FragmentShader_2);
//set the view and projection matrix, which are static throughout this tutorial
program.Use();
program["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
program["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 10), Vector3.Zero, Vector3.Up));
program["light_direction"].SetValue(new Vector3(1, 1, 1));
program["enable_lighting"].SetValue(lighting);
program_2.Use();
program_2["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
program_2["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 20), Vector3.Zero, Vector3.Up));
//<<<<<<<<< LOAD TEXTURES
crateTexture = new Texture("crate.jpg");
brickTexture = new Texture("bricks.jpg");
cracked_glassTexture = new Texture("crack.jpg");
desert_surfaceTexture = new Texture("desert.jpg");
numbersTexture = new Texture("numbers.jpg");
ziggyTexture = new Texture("ziggy.jpg");
starTexture = new Texture("star.bmp");
// each star is simply a quad
star = new VBO<Vector3>(new Vector3[] { new Vector3(-1, -1, 0), new Vector3(1, -1, 0), new Vector3(1, 1, 0), new Vector3(-1, 1, 0) });
starUV = new VBO<Vector2>(new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) });
starQuads = new VBO<int>(new int[] { 0, 1, 2, 3 }, BufferTarget.ElementArrayBuffer);
// create 50 stars for this tutorial
int numStars = 50;
for (int i = 0; i < numStars; i++)
{
stars.Add(new Star(0, (float)i / numStars * 4f, new Vector3(generator.NextDouble(), generator.NextDouble(), generator.NextDouble())));
}
// create a crate with vertices and UV coordinates
cube = new VBO<Vector3>(new Vector3[]
{
new Vector3(-1.5, 0, -0.5), new Vector3(-0.5, 1, -0.5), new Vector3(-0.5, 1, 0.5), new Vector3(-1.5, 0, 0.5),
new Vector3(-0.5, 1, -0.5), new Vector3(0.5, 1, -0.5), new Vector3(0.5, 1, 0.5), new Vector3(-0.5, 1, 0.5),
new Vector3(0.5, 1, -0.5), new Vector3(1.5, 0, -0.5), new Vector3(1.5, 0, 0.5), new Vector3(0.5, 1, 0.5),
new Vector3(1.5, 0, -0.5), new Vector3(1.5, 0, 0.5), new Vector3(0.5, -1, 0.5), new Vector3(0.5, -1, -0.5),
new Vector3(0.5, -1, 0.5), new Vector3(0.5, -1, -0.5), new Vector3(-0.5, -1, -0.5), new Vector3(-0.5, -1, 0.5),
new Vector3(-0.5, -1, -0.5), new Vector3(-0.5, -1, 0.5), new Vector3(-1.5, 0, 0.5), new Vector3(-1.5, 0, -0.5)
});
cubeUV = new VBO<Vector2>(new Vector2[] {
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) });
top_pyramid = new VBO<Vector3>(new Vector3[]
{
new Vector3(-1.5, 0, -0.5), new Vector3(-0.5, 1, -0.5), new Vector3(0, 0, -1.5),
new Vector3(-0.5, 1, -0.5), new Vector3(0.5, 1, -0.5), new Vector3(0, 0, -1.5),
new Vector3(0.5, 1, -0.5), new Vector3(1.5, 0, -0.5), new Vector3(0, 0, -1.5),
new Vector3(1.5, 0, -0.5), new Vector3(0.5, -1, -0.5), new Vector3(0, 0, -1.5),
new Vector3(0.5, -1, -0.5), new Vector3(-0.5, -1, -0.5), new Vector3(0, 0, -1.5),
new Vector3(-0.5, -1, -0.5), new Vector3(-1.5, 0, -0.5), new Vector3(0, 0, -1.5)
});
top_pyramidUV = new VBO<Vector2>(new Vector2[] {
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1)});
bottom_pyramid = new VBO<Vector3>(new Vector3[]
{
new Vector3(-1.5, 0, 0.5), new Vector3(-0.5, 1, 0.5), new Vector3(0, 0, 1.5),
new Vector3(-0.5, 1, 0.5), new Vector3(0.5, 1, 0.5), new Vector3(0, 0, 1.5),
new Vector3(0.5, 1, 0.5), new Vector3(1.5, 0, 0.5), new Vector3(0, 0, 1.5),
new Vector3(1.5, 0, 0.5), new Vector3(0.5, -1, 0.5), new Vector3(0, 0, 1.5),
new Vector3(0.5, -1, 0.5), new Vector3(-0.5, -1, 0.5), new Vector3(0, 0, 1.5),
new Vector3(-0.5, -1, 0.5), new Vector3(-1.5, 0, 0.5), new Vector3(0, 0, 1.5)
});
bottom_pyramidUV = new VBO<Vector2>(new Vector2[] {
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1)});
cubeNormals = new VBO<Vector3>(new Vector3[] {
new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0),
new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0),
new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1),
new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0),
new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0)
});
top_pyramidNormals = new VBO<Vector3>(new Vector3[]{
new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0),
new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0),
new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1),
new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0),
new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0)
});
bottom_pyramidNormals = new VBO<Vector3>(new Vector3[]{
new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0),
new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0),
new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1),
new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0),
new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0)
});
cubeQuads = new VBO<int>(new int[] { 0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23 }, BufferTarget.ElementArrayBuffer);
top_pyramidTrianlges = new VBO<int>(new int[] {
0,1,2,
3,4,5,
6,7,8,
9,10,11,
12,13,14,
15,16,17}, BufferTarget.ElementArrayBuffer);
bottom_pyramidTrianlges = new VBO<int>(new int[] {
0,1,2,
3,4,5,
6,7,8,
9,10,11,
12,13,14,
15,16,17}, BufferTarget.ElementArrayBuffer);
watch = System.Diagnostics.Stopwatch.StartNew();
Gl.BindTexture(desert_surfaceTexture);
Glut.glutMainLoop();
}
private static void OnClose()
{
// dispose of all of the resources that were created
//must still update
cube.Dispose();
cubeUV.Dispose();
top_pyramid.Dispose();
top_pyramidTrianlges.Dispose();
cubeQuads.Dispose();
crateTexture.Dispose();
program.DisposeChildren = true;
program.Dispose();
}
private static void OnDisplay()
{
}
private static void OnRenderFrame()
{
// calculate how much time has elapsed since the last frame
watch.Stop();
float deltaTime = (float)watch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency;
watch.Restart();
// use the deltaTime to adjust the angle of the cube
angle += deltaTime;
// set up the OpenGL viewport and clear both the color and depth bits
Gl.Viewport(0, 0, width, height);
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// use our shader program and bind the crate texture
Gl.UseProgram(program);
//<<<<<<<<<<<< TOP PYRAMID
// set the transformation of the top_pyramid
program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle * rotate));
program["enable_lighting"].SetValue(lighting);
// bind the vertex positions, UV coordinates and element array
Gl.BindBufferToShaderAttribute(top_pyramid, program, "vertexPosition");
Gl.BindBufferToShaderAttribute(top_pyramidNormals, program, "vertexNormal");
Gl.BindBufferToShaderAttribute(top_pyramidUV, program, "vertexUV");
Gl.BindBuffer(top_pyramidTrianlges);
// draw the textured top_pyramid
Gl.DrawElements(BeginMode.Triangles, top_pyramidTrianlges.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
//<<<<<<<<<< CUBE
// set the transformation of the cube
program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle *rotate));
program["enable_lighting"].SetValue(lighting);
// bind the vertex positions, UV coordinates and element array
Gl.BindBufferToShaderAttribute(cube, program, "vertexPosition");
Gl.BindBufferToShaderAttribute(cubeNormals, program, "vertexNormal");
Gl.BindBufferToShaderAttribute(cubeUV, program, "vertexUV");
Gl.BindBuffer(cubeQuads);
// draw the textured cube
Gl.DrawElements(BeginMode.Quads, cubeQuads.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
//<<<<<<<<<<<< BOTTOM PYRAMID
// set the transformation of the bottom_pyramid
program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle * rotate));
program["enable_lighting"].SetValue(lighting);
// bind the vertex positions, UV coordinates and element array
Gl.BindBufferToShaderAttribute(bottom_pyramid, program, "vertexPosition");
Gl.BindBufferToShaderAttribute(bottom_pyramidNormals, program, "vertexNormal");
Gl.BindBufferToShaderAttribute(bottom_pyramidUV, program, "vertexUV");
Gl.BindBuffer(bottom_pyramidTrianlges);
// draw the textured bottom_pyramid
Gl.DrawElements(BeginMode.Triangles, bottom_pyramidTrianlges.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
Glut.glutSwapBuffers();
}
private static void OnRenderFrame_2()
{
watch.Stop();
float deltaTime = (float)watch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency;
watch.Restart();
// perform rotation of the scene depending on keyboard input
if (right) phi += deltaTime;
if (left) phi -= deltaTime;
if (up) theta += deltaTime;
if (down) theta -= deltaTime;
if (theta < 0) theta += (float)Math.PI * 2;
// set up the OpenGL viewport and clear both the color and depth bits
Gl.Viewport(0, 0, width, height);
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
//<<<<<<<<< STARS
// make sure the shader program and texture are being used
Gl.UseProgram(program_2);
Gl.BindTexture(starTexture);
// calculate the camera position using some fancy polar co-ordinates
Vector3 position = 20 * new Vector3(Math.Cos(phi) * Math.Sin(theta), Math.Cos(theta), Math.Sin(phi) * Math.Sin(theta));
Vector3 upVector = ((theta % (Math.PI * 2)) > Math.PI) ? Vector3.Up : Vector3.Down;
program_2["view_matrix"].SetValue(Matrix4.LookAt(position, Vector3.Zero, upVector));
// loop through the stars, drawing each one
for (int i = 0; i < stars.Count; i++)
{
// set the position and color of this star
program_2["model_matrix"].SetValue(Matrix4.CreateTranslation(new Vector3(stars[i].dist, 0, 0)) * Matrix4.CreateRotationZ(stars[i].angle));
program_2["color"].SetValue(stars[i].color);
Gl.BindBufferToShaderAttribute(star, program_2, "vertexPosition");
Gl.BindBufferToShaderAttribute(starUV, program_2, "vertexUV");
Gl.BindBuffer(starQuads);
Gl.DrawElements(BeginMode.Quads, starQuads.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);
// update the position of the star
stars[i].angle += (float)i / stars.Count * deltaTime * 2;
stars[i].dist -= 0.2f * deltaTime;
// if we've reached the center then move this star outwards and give it a new color
if (stars[i].dist < 0f)
{
stars[i].dist += 5f;
stars[i].color = new Vector3(generator.NextDouble(), generator.NextDouble(), generator.NextDouble());
}
}
Glut.glutSwapBuffers();
}
public static void OnKeyPress(int theKey, int x, int y)
{
switch (theKey)
{
//<<<<<<< ROTATE
case Glut.GLUT_KEY_F5:
{
rotate += 1;
Console.WriteLine("Hallo!");
}
break;
case Glut.GLUT_KEY_F6:
{
rotate -= 1;
}
break;
//<<<<<<<<<< TEXTURES
case Glut.GLUT_KEY_F7:
{
Gl.BindTexture(cracked_glassTexture);
}
break;
case Glut.GLUT_KEY_F8:
{
Gl.BindTexture(desert_surfaceTexture);
}
break;
case Glut.GLUT_KEY_F9:
{
Gl.BindTexture(brickTexture);
}
break;
case Glut.GLUT_KEY_F10:
{
Gl.BindTexture(ziggyTexture);
}
break;
case Glut.GLUT_KEY_F11:
{
Gl.BindTexture(numbersTexture);
}
break;
}
Glut.glutPostRedisplay();
}
private static void OnKeyboardDown(byte key, int x, int y)
{
if (key == 'w') up = true;
else if (key == 's') down = true;
else if (key == 'd') right = true;
else if (key == 'a') left = true;
else if (key == 27) Glut.glutLeaveMainLoop();
}
private static void OnKeyboardUp(byte key, int x, int y)
{
if (key == 'w') up = false;
else if (key == 's') down = false;
else if (key == 'd') right = false;
else if (key == 'a') left = false;
else if (key == 'f')
{
fullscreen = !fullscreen;
if (fullscreen) Glut.glutFullScreen();
else
{
Glut.glutPositionWindow(0, 0);
Glut.glutReshapeWindow(1280, 720);
}
}
}
public static string VertexShader = #"
#version 130
in vec3 vertexPosition;
in vec3 vertexNormal;
in vec2 vertexUV;
out vec3 normal;
out vec2 uv;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(void)
{
normal = normalize((model_matrix * vec4(floor(vertexNormal), 0)).xyz);
uv = vertexUV;
gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";
public static string FragmentShader = #"
#version 130
uniform sampler2D texture;
uniform vec3 light_direction;
uniform bool enable_lighting;
in vec3 normal;
in vec2 uv;
out vec4 fragment;
void main(void)
{
float diffuse = max(dot(normal, light_direction), 0);
float ambient = 0.2;
float lighting = (enable_lighting ? max(diffuse, ambient) : 1);
fragment = lighting * texture2D(texture, uv);
}
";
public static string VertexShader_2 = #"
#version 130
in vec3 vertexPosition;
in vec2 vertexUV;
out vec2 uv;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(void)
{
uv = vertexUV;
gl_Position = projection_matrix * (view_matrix * model_matrix * vec4(0, 0, 0, 1) + vec4(vertexPosition.x, vertexPosition.y, vertexPosition.z, 0));
//gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";
public static string FragmentShader_2 = #"
#version 130
uniform sampler2D texture;
uniform vec3 color;
in vec2 uv;
out vec4 fragment;
void main(void)
{
fragment = vec4(color * texture2D(texture, uv).xyz, 1);
}
";
}
}
Also I've added some other textures that is not in the original tutorials
From scanning through your code, it looks like you have most of what you need. To render both items at the same time, you basically have to add the rendering code that you currently have in OnRenderFrame_2() to OnRenderFrame(). Make sure that you only have one glClear() at the start, and one glutSwapBuffers() at the end.
If the outline of your code currently looks like this:
OnRenderFrame
prepare rendering of Item 1
glViewport
glClear
glUseProgram(program1)
render Item 1
glutSwapBuffers
OnRenderFrame_2
prepare rendering of Item 2
glViewport
glClear
glUseProgram(program2)
render Item 2
glutSwapBuffers
Rearrange it like this:
OnRenderFrame
prepare rendering of Item 1
prepare rendering of Item 2
glViewport
glClear
glUseProgram(program1)
render Item 1
glUseProgram(program2)
render Item 2
glutSwapBuffers
Lately I have been trying to learn/use OpenGL 3+. I have looked through tutorials and examples but I've run into a wall trying to get textures and 2D projection to work without problems.
The goal for now is to have a function which can draw a textured quad to the screen with it's position specified by pixels (not [-1,1]).
For readability and testing I made a new barebones program with the knowledge I currently have, and it exhibits nearly the same problems. Help would be appreciated since i'm starting to go bald over this :(..
The current code shows a garbled texture instead of the image itself (texture is 128x128px).
[Program.cs]
namespace OpenGLTester
{
static class Program
{
public static GameWindow window;
public static String programDirectory = Directory.GetCurrentDirectory();
public static int testTexture;
public static int uniform_fragment_texture;
public static int shaderProgram;
[STAThread]
static void Main()
{
window = new GameWindow(1024, 768, new GraphicsMode(new ColorFormat(8, 8, 8, 8), 0, 8), "OpenGLTester", GameWindowFlags.Default, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Default);
GL.Viewport(new Size(1024,768));
shaderProgram = GL.CreateProgram();
int vertexShader = GL.CreateShader(ShaderType.VertexShader);
int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(vertexShader, File.ReadAllText(programDirectory + #"\vertex.vert"));
GL.ShaderSource(fragmentShader, File.ReadAllText(programDirectory + #"\fragment.frag"));
GL.CompileShader(vertexShader);
GL.CompileShader(fragmentShader);
GL.AttachShader(shaderProgram, vertexShader);
GL.AttachShader(shaderProgram, fragmentShader);
GL.LinkProgram(shaderProgram);
if (GL.GetError() != ErrorCode.NoError) { System.Diagnostics.Debugger.Break(); }
Console.WriteLine(GL.GetProgramInfoLog(shaderProgram));
GL.UseProgram(shaderProgram);
Matrix4 projectionMatrix = Matrix4.CreateOrthographic(1024, 768, 0, 1);
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "vertex_projection"), false, ref projectionMatrix);
uniform_fragment_texture = GL.GetUniformLocation(shaderProgram, "fragment_texture");
testTexture = loadTexture(programDirectory + #"\test.png");
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
window.UpdateFrame += window_UpdateFrame;
window.RenderFrame += window_RenderFrame;
window.Resize += window_Resize;
window.TargetRenderFrequency = 60;
window.Run();
}
static void window_Resize(object sender, EventArgs e)
{
//Don't allow resizing for now.
window.Size = new Size(1024, 768);
}
static void window_UpdateFrame(object sender, FrameEventArgs e)
{
ErrorCode currentError = GL.GetError();
if (currentError != ErrorCode.NoError)
{
Console.WriteLine(Enum.GetName(typeof(ErrorCode), currentError));
System.Diagnostics.Debugger.Break();
}
}
static void window_RenderFrame(object sender, FrameEventArgs e)
{
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
//test texture is 128x128pixels.
drawTexRect(100, 228, 100, 228, testTexture);
window.SwapBuffers();
}
static int loadTexture(String filePath)
{
GL.Enable(EnableCap.Texture2D);
int id = GL.GenTexture();
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, id);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
Bitmap bmp = new Bitmap(filePath);
BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, bmp_data.Scan0);
bmp.UnlockBits(bmp_data);
bmp.Dispose();
return id;
}
static void drawTexRect(float top, float bottom, float left, float right, int texture)
{
//topLeft,bottomLeft,bottomRight,topRight
float[] vertices = new float[] {
left, top, 0, 0,
left, bottom, 0, 1,
right, bottom, 1, 1,
right, top, 1, 0,
};
int buffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData<float>(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
//vec2 - screen position
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4, 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4, 2 * sizeof(float));
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.Uniform1(uniform_fragment_texture, 0);
GL.DrawArrays(PrimitiveType.Quads, 0, 4);
GL.DeleteBuffer(buffer);
}
}
}
[vertex.vert]
#version 330
in vec2 vertex_position;
in vec2 vertex_texturePosition;
uniform mat4 vertex_projection;
out vec2 fragment_texturePosition;
void main()
{
gl_Position = vec4(vertex_position,0.0,1.0) * vertex_projection;
fragment_texturePosition = vertex_texturePosition;
}
[fragment.frag]
#version 330
in vec2 fragment_texturePosition;
uniform sampler2D fragment_texture;
out vec4 output_color;
void main()
{
output_color = texture(fragment_texture,fragment_texturePosition);
}
After changes suggested by #j-p one problem remains:
After texture position change suggested by #j-p:
The projection is also wrong given the position i expect it to be 100 px from the left and 100 px from the top, don't see how i can fix this..
The stride parameter is in byte:
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 0);
//vec2 - texture coordinates
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 4 * sizeof(float), 2 * sizeof(float));
Also,the corresponding opengl pixel format for windows argb bitmap is BGRA. (link)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,**OpenTK.Graphics.OpenGL.PixelFormat.Bgra**, PixelType.UnsignedByte, data.Scan0);
And finally, your texture coordinates should be adjusted as follow:
float[] vertices = new float[] {
left, top, 0, 1,
left, bottom, 0, 0,
right, bottom, 1, 0,
right, top, 1, 1
};