PDA

View Full Version : [OpenTK] Depth Buffer as texture problems.



Raptor2277
05-23-2016, 08:58 PM
Hello, I am following this tutorial http://www.learnopengl.com/#!Advanced-Lighting/Shadows/Shadow-Mapping, except I'm using OpenTK. My issue is that I'm creating framebuffer with a depth component as a texture. I draw using a shader, then I plan to use the texture(which has all the depth data) for shadows. However the texture is all white! I've spend about 5 hours trying to figure this s*** out and cannot.

Here is my DepthBufferCode


/// <summary>
/// A frame buffer that just holds a depth buffer
/// </summary>
public class DepthBuffer
{
/// <summary>
/// OpenGL ID
/// </summary>
public int ID { get; private set; }

/// <summary>
/// ID to texture attached to the frambuffer, it acts as a depth buffer, and is used for sampling (this is public)
/// </summary>
public int TextureID { get; private set; }

/// <summary>
/// Status code FramebufferComplete is what we want
/// </summary>
public FramebufferErrorCode FramebufferStatus { get; private set; }

/// <summary>
/// Size of the buffer, we cannot change this, it would be easier to create a new on instead of changing size
/// </summary>
public Size Size { get; private set; }

/// <summary>
/// Create the frambuffer and attach the color and stencil/depth buffers
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
public DepthBuffer(int width, int height)
{
this.Size = new Size(width, height);

//gen depthbuffer as texture
TextureID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, TextureID);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.DepthComponent, width, height, 0, PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Repeat);

//gen frambuffer
ID = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, ID);

//attach depth
GL.FramebufferTexture(FramebufferTarget.Framebuffe r, FramebufferAttachment.DepthAttachment, TextureID, 0);

//since we dont have a color buffer, we cant draw do it (we dont need to)
GL.DrawBuffer(DrawBufferMode.None);
GL.ReadBuffer(ReadBufferMode.None);

//check status and store it
FramebufferStatus = GL.CheckFramebufferStatus(FramebufferTarget.Frameb uffer);

//unbind everything
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}

/// <summary>
/// bind the frambuffer and set the viewport to its size
/// </summary>
public void Use()
{
GL.Viewport(new Point(0, 0), Size);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, ID);
}

/// <summary>
/// delete the buffers from memory
/// </summary>
public void Dispose()
{
GL.DeleteTexture(TextureID);
GL.DeleteFramebuffer(ID);
}
}


Here is my main class


using System;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK;
using GLTools;
using System.Collections.Generic;
using ShadowMapping;
using System.Drawing;

