openGL textures beginner question - 1D Texture creation? - opengl

EDIT
Ok I added some changes to my texture rendering, and I'm now at a point that it doesn't look how I want it but before I try to change anything I just want to be sure I'm on the right path. The problem I'm trying to fix is: I have 180000 vertices. Each of them can be from one of 190 "classes". Each class can have a different color assigned at a different time. So I'm trying to create a texture with 190 colors, and for each of the 180000 vertexes have a textureCoord to the coresponding class. So for some code:
self.bufferTextureIndex = glGenBuffersARB(1)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferTextureIndex)
glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(textureIndexes), ADT.voidDataPointer(textureIndexes), GL_STATIC_DRAW_ARB)
self.texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_1D, self.texture)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 190, 0, GL_RGB , GL_FLOAT, textureArray)
So textureIndexes is an array of floats from [0..1]. len(textureIndexes) is the number of vertices I'm using (180000). For the texture, textureArray contains 190 * 3 floats coresponding to the RBG of the colors I want for each class.
The drawing part:
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferTextureIndex)
glTexCoordPointer(1, GL_FLOAT, 0, None);
glBindTexture(GL_TEXTURE_1D, self.texture)
glEnable(GL_TEXTURE_1D)
if type == GL_POINTS:
glDrawArrays( GL_POINTS, 0, len(self.vertices) / 3 );
else:
glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, ADT.voidDataPointer(self.triangles))
So does this approach seem right ? The result isn't what I'm expecting but that might be for the color codification I chose and I cam further look on that if the main approach is a good one. I think that most likely the indexes are build wrong. To build them I have a file with a number between 0 and 190 corresponding to the class for each index. So my index building so far was just read index then index / 190 for each vertex to get a number in [0..1]
EDIT2
So I took your advice, did the index + 0.5 / 190 to generate my indexes. I'm printing the length and values of the indice array. It's 60000 and all are numbers between 0 and 1 , mostly between 0.3 and 0.95. But still all my vertices are of the same color. So the only thing I haven't checked is the 1D Texture generation. Maybe here is where I got it wrong:
i = 0
while i < 30:
textureArray.append([1,0,0])
i = i + 1
while i < 60:
textureArray.append([1,1,0])
i = i + 1
while i < 90:
textureArray.append([1,1,1])
i = i + 1
while i < 120:
textureArray.append([0,1,1])
i = i + 1
while i < 150:
textureArray.append([0,0,1])
i = i + 1
while i < 190:
i = i + 1
textureArray.append([0,0,0])
This is how I generate my texture array. This will not be the actual solution but for testing reasons. So my texture should be 1/6 red - 1/6 ... . The texture generation as above:
self.texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_1D, self.texture)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 190, 0, GL_RGB , GL_FLOAT, textureArray)
Is this texture generating correct ? Because even though my indices range is like I mentioned before, all my vertices have the color of the very first color from the texture. Funny thing is that if I "omit" the glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferTextureIndex) form the drawing and let the normals take the place of the texture indices I do get some different colors, but textureIndexes seem to all point to the very first color from my texture. I've uploaded two sample files with the actual values of textureIndices and normals. No ideea why the first one doesn't work but the second seems to work(can't really verify if they are the correct colors but at least they are different).
http://www.megafileupload.com/en/file/315895/textureIndices-txt.html
http://www.megafileupload.com/en/file/315894/normalsTest-txt.html
EDIT3
So now my indices seems to work. Here is a sample image:
http://i.stack.imgur.com/yvlV3.png
However the odd part is that as you can see the borders are not defined properly. Could this be influenced in any way by some of the parameters I pass to the texture or should I triple check my textureIndex creation ?

At the moment you use your normals as texture coordinates, because self.bufferNormals was bound when calling glTexCoordPointer. 1D textures aren't just per vertex colors. they are accessed by per-vertex texture coordinates, like 2D textures, otherwise they would be a useless substitute for per-vertex colors. Read some introductory material on OpenGL texturing or texturing in general if you don't uderstand that.
As said above, definitely not.
EDIT: According to you newest question (the one with the screenshot), keep in mind, that when the vertices of a single triangle have different texture coordinates (in your case they would belong to different classes, which I suppose shouldn't happen), the texCoords are interpolated accross the triangle and then used to get the texture color. So you have to make sure all vertices of a triangle have the same texCoord if you don't want this to happen (which I suppose). So you have to duplicate vertices along the "material class" borders. Perhaps you could get a quick and dirty solution by just setting glShadeModel(GL_FLAT), but that would also flatten lighting and it is not determined to which class a border triangle belongs then.

Related

OpenGL Compute Shader - glDispatchCompue() does not run

I'm currently working with a compute shader in OpenGl and my goal is to render from one texture onto another texture with some modifications. However, it does not seem like my compute shader has any effect on the textures at all.
After creating a compute shader I do the following
//Use the compute shader program
(*shaderPtr).useProgram();
//Get the uniform location for a uniform called "sourceTex"
//Then connect it to texture-unit 0
GLuint location = glGetUniformLocation((*shaderPtr).program, "sourceTex");
glUniform1i(location, 0);
//Bind buffers and call compute shader
this->bindAndCompute(bufferA, bufferB);
The bindAndCompute() function looks like this and its purpose is to ready the two buffers to be accessed by the compute shader and then run the compute shader.
bindAndCompute(GLuint sourceBuffer, GLuint targetBuffer){
glBindImageTexture(
0, //Always bind to slot 0
sourceBuffer,
0,
GL_FALSE,
0,
GL_READ_ONLY, //Only read from this texture
GL_RGB16F
);
glBindImageTexture(
1, //Always bind to slot 1
targetBuffer,
0,
GL_FALSE,
0,
GL_WRITE_ONLY, //Only write to this texture
GL_RGB16F
);
//this->height is currently 960
glDispatchCompute(1, this->height, 1); //Call upon shader
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
And finally, here is the compute shader. I currently only try to set it so that it makes the second texture completely white.
#version 440
#extension GL_ARB_compute_shader : enable
#extension GL_ARB_shader_image_load_store : enable
layout (rgba16, binding=0) uniform image2D sourceTex; //Textures bound to 0 and 1 resp. that are used to
layout (rgba16, binding=1) uniform image2D targetTex; //acquire texture and save changes made to texture
layout (local_size_x=960 , local_size_y=1 , local_size_z=1) in; //Local work-group size
void main(){
vec4 result; //Vec4 to store the value to be written
pxlPos = ivec2(gl_GlobalInvocationID.xy); //Get pxl-pos
/*
result = imageLoad(sourceTex, pxlPos);
...
*/
imageStore(targetTex, pxlPos, vec4(1.0f)); //Write white to texture
}
Now, when I start bufferB is empty. When I run this I expect bufferB to become completely white. However, after this code bufferB remains empty. My conclusion is that either
A: The compute shader does not write to the texture
B: glDispatchCompute() is not run at all
However, i get no errors and the shader does compile as it should. I have checked that I bind the texture correctly when rendering by binding bufferA which I already know what it contains, then running bindAndCompute(bufferA, bufferA) to turn bufferA white. However, bufferA is unaltered. So, I've not been able to figure out why my compute shader has no effect. If anyone has any ideas on what I can try to do it would be appreciated.
End note: This has been my first question asked on this site. I've tried to present only relevant information but I still feel like maybe it became too much text anyway. If there is feedback on how to improve the structure of the question that is welcome as well.
---------------------------------------------------------------------
EDIT:
The textures I send in with sourceBuffer and targetBuffer is defined as following:
glGenTextures(1, *buffer);
glBindTexture(GL_TEXTURE_2D, *buffer);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA16F, //Internal format
this->width,
this->height,
0,
GL_RGBA, //Format read
GL_FLOAT, //Type of values in read format
NULL //source
);
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);
The image format of the images you bind doesn't match the image format in the shader. You bind a RGB16F (48byte per texel) texture, but state in the shader that it is of rgba16 format (64byte per texel).
Formats have to match according to the rules given here. Assuming that you allocated the texture in OpenGL, this means that the total size of each texel have to match. Also note, that 3-channel textures are (without some rather strange exceptions) not supported by image load/store.
As a side-note: The shader will execute and write if the texture format size matches. But what you write might be garbage because your textures are in 16-bit floating point format (RGBA_16F) while you tell the shader that they are in 16-bit unsigned normalized format (rgba16). Although this doesn't directlyy matter for the compute shader, it does matter if you read-back the texture or access it trough a sampler or write data > 1.0f or < 0.0f into it. If you want 16-bit floats, use rgba16f in the compute shader.

OpenGL How to render to texture with multi-sampling

Implementing some effect, I end up with 1 frame buffer associated to 1 texture, which holds my final scene. This texture is then applied on a fullscreen quad.
The result is what I expect as far as the effect goes, but I noticed that edges on the scene thus rendered, weren't smooth - presumably, because multi-sampling did not apply during render-to-framebuffer passes, as it does when I render directly to the screen buffer.
So my question is
How can I apply/use multi-sampling on this final texture, so that its content shows smooth edges?
EDIT: I have removed the original version of my code here, which was using
a classic FrameBuffer + Texture not multi-sampled. Below is the lastest,
following suggestions in the comments.
For now also, I'll focusing on getting the glBlitFramebuffer approach to work!
So my code now goes like so:
// Unlike before, finalTexture is multi-sampled, thus created like this:
glGenFramebuffers(1, &finalFrame);
glGenTextures(1, &finalTexture);
glBindFramebuffer(GL_FRAMEBUFFER, finalFrame);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, finalTexture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, w, h, GL_TRUE);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_MULTISAMPLE,
finalTexture,
0);
// Alternative using a render buffer instead of a texture.
//glGenRenderbuffers(1, &finalColor);
//glBindRenderbuffer(GL_RENDERBUFFER, finalColor);
//glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA, w, h);
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, finalColor);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Then I introduced a new frame buffer to resolve the multi-sampling:
// This one's not multi-sampled.
glGenFramebuffers(1, &resolveFrame);
glGenTextures(1, &resolveTexture);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFrame);
glBindTexture(GL_TEXTURE_2D, resolveTexture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
resolveTexture,
0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Now a lot of code to produce a glowing effect, things like:
// 1. Generate 1 frame buffer with 2 color attachments (textures) - no multisampling
// 2. Render the 3D scene to it:
// - texture 0 receives the entire scene
// - texture 1 receives glowing objects only
// 3. Generate 2 frame buffers with 1 color attachment (texture) each - no multisampling
// - we can call them Texture 2 and texture 3
// 4. Ping-pong Render a fullscreen textured quad on them
// - On the first iteration we use texture 1
// - Then On each following iteration we use one another's texture (3,2,3...)
// - Each time we apply a gaussian blur
// 5. Finally sum texture 0 and texture 3 (holding the last blur result)
// - For this we create a multi-sampled frame buffer:
// - Created as per code here above: finalFrame & **finalTexture**
// - To produce the sum, we draw a full screen texured quad with 2 sampler2D:
// - The fragment shader then computes texture0+texture3 on each pixel
// - finalTexture now holds the scene as I expect it to be
// Then I resolve the multi-sampled texture into a normal one:
glBindFramebuffer(GL_READ_FRAMEBUFFER, finalFrame);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFrame);
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// And the last stage: render onto the screen:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, resolveTexture);
drawFullScreenQuad( ... );
The resulting output is correct, meaning that I can see the scene with the desired glowing effect... But no apparent multi-sampling! :(
Note: I am starting to wonder, if I am using multi-sampling at the right stage - I will be experimenting on this - but any chance I should use it when rendering the initial 3D scene for the first time, on the initial FBOs? (the ones I refer to in the comments and I didn't want to post here to avoid confusion :s)
I added more detailed comments on what's going on before this last stage with final & resolve frame buffers.
You have: "step 5. Finally sum texture 0 and texture 3 (holding the last blur result) - For this we create a multi-sampled frame buffer". But this way multisampling will only apply to fullscreen quad.
"if I am using multi-sampling at the right stage" so the answer to your question is no, you need to use multisampling on another stage when you render a scene.
I have very similar setup with framebuffers (that one which is used to render the scene is multisampled) two output textures (for color info and for highlights which will later be blurred to achieve glow) and ping-pong framebuffers. I also use glBlitFramebuffer solution (also I use 2 blit calls for each color attachment, each one will go in own texture), have not found any way of making it render directly into framebuffer with attached texture.
If you want some code, this is solution that worked for me (it is in C# though):
// ----------------------------
// Initialization
int BlitFrameBufferHandle = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, BlitFrameBufferHandle);
// need to setup this for 2 color attachments:
GL.DrawBuffers(2, new [] {DrawBuffersEnum.ColorAttachment0, DrawBuffersEnum.ColorAttachment1});
// create texture 0
int ColorTextureHandle0 = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, ColorTextureHandle0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear); // can use nearest for min and mag filter also
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge);
// for HRD use PixelInternalFormat.Rgba16f and PixelType.Float. Otherwise PixelInternalFormat.Rgba8 and PixelType.UnsignedByte
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba16f, Width, Height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, ColorTextureHandle0, 0);
// create texture 1
int ColorTextureHandle1 = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, ColorTextureHandle1);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba16f, Width, Height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment1, TextureTarget.Texture2D, ColorTextureHandle1, 0);
// check FBO error
var error = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (error != FramebufferErrorCode.FramebufferComplete) {
throw new Exception($"OpenGL error: Framwbuffer status {error.ToString()}");
}
int FrameBufferHandle = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FrameBufferHandle);
// need to setup this for 2 color attachments:
GL.DrawBuffers(2, new [] {DrawBuffersEnum.ColorAttachment0, DrawBuffersEnum.ColorAttachment1});
// render buffer 0
int RenderBufferHandle0 = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, RenderBufferHandle0);
GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, 8, RenderbufferStorage.Rgba16f, Width, Height);
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, RenderBufferHandle0);
// render buffer 1
int RenderBufferHandle1 = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, RenderBufferHandle1);
GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, 8, RenderbufferStorage.Rgba16f, Width, Height);
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment1, RenderbufferTarget.Renderbuffer, RenderBufferHandle1);
// depth render buffer
int DepthBufferHandle = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, DepthBufferHandle);
GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, 8, RenderbufferStorage.DepthComponent24, Width, Height);
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, DepthBufferHandle);
// check FBO error
var error = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (error != FramebufferErrorCode.FramebufferComplete) {
throw new Exception($"OpenGL error: Framwbuffer status {error.ToString()}");
}
// unbind FBO
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
// ----------------------------
// Later for each frame
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FrameBufferHandle);
// render scene ...
// blit data from FrameBufferHandle to BlitFrameBufferHandle
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, FrameBufferHandle);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, BlitFrameBufferHandle);
// blit color attachment0
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.BlitFramebuffer(
0, 0, Width, Height,
0, 0, Width, Height,
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest
);
// blit color attachment1
GL.ReadBuffer(ReadBufferMode.ColorAttachment1);
GL.DrawBuffer(DrawBufferMode.ColorAttachment1);
GL.BlitFramebuffer(
0, 0, Width, Height,
0, 0, Width, Height,
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest
);
// after that use textures ColorTextureHandle0 and ColorTextureHandle1 to render post effects using ping-pong framebuffers ...
Just implemented a bloom effect myself, faced the same aliased edges on the resulting image and faced the exactly same issues. Hence sharing my experience here.
Aliasing happens when you render the lines with OpenGL - e.g. edges of a triangle or a polygon, since OpenGL draws "diagonal" (or simply put non-straight) lines on the screen using quite simple (yet fast) algorithms.
That being said, if you want to anti-alias something - that would be a 3D shape, not a texture - it is just a plain image after all.
Off-topic: in order to fix aliasing on an image you would apply the similar technique, but you would need to figure out where the "edges" are on the image and then follow the same algorithm per "edge" pixel. "Edge" (in quotes) since they are just ordinary pixels from the image perspective and being an edge is just extra context we humans attach to those pixels.
With that out of our way, the thing with two image attachments is actually a nice optimization - you do not need to render your entire scene twice to different framebuffers. But you will pay the price of copying the data from each multi-sampled framebuffer attachment to a separate non-multisampled texture for post-processing.
A bit off-topic: performance-wise, I think this is exactly the same (or within a very small threshold) - rendering an entire scene twice, to two separate framebuffers with two separate multi-sampled attachments (as inputs for the post-processing) and then copying each of them separately to two separate non-multisampled textures.
So the last step before you can apply your (any) post-processing to the multi-sampled scene is to convert each multi-sampled render result to non-multisampled texture - so that your shaders work with plain sampler2D.
It would be something similar to this:
glBindFramebuffer(GL_READ_FRAMEBUFFER, bloomFBOWith2MultisampledAttachments);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, temporaryFBOWith1NonMultisampledAttachment);
// THIS IS IMPORTANT
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, windowWidth, windowHeight, 0, 0, windowWidth, windowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// bloomFBOWith2MultisampledAttachments is still bound
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, blurFramebuffer1);
// THIS IS IMPORTANT
glReadBuffer(GL_COLOR_ATTACHMENT1);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, windowWidth, windowHeight, 0, 0, windowWidth, windowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
Given you are rendering your scene to two attachments in one framebuffer, you will then need to copy from each of those multi-sampled attachments to non-multi-sampled textures and use them for additive rendering and blurring, correspondingly.
If you don't mind messy code and the use of globjects for OpenGL APIs abstraction, here's my entire bloom solution with anti-aliasing.
And few screenshots:
The first screenshot does not use a framebuffer to render to, so the lines are really smooth.
The second screenshot is the first implementation of a bloom effect (available as a separate CMake project).
Aliasing is more visible on longer distances, so the third screenshots shows a bit more of a scene - the edges look really stairs-like.
The last two screenshots show the bloom effect with anti-aliasing applied.
Note how lantern only has somewhat low-resolution texture, hence aliased lines, whilst the paper has its edges smoothed out by anti-aliasing.

