I'm developing a 3d program with OpenGL 3.3. So far I managed to render many cubes and some spheres. I need to texture all the faces of all the cubes with a common texture except one face which should have a different texture. I tried with a single texture and everything worked fine but when I try to add another one the program seems to behave randomly.
My questions:
is there a suitable way of passing multiple textures to the shaders?
how am I supposed to keep track of faces in order to render the right texture?
Googling I found out that it could be useful to define vertices twice, but I don't really get why.
Is there a suitable way of passing multiple textures to the shaders?
You'd use glUniform1i() along with glActiveTexture(). Thus given your fragment shader has multiple uniform sampler2D:
uniform sampler2D tex1;
uniform sampler2D tex2;
Then as you're setting up your shader, you set the sampler uniforms to the texture units you want them associated with:
glUniform1i(glGetUniformLocation(program, "tex1"), 0)
glUniform1i(glGetUniformLocation(program, "tex2"), 1)
You then set the active texture to either GL_TEXTURE0 or GL_TEXTURE1 and bind a texture.
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, texture1)
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, texture2)
How am I supposed to keep track of faces in order to render the right texture?
It depends on what you want.
You could decide which texture to use based the normal (usually done with tri-planar texture mapping).
You could also have another attribute that decides how much to crossfade between the two textures.
color = mix(texture(tex1, texCoord), texture(tex2, texCoord), 0.2)
Like before, you can equally have a uniform float transition. This would allow you to fade between textures, making it possible to fade between slides like in PowerPoint, so to speak.
Try reading LearnOpenGL's Textures tutorial.
Lastly there's a minimum of 80 texture units. You can check specifically how many you have available using GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
You can use index buffers. Define the vertices once, and then use one index buffer to draw the portion of the mesh with the first texture, then use the second index buffer to draw the portion that needs the second texture.
Here's the general formula:
Setup the vertex buffer
Setup the shader
Setup the first texture
Setup and draw the index buffer for the part of the mesh that should use the first texture
Setup the second texture
Setup and draw the index buffer for the part of the mesh that should use the second texture.
Related
I'd like to access framebuffer to get RGB and change their values for each pixel. It is because the glReadPixels, and glDrawPixels are too slow to use, so that i should use shaders instead of using them.
Now, I write code, and success to display three-dimensional model using GLSL shaders.
I drew two cubes as follows.
....
glDrawArrays(GL_TRIANGLES, 0, 12*6);
....
and fragment shader :
varying vec3 fragmentColor;
void main()
{
gl_FragColor = vec4(fragmentColor, 1);
}
Then, how can I access to RGB values and change it?
For example, If the pixel values at (u1, v1) on window and (u2, v2) are (0,0,255), then I want to change them to (255,0,0)
With the exception of an OpenGL ES-only extension, fragment shaders cannot just read from the current framebuffer. Otherwise, we wouldn't need blending.
You also can't just render to the image you're reading from in a shader. So if you need to do some sort of post-processing, then that is best done by rendering to a separate image. That is, you do your rendering to image 1, then bind that as a texture and change the FBO so that you're rendering to image 2.
Alternatively, if you have access to OpenGL 4.5/ARB/NV_texture_barrier, then you can use texture barriers to handle this. This permits you a single read/modify/write pass, if you bind the current framebuffer's image as a texture. You'd issue the barrier before doing your read/modify/write, then bind that texture to a sampler while still rendering to that framebuffer.
Also, this requires that the FS read from the exact texel that it would write to. Assuming a viewport anchored at 0,0, the code for this would be texelFetch(sampler, ivec2(gl_FragCoord.xy), 0). You can't read from someone else's texel and modify it.
Obviously you must be rendering to a texture; you cannot use the default framebuffer for this.
Texture barrier could be used for cases where you read from different texels than you write to. But that would require doing something similar to the first case of switching bound images. Though you wouldn't need to change the FBO exactly; you could change the region of the FBO that you render to. That is, so long as you're reading from a different area than you're rendering to, and you use barriers appropriately when switching between those regions, everything is fine.
I have a functioning OpenGL ES 3 program (iOS), but I've having a difficult time understanding OpenGL textures. I'm trying to render several quads to the screen, all with different textures. The textures are all 256 color images with a sperate palette.
This is C++ code that sends the textures to the shaders
// THIS CODE WORKS, BUT I'M NOT SURE WHY
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->TextureId);
glUniform1i(_glShaderTexture, 1); // what does the 1 mean here
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->PaletteId);
glUniform1i(_glShaderPalette, 2); // what does the 2 mean here?
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
This is the fragment shader
uniform sampler2D texture; // New
uniform sampler2D palette; // A palette of 256 colors
varying highp vec2 texCoordOut;
void main()
{
highp vec4 palIndex = texture2D(texture, texCoordOut);
gl_FragColor = texture2D(palette, palIndex.xy);
}
As I said, the code works, but I'm unsure WHY it works. Several seemingly minor changes break it. For example, using GL_TEXTURE0, and GL_TEXTURE1 in the C++ code breaks it. Changing the numbers in glUniform1i to 0, and 1 break it. I'm guessing I do not understand something about texturing in OpenGL 3+ (maybe Texture Units???), but need some guidance to figure out what.
Since it's often confusing to newer OpenGL programmers, I'll try to explain the concept of texture units on a very basic level. It's not a complex concept once you pick up on the terminology.
The whole thing is motivated by offering the possibility of sampling multiple textures in shaders. Since OpenGL traditionally operates on objects that are bound with glBind*() calls, this means that an option to bind multiple textures is needed. Therefore, the concept of having one bound texture was extended to having a table of bound textures. What OpenGL calls a texture unit is an entry in this table, designated by an index.
If you wanted to describe this state in a C/C++ style notation, you could define the table of bound texture as an array of texture ids, where the size is the maximum number of bound textures supported by the implementation (queried with glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)):
GLuint BoundTextureIds[MAX_TEXTURE_UNITS];
If you bind a texture, it gets bound to the currently active texture unit. This means that the last call to glActiveTexture() determines which entry in the table of bound textures is modified. In a typical call sequence, which binds a texture to texture unit i:
glActiveTexture(GL_TEXTUREi);
glBindTexture(GL_TEXTURE_2D, texId);
this would correspond to modifying our imaginary data structure by:
BoundTextureIds[i] = texId;
That covers the setup. Now, the shaders can access all the textures in this table. Variables of type sampler2D are used to access textures in the GLSL code. To determine which texture each sampler2D variable accesses, we need to specify which table entry each one uses. This is done by setting the uniform value to the table index:
glUniform1i(samplerLoc, i);
specifies that the sampler uniform at location samplerLoc reads from table entry i, meaning that it samples the texture with id BoundTextureIds[i].
In the specific case of the question, the first texture was bound to texture unit 1 because glActiveTexture(GL_TEXTURE1) was called before glBindTexture(). To access this texture from the shader, the shader uniform needs to be set to 1 as well. Same thing for the second texture, with texture unit 2.
(The description above was slightly simplified because it did not take into account different texture targets. In reality, textures with different targets, e.g. GL_TEXTURE_2D and GL_TEXTURE_3D, can be bound to the same texture unit.)
GL_TEXTURE1 and GL_TEXTURE2 refer to texture units. glUniform1i takes a texture unit id for the second argument for samplers. This is why they are 1 and 2.
From the OpenGL website:
The value of a sampler uniform in a program is not a texture object,
but a texture image unit index. So you set the texture unit index for
each sampler in a program.
I am currently writing a 2d engine for a small game.
The idea was that I could render the whole scene in just one draw call. I thought I could render every 2d image on a quad which means that I could use instancing.
I imagined that my vertex shader could look like this
...
in vec2 pos;
in mat3 model;
in sampler2d tex;
in vec2 uv;
...
I thought I could just load a texture on the gpu and get a handle to it like I would do with a VBO, but it seems it is not that simple.
It seems that I have to call
glActiveTexture(GL_TEXTURE0..N);
for every texture that I want to load. Now this doesn't seem as easy to program as I thought. How do modern game engines render multiple textures?
I read that the texture limit of GL_TEXTURE is dependent on the GPU but it is at least 45. What if I want to render an image that consists of more than 45 textures for example 90?
It seems that I would have to render the first 45 textures and delete all the texture from the gpu and load the other 45 textures from the hdd to the gpu. That doesn't seem very reasonable to do every frame. Especially when I want to to animate a 2D image.
I could easily think that a simple animation of a 2d character could consist of 10 different images. That would mean I could easily over step the texture limit.
A small idea of mine was to combine multiple images in to one mega image and then offset them via uv coordinates.
I wonder if I just misunderstood how textures work in OpenGL.
How would you render multiple textures in OpenGL?
The question is somewhat broad, so this is just a quick overview of some options for using multiple textures in the same draw call.
Bind to multiple texture units
For this approach, you bind each texture to a different texture unit, using the typical sequence:
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, tex[i]);
In the shader, you can have either a bunch of separate sampler2D uniforms, or an array of sampler2D uniforms.
The main downside of this is that you're limited by the number of available texture units.
Array textures
You can use array textures. This is done by using the GL_TEXTURE_2D_ARRAY texture target. In many ways, a 2D texture array is similar to a 3D texture. It's basically a bunch of 2D textures stacked on top of each other, and stored in a single texture object.
The downside is that all textures need to have the same size. If they don't, you have to use the largest size for the size of the texture array, and you waste memory for the smaller textures. You'll also have to apply scaling to your texture coordinates if the sizes aren't all the same.
Texture atlas
This is the idea you already presented. You store all textures in a single large texture, and use the texture coordinates to control which texture is used.
While a popular approach, there are some technical challenges with this. You have to be careful at the seams between textures so that they don't bleed into each other when using linear sampling. And while this approach, unlike texture arrays, allows for different texture sizes without wasting memory, allocating regions within the atlas gets a little trickier with variable sizes.
Bindless textures
This is only available as an extension so far: ARB_bindless_texture.
You need to learn about the difference of texture units and texture objects.
Texture units are like "texture cartridges" of the OpenGL rasterizer. The rasterizer has a limited amount of "cartridge" slots (called texture units). To load a texture into a texture unit you first select the unit with glActiveTexture, then you load the texture "cartridge" (the texture object) using glBindTexture.
The amount of texture object you can have is only limited by your systems memory (and storage capabilities), but only a limited amount of textures can be "slotted" into the texture unit at the same time.
Samplers are like "taps" into the texture units. Different samplers within a shader may "tap" into the same texture unit. By setting the sampler uniform to a texture unit you select which unit you want to sample from.
And then you can also have the same texture "slotted" into multiple texture units at the same time.
Update (some clarification)
I read that the texture limit of GL_TEXTURE is dependent on the GPU but it is at least 45. What if I want to render an image that consists of more than 45 textures for example 90?
Normally you don't try to render the whole image with a single drawing call. It's practically impossible to catch all variations on which textures to use in what situation. Normally you write shaders for specific looks of a "material". Say you have a shader simulating paint on some metal. You'd have 3 textures: Metal, Paint and a modulating texture that controls where metal and where paint is visible. The shader would then have 3 sampler uniforms, one for each texture. To render the surface with that appearance you'd
select the shader program to use (glUseProgram)
for each texture activate in turn the texture unit (glActiveTexture(GL_TEXTURE_0+i) and bind the texture ('glBindTexture`)
set the sampler uniforms to the texture units to use (glUniform1i(…, i)).
draw the geometry.
I know there can be GL_MAX_TEXTURE_IMAGE_UNITS texture units in an OpenGL Program. But lets assume I am using only one.
Suppose I have 5 2D textures. Can I "map" them to a single texture unit (TEXTURE0) to render all of them.
I mean I will do this:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
//specify tex data and tex params for tex1
glBindTexture(GL_TEXTURE_2D, tex2);
//specify tex data and tex params for tex1
.. and so on for all 5 textures
Render Loop:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex1);
//draw
glBindTexture(GL_TEXTURE_2D, tex2);
//draw
..and so on for all 5 textures
In the fragment shader I am using only 1 sampler2d variable which is initialized to zero (for texture unit 0)
If this will not work correctly, then should I use 5 different texture units(TEXTURE0, TEXTURE0+1, ....TEXTURE0+5) and "map" each texture to a different texture unit.
Most important question: If my first approach is correct, how many 2D textures(lets just only talk about 2D textures for now) can I "map" to a Texture unit?
As long as you don't want to use several textures on a single piece of geometry simultanously, this is perfectly possible. Actually it's the usual thing to do, because the purpose of multitexturing and texture units is not to hold different textures for different objects, but different layers of textures used on the same object.
Think of texture units as something like layers in Photoshop.
Well, as I understand OpenGL texture units:
Text units are a way for shaders to point texture for sampling. If your shader must access more than one texture, you must separate them into differents texture units.
In your case, as you seem to need only 1 texture at the same time, glActiveTexture is useless, just let's Opengl use the default GL_TEXTURE0 for all.
So, yes, your render loop is correct.
How many is the limit of texture units? 48+, more than enough!
Note:
Remember that OpenGL is a state machine, so to configure more than 1 texture to work at the same time, you need a way to select them, that is exactly what glActiveTexture do.
I hope it will help you.
I am working with "render to texture" feature using FBOs and textures attached.
My problem is that in the fragment shader i don't know how to write to an specific row of the 2D-texture. I do have the information of which row (indicated by a uniform float variable), but i dont know how to draw just there.
Is this possible? Or what is a good way to know where am i in the fragment shader?
My global idea is to render the evolution of a 1D-texture into a 2D-texture from top to bottom. Each evolution step is computed by a fragment shader (usiong render to texture ping-pong method, with 2 FBOs)
You can use discard; in the fragment shader to throw away fragments you don't want. Something like
if (gl_FragCoord.y != row_to_keep)
discard;
Then render your scene normally, and you'll end up with just one row of the output written.
I think the fragment shader is not the place for this.
If you only want to write into a single line of the FBO, can't you set the vertices of your draw call to only overlap the pixels you want to draw?