namespace Million_Cubes
{
class Program
{
private GameWindow window;
private Camera cam;
private List<Model> models;
private DepthBuffer depthBuffer;
private ShaderProgram depthShader;

private ModelVBOs frame;
private ShaderProgram frameShader;

Texture txt;

VBO<float> verts;
VBO<float> uv;
VBO<uint> element;

public Program()
{
window = new GameWindow(1600, 900, new GraphicsMode(32, 24, 8, 4), "Million Cubes");
//window.VSync = VSyncMode.Off;
window.UpdateFrame += Window_UpdateFrame;
window.RenderFrame += Window_RenderFrame;
window.MouseDown += Window_MouseDown;
window.MouseUp += Window_MouseUp;
window.MouseMove += Window_MouseMove;
window.MouseWheel += Window_MouseWheel;
window.Resize += Window_Resize;
window.KeyDown += Window_KeyDown;
window.Closed += Window_Closed;

cam = new Camera();
depthBuffer = new DepthBuffer(1024, 1024);
var de = depthBuffer.FramebufferStatus;


models = new List<Model>();
ObjLoader loader = new ObjLoader();
var cube = loader.loadVBOS("content/floor.obj", 3);
var dragon = loader.loadVBOS("content/dragon.obj", 3);

var shader = new ShaderProgram("content/default.vert", "content/default.frag", "default");
shader.writeAllInfoLogs();

depthShader = new ShaderProgram("content/depth.vert", "content/depth.frag", "depth");
depthShader.Use();
var proj = Matrix4.CreateOrthographicOffCenter(-10, 10, -10, 10, 1.0f, 100.5f);
var light = Matrix4.LookAt(new Vector3(.1f, 10, .1f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
Matrix4 lightSpace = Matrix4.Mult(proj, light);
depthShader.setUniform("lightSpaceMatrix", lightSpace);
depthShader.writeAllInfoLogs();

models.Add(new MyModel(dragon, null, shader));
models.Add(new MyModel(cube, null, shader) { Position = new Vector3(0, -5, 0), Scale = 3f });

//frame
verts = new VBO<float>(new float[] { -1, .5f, 0, -.5f, .5f, 0, -.5f, 1, 0, -1, 1, 0 }, BufferTarget.ArrayBuffer, VBO<float>.PointerType.vertex);
uv = new VBO<float>(new float[] { 0, 0, 1, 0, 1, 1, 0, 1 }, BufferTarget.ArrayBuffer, VBO<float>.PointerType.texCoord);
element = new VBO<uint>(new uint[] { 0, 1, 2, 3 }, BufferTarget.ElementArrayBuffer, VBO<uint>.PointerType.element);

frameShader = new ShaderProgram("content/frame.vert", "content/frame.frag", "frame");
frameShader.writeAllInfoLogs();

txt = new Texture("content/derp.jpg");
}

private void Window_RenderFrame(object sender, FrameEventArgs e)
{
//depthBuffer
depthBuffer.Use();
GL.Clear(ClearBufferMask.DepthBufferBit);
foreach (Model m in models)
((MyModel)m).draw(cam, depthShader);

//normal drawwing
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
GL.Viewport(new Rectangle(0, 0, window.Bounds.Width, window.Bounds.Height));
GL.ClearColor(new Color4(46, 49, 54, 255));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

foreach (Model m in models)
m.draw(cam, true);

//right bottom texture
frameShader.Use();
frameShader.bindBufferToShaderAttrib(verts, "vertIn");
frameShader.bindBufferToShaderAttrib(uv, "uvIn", 2);
GL.BindTexture(TextureTarget.Texture2D, depthBuffer.TextureID);
element.bind();
GL.DrawElements(PrimitiveType.Quads, 4, DrawElementsType.UnsignedInt, 0);

window.SwapBuffers();
}

private void Window_UpdateFrame(object sender, FrameEventArgs e)
{
cam.update();
}

private void run()
{
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.Texture2D);

//GL.EnableClientState(ArrayCap.VertexArray);
//GL.EnableClientState(ArrayCap.TextureCoordArray);

GL.CullFace(CullFaceMode.Back);
GL.Enable(EnableCap.CullFace);

GL.MatrixMode(MatrixMode.Projection);
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.De greesToRadians(75), window.Width / (float)window.Height, .1f, 100f);

cam = new Camera();
cam.Projection = perspective;

window.Run();
}

#region Events

private void Window_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs e)
{
cam.keydown(e);
}

private void Window_Resize(object sender, EventArgs e)
{
GL.Viewport(0, 0, window.Width, window.Height);
}

private void Window_MouseMove(object sender, OpenTK.Input.MouseMoveEventArgs e)
{
cam.mouseMove(e.X, e.Y);
}

private void Window_MouseUp(object sender, OpenTK.Input.MouseButtonEventArgs e)
{
cam.mouseUp();
}

private void Window_MouseDown(object sender, OpenTK.Input.MouseButtonEventArgs e)
{
cam.mouseDown(e.X, e.Y);
}

private void Window_MouseWheel(object sender, OpenTK.Input.MouseWheelEventArgs e)
{
cam.mouseWheel(e.Delta);
}

private void Window_Closed(object sender, EventArgs e)
{
window.Close();
}

#endregion

#region Entry
static void Main(string[] args)
{
Program p = new Program();
p.run();
}
#endregion
}
}