Why does mipmapping not work on my 3D texture? (opengl)

So I am creating a terrain and for texturing, I want to use a 3D texture (depth 3) which holds 3 images (512x512) on each z-layer, so that I would be able to use GPU interpolation between these layers based on just one factor: 0/3 = image 1, 1/3 = image 2, 2/3 = image 3, and every value in between interpolates with the next level (cyclic).
This works perfectly as long as I don't enable mip maps on this 3D texture. When I do enable it, my terrain gets the same one image all over unless I come closer, as if the images have shifted from being z-layers to being mip-map layers.
I don't understand this, can someone tell me what I'm doing wrong?
This is where I generate the texture:
glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_3D, m_textureId);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 512, 512, 3, 0, GL_BGR, GL_UNSIGNED_BYTE, 0);
This is the step I perform for every Z:
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, Z, 512, 512, 1, GL_BGR, GL_UNSIGNED_BYTE, imageData);
After this, I do:
glGenerateMipmap(GL_TEXTURE_3D);
In the shader, I define the texture as:
uniform sampler3D tGround;
and simply sample it with:
texture(tGround, vec3(texcoord, f));
where texcoord is a 2D coordinate and f is the layer we need, simply based on height at this moment.
There is a way to do something like what you want, but it does require work. And you can't use a 3D texture to do it.
You have to use Array Textures instead. The usual way to think of a 2D array texture is as a bundle of 2D textures of the same size. But you can also think of it as a 3D texture where each mipmap level has the same number of Z layers. However, there's also the issue where there is no blending between array layers.
Since you want blending, you will need to synthesize it. But that's easy enough with shaders:
vec4 ArrayTextureBlend(in vec3 texCoord)
{
float frac = fract(texCoord.z);
texCoord.z = floor(texCoord.z);
vec4 top = texture(arrayTex, texCoord);
vec4 bottom = texture(arrayTex, texCoord + vec3(0, 0, 1));
return mix(top, bottom, frac); //Linearly interpolate top and bottom.
}

