Jump to content

  • Log In with Google      Sign In   
  • Create Account


Sirisian

Member Since 05 Oct 2005
Offline Last Active Yesterday, 07:33 PM
-----

Topics I've Started

FBO with differing texture sizes? (glViewportArray?)

11 March 2012 - 05:46 PM

// edit hmm apparently when using different texture sizes it uses the minimum sized texture for all of them. So what I was trying was not possible.

I've been learning FBOs and wanted to try dealing with frame buffer textures that were different sizes. So in my test I created a texture the resolution of the screen to store parts of my model that didn't glow. Then I created a texture half the width and height of the screen for the part for the part of the model that did glow. My test was that I'd have a shader that would output to both textures. This works when both textures are the same width and height, but if I change the second texture (the glow one) to be half the width and height suddenly my viewport is cut into half when rendering just the first non-glow texture.

So the working code is as follow:
// Model Texture
glGenTextures(1, &modelTexture);
glBindTexture(GL_TEXTURE_2D, modelTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
// Blur Texture
glGenTextures(1, &modelBlurTexture);
glBindTexture(GL_TEXTURE_2D, modelBlurTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
// Depth buffer
glGenRenderbuffers(1, &modelDepthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, modelDepthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Model FBO
glGenFramebuffers(1, &modelFBO);
glBindFramebuffer(GL_FRAMEBUFFER, modelFBO);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, modelDepthRenderBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, modelTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, modelBlurTexture, 0);
GLenum modelTextureFBOStatus;
if ((modelTextureFBOStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
{
  std::cerr << "glCheckFramebufferStatus: error " << modelTextureFBOStatus << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

And the render code is just:
// Draw the model to the FBO
glUseProgram(modelShader.Program);
GLfloat viewports[] = { 0, 0, width, height, 0, 0, width, height };
glViewportArrayv(0, 2, viewports);
glBindFramebuffer(GL_FRAMEBUFFER, modelFBO);
GLenum modelBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, modelBuffers);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(model.GPU.VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, noiseTexture);
glUniformMatrix4fv(modelShader.MVP.Model, 1, true, model.ModelMatrix);
glUniformMatrix4fv(modelShader.MVP.View, 1, true, view);
glUniform1f(modelShader.Distance, distance);
glDrawElements(GL_TRIANGLES, model.CPU.IBO.size(), GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Notice I have glViewportArray set so the first viewport is (0, 0, width, height) mapped to (left, bottom, width, height). Am I using that correct? According the documentation: http://www.opengl.or...ewportArray.xml it says I am. Meaning the normalized device coordinates (-1, -1) would map to the window coordinates of (0, 0) and (1, 1) would map to (width, height) which seems right.

The above produces this:
Posted Image

But if I change the blurTexture to half the width and height to:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width / 2, height / 2, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
suddenly the modelTexture's results change when I run the program:
Posted Image

I can't figure out why that is happening. I'd appreciate it if someone could explain what I'm doing wrong. I imagine I've just misunderstood how FBOs and viewports arrays work together to allow different texture sizes. (If it isn't clear I'm using OpenGL 4.2).

Single timer event dispatcher.

12 February 2012 - 05:04 PM

I have a need to asynchronously execute many timed events (Could go over 1000 events). So the basic idea is that I have a priority queue of events and the timer should execute the first one and then wait for the next item and execute it when the time comes. Events can be inserted concurrently and must have a way to be removed. I'm not sure what the best design looks like in C#.

I'll describe my current implementation:
[source lang="csharp"]public class TimeEvent : IComparable<TimeEvent>{ public DateTime Time { get; set; } public bool Enabled { get; set; } public TimeEvent() { Enabled = true; } public int CompareTo(TimeEvent other) { return Time.CompareTo(other.Time); }}[/source]

Then I have a derived TimeEvent class. As an example (not that important):
[source lang="csharp"]internal class TimeEvent1 : TimeEvent{ public Action<Packet> Callback { get; set; } public SourceConnectionRequestTimeout(Action<Packet> callback, TimeSpan time) { Callback = callback; Time = DateTime.Now + time; }}[/source]

Ignoring the odd use of inheritance, the basic dispatcher uses a Timer instance. "timeEvents" is a basic heap implementation for a priority queue.
[source lang="csharp"]TimeEventDispatcher = new Timer((o) =>{ lock (TimeEventDispatcher) { var timeEvent = timeEvents.Pop(); if (timeEvent.Enabled) { if (timeEvent is TimeEvent1) { (timeEvent as TimeEvent1).Callback(); } } // Stop the timer if there are no other events in the priority queue. If there are events then wait for the next one. if (!timeEvents.Empty) { timeEvent = timeEvents.Peek(); var delay = Math.Max(0, (int)(timeEvent.Time - DateTime.Now).TotalMilliseconds); TimeEventDispatcher.Change(delay, Timeout.Infinite); } }}, null, Timeout.Infinite, Timeout.Infinite);[/source]
Now to add a TimeEvent instance I'm locking the timer so the code in the callback can't execute at the same time. Then I insert the new time event instance. If it happens to be the first item in the priority queue this means the timer needs to be changed to update at the new earlier time. (Basically if the item in the priority queue was set to expire 100 ms from now and we insert an item to execute 50 ms from now then we need to change the timer to 50 ms). This also conveniently starts the timer if it isn't already started.
[source lang="csharp"]public void AddTimeEvent(TimeEvent timeEvent){ lock (TimeEventDispatcher) { timeEvents.Push(timeEvent); if (timeEvents.Peek() == timeEvent) { var delay = Math.Max(0, (int)(timeEvent.Time - DateTime.Now).TotalMilliseconds); TimeEventDispatcher.Change(delay, Timeout.Infinite); } }}[/source]
Removing an event is done by locking the timer and setting the Enabled property on the time event instance to false. So when it's processed it's removed without executing the item. Pretty simple solution.

Okay so the above solution seems like it would work. There's a race condition in the system where if a callback is execute and doesn't get to the lock statement by the time another time event is inserted before the most recent one the it'll execute the wrong one. But that can only happen if you insert an item that must be executed right away so it has no ill-effect on the algorithm. Also all the time events are very small so when they execute they don't block the system so they don't need to be executed asynchronously themselves (via tasks or somethings).

Is there a better algorithm in C# for handling this situation? (Mostly caring about performance). Anything my algorithm is missing assuming it should be design to handle possibly thousands of time events.

(Also if anyone is curious about the actual problem, this is a networking library timer like the one found in TCP that manages resend events and other timer events).

Whitehouse: We the People petition system

14 October 2011 - 11:18 PM

We The People launched a few weeks ago. I was skeptical at first, but it seems to be doing fairly well. The commenting system still seems to be in development.

Sorting by popularity has a lot of interesting topics. I won't bias the thread by listing my favorites. Fun system though if you live in the US. (I believe it's international though so anyone can participate).

I voted a few times already. Waiting for the comment system. I already submitted all of my feedback to make things better. (I imagine they know about the minor usability problems).

http://www.youtube.com/watch?v=MdcotOjqnVI

GDWiki DNS error?

09 October 2011 - 03:47 AM

I was going to link someone my networking articles, but the DNS seems to be broken for the wiki. Can you guys fix that.

Brain Scanner Records Dreams on Video

30 September 2011 - 07:30 PM

I don't know how I missed this. Someone just linked it in IRC. Amazing technology. The ability to pull foggy video from a person's head by scanning it. This is real-time video.

Been listening to dream police now. :lol:

PARTNERS