Here are the shaders. These are empty cause we just want to draw them from the light's perspective and write to the depth buffer (done in fragment shader, automatically)


-----------------Vert--------------
#version 330

in vec3 vertIn;

uniform mat4 lightSpaceMatrix;
uniform mat4 model;

void main()
{
gl_Position = lightSpaceMatrix * model * vec4(vertIn, 1);
}
-----------------Frag--------------
#version 330

void main()
{

}


Here is what is looks like. The box in the corner renders the depth buffer. I put the shader to render red if the depth is EXCATLY 1.
http://postimg.org/image/u0ezoqarf/

After messing around. I tried using the camera as the light source. And if I zoom in. it stars to show something. Note that the far plane for the camera is 100.
http://postimg.org/image/jd03ll3zv/

I set the camera's zfar and znear planes to .1f and 1.f and the two images start to line up.
http://postimg.org/image/tbzrg1fgb/

So it looks like the depth buffer only writes from 0 to 1. Yes that's accurate but it should write from 0 to 1 within the clipping planes (0 = 0, 1 = 100). I have no idea how to fix this. Ive tried messing around with a bunch of s*** and none of it seems to work.

Raptor2277
05-23-2016, 09:02 PM
Things I've tried so far.
PixelType.UnsignedInt , float, uint, etc.
PixelInternalFormat.DepthComponent, DepthComponenet16, 24, 32

Tried using perspective instead of ortho, different clipping planes.

Raptor2277
05-23-2016, 09:57 PM
Images don't show. Here they are in order.
http://postimg.org/image/u0ezoqarf/
http://postimg.org/image/jd03ll3zv/
http://postimg.org/image/tbzrg1fgb/

john_connor
05-24-2016, 02:18 AM
So it looks like the depth buffer only writes from 0 to 1. Yes that's accurate but it should write from 0 to 1 within the clipping planes (0 = 0, 1 = 100). I have no idea how to fix this. Ive tried messing around with a bunch of s*** and none of it seems to work.

i think the projection matrix is responsible for the transformation ...
from 0.1 <--> 100 (your scene's view frustum)
to 0 <--> 1 (normalized device coords, a cube of length 1)
by multiplying a vertex with that matrix, you calculate the position in that "cube of length 1":
http://www.songho.ca/opengl/gl_projectionmatrix.html

you can change the values directly using this function:
https://www.opengl.org/sdk/docs/man/html/glDepthRange.xhtml

Raptor2277
05-24-2016, 10:28 AM
Thats not gonna change anything, changing the depthRange is gonna change what is maps to. So glDepthRange(0, 10) will map 0 to 0 and 100 to 10. That's not the problem. The problem is that the depth buffer only gets written when the vertex is in the range of 0 to 1, even though my near and far planes are set to 1 and 100.

Raptor2277
05-24-2016, 11:12 AM
Solved.

Changed some code.


---------vertex shader------
#version 330

in vec3 vertIn;

uniform mat4 view;
uniform mat4 proj;
uniform mat4 model;

void main()
{
mat4 lightSpace = proj * view;
gl_Position = lightSpace * model * vec4(vertIn, 1);
}

------Program------
var proj = Matrix4.CreateOrthographicOffCenter(-10, 10, -10, 10, 1.0f, 100.5f);
var light = Matrix4.LookAt(new Vector3(.1f, 10, 5.1f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
Matrix4 lightSpace = Matrix4.Mult(proj, light);
depthShader.Use();
depthShader.setUniform("proj", proj);
depthShader.setUniform("view", light);


CLEARLY doing proj * view = lightSpace; then lightSpace * model * vec4; works.

But when I do

Matrix4 lightSpace = Matrix4.Mult(proj, light);
depthShader.setUniform("lightSpace", lightSpace);

and in shader do lightSpace * model * vec4; IT DOESN'T F****** work. I just found out that I have to multiply them backwards for it to work. Matrix4 lightSpace = Matrix4.Mult(light, proj); <===== all this s*** cause of this. WHY is it backwards?