Suppose I'm having a problem like this: now I have a framebuffer and a texture only contains one color component(for example, GL_RED) has already binded to it. What will fragment shader looks like? I guess the answer is:
...
out float ex_color;
ex_color = ...;
Here comes my question : will the shader automatically detect the format of framebuffer and write values to it? What if fragment shader outputs float values but framebuffer format is GL_RGBA?
By the way, what is the correct approach to create a texture only has one component? I read examples from g-truc which has a sample like this:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED,GLsizei(Texture.dimensions().x), GLsizei(Texture.dimensions().y), 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
What's the meaning of assign GL_RGB as pixel data format?
Just like vertex shader inputs don't have to match the exact size of the data specified by glVertexAttribPointer, fragment shader outputs don't have to match the exact size of the image they're being written to. If the output provides more components than the destination image format, then the extra components are ignored. If it provides fewer, then the other components have undefined values (unlike vertex inputs, where unspecified values have well-defined values).
What's the meaning of assign GL_RGB as pixel data format?
That's the pixel transfer format. That describes the format of pixels you're providing to OpenGL, not the format that OpenGL will store them as.
You should always use sized internal formats, not unsized ones like GL_RED.
For a decent explanation of the internal format and format, see:
http://opengl.org/wiki/Image_Format and http://opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml.
You basically want GL_RED for format and likely want GL_R8 (unsigned normalized 8-bit fixed-point) for the internal format.
A long time ago, luminance textures were the norm for single-channel, but that is a deprecated format in modern GL and red is now the logical "drawable" texture format for single-channels, just as red/green is the most logical format for two-channel.
As for your shader, there are rules for component expansion defined by the core specification. If you have a texture with 1 channel as an input, but sample it as a vec4, it will be equivalent to: vec4 (RED, 0.0, 0.0, 1.0).
Writing to the texture is a little bit different.
From the OpenGL 4.4 Spec, section 15.2 (Shader Execution), pp. 441 -- http://www.opengl.org/registry/doc/glspec44.core.pdf
When a fragment shader terminates, the value of each active user-defined output variable is written to components of the fragment color output to which it is bound. The set of fragment color components written is determined according to the variable’s data type and component index binding, using the mappings in table 11.1 [pp. 341].
By default, if your fragment shader's output is a float, it is going to write to the x (red) component of your texture. You could use a layout qualifier (e.g. layout (component=1) out float color;) to specify that it should write to y (green), z (blue) or w (alpha) (assuming you have an RGBA texture).
Related
I have to create a texture with equivalent format of D3DFMT_A8L8 in directx9 to directx11. But the note in the documentation is not clear to me. Would someone explain what should be done? While creating input layout I am facing invalid parameter error.
D3DFMT_A8L8 => DXGI_FORMAT_R8G8_UNORM
Note: Use swizzle .rrrg in shader to duplicate red and move green to the alpha components to get Direct3D 9 behavior.
In Direct3D 9, the "Luminance" formats would automatically be read in the shader as RGB values (replicated) because they were greyscale formats. In Direct3D 10+, there are no "Luminance" format. There are one and two channel formats, and there's no "special behavior" with them.
Therefore, in a shader a DXGI_FORMAT_R8G8_UNORM texture will have the first channel in the 'r' channel and the second channel in the 'g' channel. The DXGI_FORMAT_R8G8_UNORM has the same memory foot-print as D3DFMT_A8L8, i.e. two 8-bit channels of unsigned normal integer data, but if you want the behavior in a modern shader that matches the old one you have to do it explicitly with shader swizzles:
Texture2D<float4> Texture : register(t0);
sampler Sampler : register(s0);
float4 color = Texture.Sample(Sampler, pin.TexCoord);
// Special-case for DXGI_FORMAT_R8G8_UNORM treated as D3DFMT_A8L8
color = color.rrrg;
This has nothing at all to do with input layouts. It's just the way a texture sampler works.
I have a framebuffer object with 2 outputs:
layout(location = 0) out vec4 color;
layout(location = 1) out uint object_id;
In my shader I also receive a boolean value, which tells me if I should write to the second output or not.
color = some_color;
if (condition) {
object_id = value;
}
Is this possible to achieve?
I thought I could do it with glBlendEquation(1, GL_MAX) and just write 0 in the else part of the if, but that doesn't seem to work with r32ui textures.
In my shader I also receive a boolean value, which tells me if I should write to the second output or not.
What is condition? A uniform? Something the shader calculates?
It comes as vertex shader input.
If you don't write to one of the user-defined fragment shader output variables, then this is an undefined behavior and the result which is stored to the framebuffer is undefined.
See OpenGL 4.6 API Core Profile Specification; 17.4. WHOLE FRAMEBUFFER OPERATIONS; page 516
If a fragment shader writes to no user-defined output variables, the values of the fragment colors following shader execution are undefined, and may differ for each fragment color. If some, but not all user-defined output variables are written, the values of fragment colors corresponding to unwritten variables are similarly undefined.
See OpenGL 4.6 API Core Profile Specification; 15.2. SHADER EXECUTION; page 492
When a fragment shader terminates, the value of each active user-defined output variable is written to components of the fragment color output to which it is bound.
I thought I could do it with glBlendEquation(1, GL_MAX) and just write 0 in the else part of the if, but that doesn't seem to work with r32ui textures.
That is not possible, because blending is not applied to integer format buffers.
OpenGL 4.6 API Core Profile Specification; 17.3.6 Blending; page 502:
Blending applies only if the color buffer has a fixed-point or floating-point
format. If the color buffer has an integer format, proceed to the next operation.
What you can do is to use a fixed point format for the framebuffer data store, like GL_R16. GL_R16 has 16 bits to store the values from 0.0 to 1.0 and blending is provided. Further GL_R16 is provided for both, textures and renderbuffers. The corresponding data type is float.
You can store a unsigned integer to it by "normalizing" the value by dividing it by 2^16-1:
layout(location = 1) out vec4 object_id;
object_id.r = float(value) / (exp2(16.0)-1.0);
Assuming I only want to render quads and can reuse my mesh, I would like to be able to, in a single draw call, render many instances.
I would like to achieve this with a texture buffer object by placing transformation matrices into the buffer.
I understand how to setup a texture buffer object in C++, but am confused on how to grab my transformations from this in GLSL.
uniform samplerBuffer sampler;
...
... = texelFetch( sampler, index );
In the above code (in a vertex shader) I'm not sure how the samplerBuffer keyword works (and have had a lot of trouble finding documentation). I would like to know which index in the texture buffer a given vertex is associated with, this way a transformation lookup can occur. How can I do this, and what would the GLSL syntax look like?
It can be assumed that the transformation matrices are 4x4 matrices. I was hoping to be able to keep the OpenGL version requirements in the 2.XX range.
Edit: So I found this: http://www.opengl.org/registry/specs/ARB/draw_instanced.txt. I can deal with a 3.0 limitation. However I'm getting confused when looking up examples of how to use this. Using GLEW, I suppose I would call glDrawElementsInstanced, but some places on the internet are saying this requires OpenGL version 3.3 or later. How can I take advantage of the 3.0 requirement I linked?
Well, a buffer texture is essentially a 1D array of data stored in a buffer object's (TEXTURE_BUFFER) data store. You provide a single integer, which is essentially an offset into the buffer and fetch a single texel with texelFetch starting at that offset. The offset always refers to a texel, not to a single component (e.g. the R-component of a vec4) of a texel. Therefore, if you setup the buffer texture with an internal format GL_R, you'll look up a single texel which only stores a single value - however, if you're using GL_RGBA a texel will consist of four components.
For instance, suppose you choose to put two normalized color vectors with RGBA components into the data store, choose the internal format GL_RGBA and index with 0 and 1, you'll get the first and the second texel from the buffer texture, as per section 8.9 of the core OpenGL 4.4 spec:
[..]the attached buffer object’s data store is interpreted as an array of elements of the GL data type corresponding to internalformat. Each texel consists of one to four elements that are mapped to texture components (R, G, B, and A).
Note that texelFetch will always return a gvec4, that is, an ivec4, uivec4 or vec4 depending on the internal format. If you choose an internal format which specifies less than four components, for instance GL_R32F, the result will be an unnormalized (<- that's important!) vec4(R, 0, 0, 1) - the remaining GB components are set to zero and A to 1. See table 8.15 of the aforementioned spec for a complete overview.
Also note that texelFetch does not perform any filtering or LOD clamping.
All versions of texelFetch returns gvec4 so I assume you should perform a 4 lookups, 1 for each row. But that depends on how you encoded your matrix.
uniform samplerBuffer sampler;
...
mat4 transform( texelFetch( sampler, RowIndex0 ), texelFetch( sampler, RowIndex1 ), texelFetch( sampler, RowIndex2 ), texelFetch( sampler, RowIndex3 ) );
Keep in mind that mat4 in GLSL takes columns in the constructor, so you need to transpose that if you are working with Column based matrices.
For offscreen rendering to a texture, I'm attaching at the attachment GL_COLOR_ATTACHMENT0 a texture defined by
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_FLOAT,NULL);
I then render to the FBO using a fragment shader that outputs a vec4, so normally, that should be ok. To check that I display the texture correctly, I use the function
glTexSubImage2D()
to add some grey pixels in the middle of the texture. The texture IS correctly displayed (I can perfectly see these pixels at the right place), but the rest of the texture is only noisy artifacts (when it's not black).
Does this come from the fact that I use GL_FLOAT for a GL_RGBA texture? If yes, how can I, in GLSL, convert a uvec4 to vec4? The output of my main shader is a vec4, and I don't know how to convert the uvec4 output of a usampler2D texture to my final vec4.
Thank you for any answer you might provide :)
EDIT : I found the solution : I didn't clear the GL_COLOR_BUFFER_BIT between my 2 renders.
I know this question was self-answered, but a discussion need to be had about this:
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_FLOAT,NULL);
That does not create a floating-point texture. It creates a texture that contains normalized, unsigned integers.
The actual format of a texture is the third parameter; that defines what the texture actually contains. The last three parameters define how you are trying to upload data to the texture; if the pointer is NULL (and no PBO is bound), then the parameters mean nothing.
Basically, my program uses frame buffer object to render to a 3D texture.
If the 3D texture which I attach to fbo is in GL_RGB8 format, which is 24 bits per texel, there is no problem. Only 8-bits of them are used.
The problem happens when I try to use GL_ALPHA8 (8 bits per texel) as the internal format for the 3D texture, the rendering result is blank.
The cg fragment shader which I used to render to fbo looks like this:
void F_PureDecoder(
float3 vIndexCoord : TEXCOORD0,
out float color :COLOR)
{
... ...
color=float4(fL3,fL3,fL3,fL3);
}
Am I doing something wrong or fbo doesn't support to render to 8-bit texel texture? I am primarily unsure if the output format of fragment shader is correct. Coz the framebuffer is 8 bits but the output is 24 bits. Should I modify the output format from fragment shader? If so, what format should I use?
Thanks very much for any input!
To render to one/two component textures, you MUST use the GL_ARB_texture_rg extension, it will NOT work with any other format. See the extension specification for why it doesn't work:
It is also desirable to be able to render to one- and two-
component format textures using capabilities such as framebuffer
objects (FBO), but rendering to I/L/LA formats is under-specified
(specifically how to map R/G/B/A values to I/L/A texture channels).
So, use the GL_R8 internalFormat. To write to it, just write the full RGBA output, but only the R component will be written.