FreeType OpenGL dynamic Text = abysmal performance

I'm currently searching for bottlenecks in my code and it turns out the GUI is one of them. Well, not actually the GUI but rather the dynamic text that is drawn there.
Initialization
if (FT_Init_FreeType(&m_FreeType))
throw Helpers::ExceptionWithMsg("Could not init freetype lib");
if (FT_New_Face(m_FreeType, "res\\fonts\\FreeSans.ttf", 0, &m_FontFace))
throw Helpers::ExceptionWithMsg("Could not open font");
m_ShaderID = ... // Loads the corresponding shader
m_TextColorLocation = glGetUniformLocation(m_ShaderID, "color");
m_CoordinatesLocation = glGetAttribLocation(m_ShaderID, "coord");
glGenBuffers(1, &m_VBO);
FT_Set_Pixel_Sizes(m_FontFace, 0, m_FontSize);
glyph = m_FontFace->glyph;
glGenTextures(1, &m_Texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);
// We require 1 byte alignment when uploading texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Clamping to edges is important to prevent artifacts when scaling
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUseProgram(m_ShaderID);
glUniform4f(m_TextColorLocation, m_TextColor.x, m_TextColor.y, m_TextColor.z, m_TextColor.w);
glUseProgram(0);
What I do: I initialize FreeType, get the Font, initialize the shader and all uniforms.
Then I create the vbo for the textureCoordinates, set the Pixels for the font, get the glyph.
Now I generate the texture, activate it, bind it... I want to set all the parameters and then the uniform that never changes.
Rendering:
glUseProgram(m_ShaderID);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);
// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set up the VBO for our vertex data
glEnableVertexAttribArray(m_CoordinatesLocation);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glVertexAttribPointer(m_CoordinatesLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLfloat cursorPosX = m_X;
GLfloat cursorPosY = m_Y;
for (size_t i = 0; i < m_Text.size(); ++i)
{
// If Loading a char fails, just continue
if (FT_Load_Char(m_FontFace, m_Text[i], FT_LOAD_RENDER))
continue;
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glyph->bitmap.width, glyph->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
// Calculate the vertex and texture coordinates
GLfloat x2 = cursorPosX + glyph->bitmap_left * m_SX;
GLfloat y2 = -cursorPosY - glyph->bitmap_top * m_SY;
GLfloat w = glyph->bitmap.width * m_SX;
GLfloat h = glyph->bitmap.rows * m_SY;
PointStruct box[4] =
{
{ x2, -y2, 0, 0 },
{ x2 + w, -y2, 1, 0 },
{ x2, -y2 - h, 0, 1 },
{ x2 + w, -y2 - h, 1, 1 }
};
// Draw the character on the screen
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Advance the cursor to the start of the next character
cursorPosX += glyph->advance.x / 64 * m_SX;
cursorPosY += glyph->advance.y / 64 * m_SY;
}
glDisableVertexAttribArray(m_CoordinatesLocation);
glDeleteTextures(1, &m_Texture);
glDisable(GL_BLEND);
glUseProgram(0);
Setting the shader and stuff is obvious.
For each render call I activate the texture, bind it, enable the VBO I store my textureCoordinates in. Then I iterate over every character in the text load it with FT_LOAD_CHAR.
I then specify the texture with glTexImage2D, calculate vertex and texture coordinates and draw everything.
That seems to be highly inefficient, but I find no way to improve the performance and yet have readable text.
I wanted to set the text parameters just once in the init -> all chars are boxes.
I wanted to set GL_DYNAMIC_DRAW to GL_STATIC_DRAW... not much difference.
What else can I do?
The text I render is dynamic, it changes (or may change) each frame, so I'm kind of stuck.
I query the performance of this stuff with a query. If I do not render the dynamic text it's very low, but if I render the dynamic text it gets up very high... there is not much else going on in this pass, it's just drawing the GUI.
What really bothers me
One thing I really don't understand (may be the sunny day...)
If I do not set linear filtering in the render-method() I get strange cube-glyphs, but why is that? OpenGL is a state machine, the texture-parameters are set to the one currently bound. So if I set the Min and Mag filter to GL_LINEAR in the initialization why isn't that enough?
If I remove those 2 lines in the render I get way better performance from the query (much lower numbers), but it doesn't drawn anything readable.
This is absolutely going to be slow.
For each render call I activate the texture, bind it, enable the VBO I store my textureCoordinates in. Then I iterate over every character in the text load it with FT_LOAD_CHAR. I then specify the texture with glTexImage2D, calculate vertex and texture coordinates and draw everything.
The problem, unfortunately, is hard. Here is the method I use:
There is one texture, with the GL_RED8 format, which stores glyphs.
Whenever a new glyph is needed, it is added to the texture. This is done by calling FT_Render_Glyph() and copying the result into the texture buffer. If the new glyph doesn't fit, the whole glyph texture is resized and repacked. (I use the skyline algorithm for packing glyphs since it's simple.)
If any new glyphs have been added, then I call glTexSubImage2D(). The code should be structured so that this is only called once per frame.
To render text, I create a VBO that contains vertex and texture coordinates for all the quads necessary to render a piece of text. (Please understand that "quad" means two triangles, not GL_QUAD).
So, when you change what text you want to render,
You have to update the VBO, but only once per frame
You might have to update the texture, but only once per frame, and this will probably happen less frequently as the glyph texture fills up with the glyphs you use.
A good way to prototype this kind of system is to render all of the glyphs in a font into the texture at first, but this doesn't work well if you end up using multiple fonts and styles, or if you want to render Chinese, Korean, or Japanese text.
Additional considerations are line breaking, glyph substitution, kerning, bidi, general problems with international text, how to specify styling, et cetera. I recommend using HarfBuzz in combination with FreeType. HarfBuzz handles difficult glyph substitution and positioning issues. None of this is strictly necessary if your program has English text only.
There are some libraries that do all of this, but I have not used them.
An alternative method, if you want to cut the gordian knot, is to embed a web browser like Chromium (Awesomium, WebKit, Gecko—many choices) in your application, and farm out all text rendering to that.
your bottleneck are probably the many draw calls. firstly you buffer the texture inside of your draw routine: instead provide a texture where you can map characters onto quad-positions and then replace the following:
// Calculate the vertex and texture coordinates
GLfloat x2 = cursorPosX + glyph->bitmap_left * m_SX;
GLfloat y2 = -cursorPosY - glyph->bitmap_top * m_SY;
GLfloat w = glyph->bitmap.width * m_SX;
GLfloat h = glyph->bitmap.rows * m_SY;
PointStruct box[4] =
{
{ x2, -y2, 0, 0 },
{ x2 + w, -y2, 1, 0 },
{ x2, -y2 - h, 0, 1 },
{ x2 + w, -y2 - h, 1, 1 }
};
// Draw the character on the screen
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
with code that pre-processes your text, produces a larger PointStruct buffer (don't forget to adjust your texture coordinates for the look-up-texture) and draws multiple characters per draw call.
There are two easy options to improve performance.
Create a single texture that has all the characters that you will need to render at set offsets. Your text string then becomes a model (buffer object) that will reference the correct series of offsets to create your text string. This has the disadvantage that you will not be able to do kerning or any other fancy font joining.
Use Pango and Cairo to fully render your text as a single bitmap. This bitmap will have the text formatted with correct kerning and joining. You then only upload and draw a single texture for your entire text output.

Create contour plot in opengl using grid data and a 1D texture map

I have a set of X,Y,Z values on a regular spaced grid from which I need to create a color-filled contour plot using C++. I've been googling on this for days and the consensus appears to be that this is achievable using a 1D texture map in openGL. However I have not found a single example of how to actually do this and I'm not getting anywhere just reading the openGL documentation. My confusion comes down to one core question:
My data does not contain an X,Y value for every pixel - it's a regularly spaced grid with data every 4 units on the X and Y axis, with a positive integer Z value.
For example: (0, 0, 1), (4, 0, 1), (8, 0, 2), (0, 4, 2), (0, 8, 4), (4, 4, 3), etc.
Since the contours would be based on the Z value and there are gaps between data points, how does applying a 1D texture achieve contouring this data (i.e. how does applying a 1D texture interpolate between grid points?)
The closest I've come to finding an example of this is in the online version of the Redbook (http://fly.cc.fer.hr/~unreal/theredbook/chapter09.html) in the teapot example but I'm assuming that teapot model has data for every pixel and therefore no interpolation between data points is needed.
If anyone can shed light on my question or better yet point to a concrete example of working with a 1D texture map in this way I'd be forever grateful as I've burned 2 days on this project with little to show for it.
EDIT:
The following code is what I'm using and while it does display the points in the correct location there is no interpolation or contouring happening - the points are just displayed as, well, points.
//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
stripeImage[3*j] = j < 2 ? 0 : 255;
stripeImage[3*j+1] = 255;
stripeImage[3*j+2] = 255;
}
glDisable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
float s[4] = { 0,1,0,0 };
glTexGenfv( GL_S, GL_OBJECT_PLANE, s );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_1D );
glBegin(GL_POINTS);
//_coords contains X,Y,Z data - Z is the value that I'm trying to contour
for (int x = 0; x < _coords.size(); ++x)
{
glTexCoord1f(static_cast<ValueCoord*>(_coords[x])->GetValue());
glVertex3f(_coords[x]->GetX(), _coords[x]->GetY(), zIndex);
}
glEnd();
The idea is using the Z coordinate as S coordinate into the texture. The linear interpolation over the texture coordinate then creates the contour. Note that by using a shader you can put the XY->Z data into a 2D texture and use a shader to do a indirection of the value of the 2D sampler in the color ramp of the 1D texture.
Update: Code example
First we need to change the way you use textures a bit.
To this to prepare the texture:
//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
stripeImage[3*j] = j*255/32; // use a gradient instead of a line
stripeImage[3*j+1] = 255;
stripeImage[3*j+2] = 255;
}
GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_1D, texID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
// We want the texture to wrap, so that values outside the range [0, 1]
// are mapped into a gradient sawtooth
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
And this to bind it for usage.
// The texture coordinate comes from the data, it it not
// generated from the vertex position!!!
glDisable( GL_TEXTURE_GEN_S );
glDisable(GL_TEXTURE_2D);
glEnable( GL_TEXTURE_1D );
glBindTexture(GL_TEXTURE_1D, texID);
Now to your conceptual problem: You cannot directly make a contour plot from XYZ data. XYZ are just sparse sampling points. You need to fill the gaps, for example by putting it into a 2D histogram first. For this create a grid with a certain amount of bins in each direction, initialized to all NaN (pseudocode)
float hist2D[bins_x][bins_y] = {NaN, NaN, ...}
then for each XYZ, add the Z value to the bins of the grid if not a NaN, otherwise replace NaN with the Z value. Afterwards use a Laplace filter on the histogram to smooth out the bins still containing a NaN. Finally you can render the grid as contour plot using
glBegin(GL_QUADS);
for(int y=0; y<grid_height; y+=2) for(int x=0; x<grid_width; x+=2) {
glTexCoord1f(hist2D[x ][y ]]); glVertex2i(x ,y);
glTexCoord1f(hist2D[x+1][y ]]); glVertex2i(x+1,y);
glTexCoord1f(hist2D[x+1][y+1]]); glVertex2i(x+1,y+1);
glTexCoord1f(hist2D[x ][y+1]]); glVertex2i(x ,y+1);
}
glEnd();
or you could upload the grid as a 2D texture and use a fragment shader to indirect into the color ramp.
Another way to fill the gaps in sparse XYZ data is to find the 2D Voronoi diagram of the XY set and use this to create the sampling geometry. The Z values for the vertices would be the distance weighted average of the XYZs contributing to the Voronoi cells intersecting.