Issue when updating stencil buffer in OpenGL - c++

I'm having issues when drawing using the stencil test in OpenGL on mac. When I first draw the scene, the stencil works fine. I draw a semi-transparent black rectangle in the middle, with writing to the stencil buffer enabled, and then a larger blue rectangle with writing to the stencil buffer disabled. I get the right result when the window first pops up, which looks like this:
However, when I resize the window, and the rendering function gets called again, I get a result which looks like:
or
Sometimes the weird white space follows the middle rectangle, other times the white snaps between seemingly random arrangements, but keeps those arrangements when you go back to that window size. I can find no solution to this online. Here is my render function, which is called any time that the window is resized:
glClearColor(0, 0, 0, 1);
glClearStencil(0x00);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Replace data in the stencil buffer with 1s if it passes the test
// which should be GL_ALWAYS
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// Allow data to be written to the stencil buffer.
glStencilMask(0xFF);
p->fillSquare(1, 1, 1, 0.3, -0.25, 0.25, 0.25, 0.25, -0.25, -0.25, 0.25, -0.25); // Write a semi transparent black rectangle
glStencilMask(0x00); // Disable writing to the stencil buffer.
glStencilFunc(GL_NOTEQUAL, 1, 0xFF); // Only draw if stencil value is 1.
// Draw blue rectangle
p->fillSquare(0.60, 0.60, 0.80, 1, -0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5);
glfwSwapBuffers(w);
In case you want to know, p->fillRect() takes four floats for RGBA color of the rectangle and then the x and y coordinate of each vertex.
It seems like there may be some kind of issue in clearing the stencil, but I really can't be sure. I do have the stencil test turned on in my OpenGL initialization function.
If you need to know anything else about the other aspects of my code or system, feel free to comment.
Note: I am not using the OpenGL's depth, so it's okay to not be clearing the depth buffer (I've tested this).

The clearing of the stencil buffer does indeed not work (except for the very first time that funtion is called) as you might expect it.
What you missed is that the glStencilMask will also affect glClear(... | GL_STENCIL_BUFFER_BIT).
You should move the glStencilMask(0xFF) up a bit, before doing the clear call.

Related

How does gl_FragColor affect the stencil buffer?

I have set up my operations to draw to the stencil buffer, similar to the following:
void onDisplay() {
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glStencilFunc(GL_NEVER, 1, 0xFF);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
// Draw to stencil buffer
glStencilMask(0xFF);
glClear(GL_STENCIL_BUFFER_BIT); // needs mask=0xFF
draw_circle();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glStencilMask(0x00);
// draw where stencil's value is 0
glStencilFunc(GL_EQUAL, 0, 0xFF);
/* (nothing to draw) */
// draw only where stencil's value is 1
glStencilFunc(GL_EQUAL, 1, 0xFF);
draw_scene();
glDisable(GL_STENCIL_TEST);
}
Now, if I have the following fragment shader enabled when I call draw_circle() (above):
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
How will the values of the stencil buffer differ from if I were to use the following fragment shader?
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
In other words, I'm wondering how the output of the fragment shader affects the stencil buffer when drawing to the stencil buffer.
Edit:
The point of my question is to correct some misunderstandings I know I have regarding the stencil buffer. One example I have that I think explains the stencil buffer fairly well is [1]. Here, the following is mentioned:
The glColorMask function allows you to specify which data is written to the color buffer during a drawing operation. In this case you would want to disable all color channels (red, green, blue, alpha). Writing to the depth buffer needs to be disabled separately as well with glDepthMask, so that cube drawing operation won't be affected by leftover depth values of the rectangle. This is cleaner than simply clearing the depth buffer again later.
So, it seems from this page, that, in order to write to the stencil buffer, one needs to enable/disable the appropriate modes (i.e. color and depth), and then go through the entire rasterization process, which will only write to the stencil buffer. Since the rasterization process includes the fragment shader, is the output of the fragment shader (i.e. gl_FragColor) simply ignored? How can I tell GL what to write to the stencil buffer position (x, y)?
[1] : https://open.gl/depthstencils
Unless you have access to AMD/ARB_shader_stencil_export, the fragment shader cannot directly affect the output to the stencil buffer. The only exception to this is discarding the fragment.
And according to this database, only AMD cards provide this extension. Also, that extension exposes an output specifically for the stencil. It modifies the stencil value of the fragment; the color values of the fragment never affect the fragment's stencil value.

See-through window using OpenGL stencil buffer [duplicate]

I'm having issues when drawing using the stencil test in OpenGL on mac. When I first draw the scene, the stencil works fine. I draw a semi-transparent black rectangle in the middle, with writing to the stencil buffer enabled, and then a larger blue rectangle with writing to the stencil buffer disabled. I get the right result when the window first pops up, which looks like this:
However, when I resize the window, and the rendering function gets called again, I get a result which looks like:
or
Sometimes the weird white space follows the middle rectangle, other times the white snaps between seemingly random arrangements, but keeps those arrangements when you go back to that window size. I can find no solution to this online. Here is my render function, which is called any time that the window is resized:
glClearColor(0, 0, 0, 1);
glClearStencil(0x00);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Replace data in the stencil buffer with 1s if it passes the test
// which should be GL_ALWAYS
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// Allow data to be written to the stencil buffer.
glStencilMask(0xFF);
p->fillSquare(1, 1, 1, 0.3, -0.25, 0.25, 0.25, 0.25, -0.25, -0.25, 0.25, -0.25); // Write a semi transparent black rectangle
glStencilMask(0x00); // Disable writing to the stencil buffer.
glStencilFunc(GL_NOTEQUAL, 1, 0xFF); // Only draw if stencil value is 1.
// Draw blue rectangle
p->fillSquare(0.60, 0.60, 0.80, 1, -0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5);
glfwSwapBuffers(w);
In case you want to know, p->fillRect() takes four floats for RGBA color of the rectangle and then the x and y coordinate of each vertex.
It seems like there may be some kind of issue in clearing the stencil, but I really can't be sure. I do have the stencil test turned on in my OpenGL initialization function.
If you need to know anything else about the other aspects of my code or system, feel free to comment.
Note: I am not using the OpenGL's depth, so it's okay to not be clearing the depth buffer (I've tested this).
The clearing of the stencil buffer does indeed not work (except for the very first time that funtion is called) as you might expect it.
What you missed is that the glStencilMask will also affect glClear(... | GL_STENCIL_BUFFER_BIT).
You should move the glStencilMask(0xFF) up a bit, before doing the clear call.

How Can I use glClipPlane more than 6 times in OPENGL?

I have a Sphere . I would like to clip some planes like below picture. I need more than 10 clipping plane but maximum glClipPlane limit is 6. How can I solve this problem.
My Sample Code below;
double[] eqn = { 0.0, 1.0, 0.0, 0.72};
double[] eqn2 = { -1.0, 0.0, -0.5, 0.80 };
double[] eqnK = { 0.0, 0.0, 1.0, 0.40 };
/* */
Gl.glClipPlane(Gl.GL_CLIP_PLANE0, eqn);
Gl.glEnable(Gl.GL_CLIP_PLANE0);
/* */
Gl.glClipPlane(Gl.GL_CLIP_PLANE1, eqn2);
Gl.glEnable(Gl.GL_CLIP_PLANE1);
Gl.glClipPlane(Gl.GL_CLIP_PLANE2, eqnK);
Gl.glEnable(Gl.GL_CLIP_PLANE2);
//// draw sphere
Gl.glColor3f(0.5f, .5f, 0.5f);
Glu.gluSphere(quadratic, 0.8f, 50, 50);
Glu.gluDeleteQuadric(quadratic);
Gl.glDisable(Gl.GL_CLIP_PLANE0);
Gl.glDisable(Gl.GL_CLIP_PLANE1);
Gl.glDisable(Gl.GL_CLIP_PLANE2);
You should consider multi-pass rendering and the stencil buffer.
Say you need 10 user clip-planes and you are limited to 6, you can setup the first 6, render the scene into the stencil buffer and then do a second pass with the remaining 4 clip planes. You would then use the stencil buffer to reject parts of the screen that were clipped on the prior pass. So this way you get the effect of 10 user clip planes when the implementation only supports 6.
// In this example you want 10 clip planes but you can only do 6 per-pass,
// so you need 1 extra pass.
const int num_extra_clip_passes = 1;
glClear (GL_STENCIL_BUFFER_BIT);
// Disable color and depth writes for the extra clipping passes
glDepthMask (GL_FALSE);
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Increment the stencil buffer value by 1 for every part of the sphere
// that is not clipped.
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
glStencilFunc (GL_ALWAYS, 1, 0xFFFF);
// Setup Clip Planes: 0 through 5
// Draw Sphere
// Reject any part of the sphere that did not pass _all_ of the clipping passes
glStencilFunc (GL_EQUAL, num_extra_clip_passes, 0xFFFF);
// Re-enable color and depth writes
glDepthMask (GL_TRUE);
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Setup Leftover Clip Planes
// DrawSphere
It is not perfect, it is quite fill-rate intensive and limits you to a total of 1536 clip planes (given an 8-bit stencil buffer), but it will get the job done without resorting to features present only in GLSL 130+ (namely gl_ClipDistance []).
You can just reuse "Gl.glEnable(Gl.GL_CLIP_PLANE1);" because you was disabled it later ...

Creating and blending a dynamic texture in OpenGL

I need to render a sphere to a texture (done using a Framebuffer Object (FBO)), and then alpha blend that texture with the back buffer. So far I'm not doing any processing with the texture except clearing it at the beginning of every frame.
I should say that my scene consists of nothing but a planet in empty space, the sphere should appear next to or around the planet (kind of like a moon for now). When I render the sphere directly to the back buffer, it displays correctly; but when I do the intermediary step of rendering it to a texture and then blending that texture with the back buffer, the sphere only shows up when it is in front of the planet, the part that isn't in front is just "cut off":
I render the sphere using glutSolidSphere to a RGBA8 fullscreen texture that's bound to an FBO, making sure that every sphere pixel receives an alpha value of 1.0. I then pass the texture to a fragment shader program, and use this code to render a fullscreen quad - with the texture mapped onto it - to the backbuffer while alpha blending:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glTexCoord2i(0, 1);
glVertex3i(-1, 1, -1); // TOP LEFT
glTexCoord2i(0, 0);
glVertex3i(-1, -1, -1); // BOTTOM LEFT
glTexCoord2i(1, 0);
glVertex3i( 1, -1, -1); // BOTTOM RIGHT
glTexCoord2i(1, 1);
glVertex3i( 1, 1, -1); // TOP RIGHT
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
This is the shader code (taken from an FX file written in Cg):
sampler2D BlitSamp = sampler_state
{
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
float4 blendPS(float2 texcoords : TEXCOORD0) : COLOR
{
float4 outColor = tex2D(BlitSamp, texcoords);
return outColor;
}
I don't even know whether this is a problem with the depth buffer or with alpha blending, I've tried a lot of combinations of enabling and disabling depth testing (with a depth buffer attached to the FBO) and alpha blending.
EDIT: I tried just rendering a blank fullscreen quad straight to the back buffer and even that was cropped around the planet's edges. For some reason, enabling depth testing for rendering the quad (that is, removing the lines glDisable(GL_DEPTH_TEST) and glEnable(GL_DEPTH_TEST) in the code above) got rid of the problem, but now everything but the planet and the sphere appears white:
I made sure (and could confirm) that the alpha channel of the texture is 0 at every pixel but the sphere's, so I don't understand where the whiteness could be introduced. (Would also still be interested in an explanation why enabling depth testing has this effect.)
I see two possible sources of error here:
1. Rendering to the FBO
If the missing pixels are not even present in the FBO after rendering, there must be some mechanism which discarded the corresponding fragments. The OpenGL pipeline includes four different types of fragment tests which can lead to fragments being discarded:
Scissor Test: Unlikely to be the cause, as the scissor test only affects a rectangular portion of the screen.
Alpha Test: Equally unlikely, as your fragments should all have the same alpha value.
Stencil Test: Also unlikely, unless you use stencil operations when drawing the background planet and copy over the stencil buffer from the back buffer to the FBO.
Depth Test: Same as for stencil test.
So there's a good chance that rendering into FBO is not the issue here. But just to be absolutely sure, you should read back your color attachment texture and dump it into a file for inspection. You can use the following function for that:
void TextureToFile(GLuint texture, const char* filename) {
glBindTexture(GL_TEXTURE_2D, texture);
GLint width, height;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
std::vector<GLubyte> pixels(3 * width * height);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
std::ofstream out(filename, std::ios::out | std::ios::binary);
out << "P6\n"
<< width << '\n'
<< height << '\n'
<< 255 << '\n';
out.write(reinterpret_cast<const char*>(&pixels[0]), pixels.size());
}
The resulting file is a portable pixmap (.ppm). Be sure to unbind the FBO before reading back the texture.
2. Texture mapping
Assuming rendering into the FBO works as expected, the only other source of error is blending the texture over the previously rendered scene. There are two scenarios:
a) Fragments get discarded
The possible reasons for fragments to get discarded are the same as in 1.:
Scissor Test: Nope, affects rectangular areas only.
Alpha Test: Probably not, the texels covered sphere should all have the same alpha value.
Stencil Test: Might be the cause if you use stencil operations/stencil testing when drawing the background planet and the old stencil state is still active.
Depth Test: Might be the cause, but as you already disable it, it really shouldn't have any effect.
So you should make sure that all of these tests are disabled, especially the stencil test.
b) Wrong results from blending
Assuming all fragments reach the back buffer, blending is the only thing which could still cause the wrong result. With your blending function (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) the values in the back buffer are irrelevant for blending, and we assume that the alpha values in the texture are correct. So I see no reason for why blending should be the root cause here.
Conclusion
In conclusion, the only sensible cause for the observed result seems to be stencil testing. If it's not, I'm out of options :)
I solved it or at least came up with a work around.
First off, the whiteness stems from the fact that glClearColor had been set to glClearColor(1.0f, 1.0f, 1.0f, 1000.0f), so everything but the planet wasn't even written to in the end. I now copy the contents of the back buffer (which is the planet, the atmosphere, and the space around it) to the texture before rendering the sphere, and I render the atmosphere and space before that copy/blit operation, so they are included in it. Previously, everything but the planet itself was rendered after my quad, which - when using depth testing - apparently placed everything behind the quad, making it invisible.
The reference implementation of the effect I'm trying to achieve has always used this kind of blit operation in its code but I didn't think it was necessary for the effect. Now I feel like there might be no other way...

Mask part of a texture on draw with OpenGL in a fixed pipeline

I am trying to figure out the best way to mask of sections of a texture when they ar drawn. My issue comes in the fact that I seem to have run our of alpha masks!
We are using openGL to draw a custom built 2D game engine. The game is built up off of sprites and simple block textures.
My desired outcome is like this:
A character sprite is drawn in place (using it's alpha color to not just be a box)
An item is drawn into the players hand (also using it's alpha color to draw into the scene without being a box)
The item should appear behind the characters arm/hand, but above the rest of the body.
For the moment the only way I can figure out how to accomplish this, is by drawing them in order (Body, Item, Arm) but I would like to avoid this to make art assets a bit easier to deal with. My idea solution would be to draw the character, then draw the item with an alpha mask that blocks out areas of the texture that should be "under" the arm.
Other solutions that I have seen are like this, where the glBlendFuncSeparate() function is used. I am trying to avoid bringing in extensions, as my current version of OpenGL doesn't support it. Not to say that I am opposed to the idea, but it seems a bit of a handle to brig it in just to draw an alpha mask?
I fully admit that this is a learning process for me, and I am using it as an excuse to really see how OpenGL handles. Any suggestions as to where I should head to get this to draw correctly? Is there a way for OpenGL in the fixed pipeline to take a texture, apply an alpha mask on top of it, and THEN draw it into the buffer? Should I give in and separate my character into several parts of its model?
[UPDATE: 8/12/12]
Tried to add the code suggested by Tim, but I seem to be having an issue. When I enable the stencil buffer, everything just gets blocked out, NOT just what I wanted. Here is my test example code.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glStencilFunc(GL_ALWAYS, 0,0);
// Draw our blocking poly
glBegin(GL_POLYGON);
glVertex2f( 50, 50 );
glVertex2f( 50, 50+128 );
glVertex2f( 50+128, 50+128 );
glEnd();
glStencilFunc(GL_GREATER, 0, -1);
glEnable(GL_STENCIL_TEST);
// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Enable use of textures
glEnable(GL_TEXTURE_2D);
// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);
// Draw the box with colors
glBegin(GL_QUADS);
glTexCoord2d( 0, 0 ); glVertex2f( 50, 50 );
glTexCoord2d( 0, 1 ); glVertex2f( 50, 50+128 );
glTexCoord2d( 1, 1 ); glVertex2f( 50+128, 50+128 );
glTexCoord2d( 1, 0 ); glVertex2f( 50+128, 50 );
glEnd();
// Swap buffers and display!
SDL_GL_SwapBuffers();
Just to be clear, here is my init code as well to set this system up.
When the code is run with stencil disabled, I get this:
When I use glEnable(GL_STENCIL_TEST), I get this:
I've tried playing around with various options, but I cannot see a clear reason why my stencil buffer is blocking everything.
[Update#2 8/12/12]
We got some working code, Thanks tim! Here is what I ended up running to work correctly.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
glEnable(GL_STENCIL_TEST);
// Draw our blocking poly
glBegin(GL_POLYGON);
glVertex2f( 50, 50 );
glVertex2f( 50, 50+128 );
glVertex2f( 50+128, 50+128 );
glEnd();
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Enable use of textures
glEnable(GL_TEXTURE_2D);
// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);
// Draw the box with colors
glBegin(GL_QUADS);
glTexCoord2d( 0, 0 ); glVertex2f( 50, 50 );
glTexCoord2d( 0, 1 ); glVertex2f( 50, 50+128 );
glTexCoord2d( 1, 1 ); glVertex2f( 50+128, 50+128 );
glTexCoord2d( 1, 0 ); glVertex2f( 50+128, 50 );
glEnd();
glDisable(GL_STENCIL_TEST);
// Swap buffers and display!
SDL_GL_SwapBuffers();
Here's my idea for the situation where you have one texture and one alpha mask:
Draw the character onto the scene like normal.
Lock the RGB color channels so that it cannot be changed with glColorMask
Setup the stencil buffer with glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glStencilFunc(GL_ALWAYS, 0,0);
Draw the alpha mask with alpha testing enabled. This will increment the stencil buffer anywhere the alpha test passes (you may have to flip this based on your mask polarity)
At this point, you have a character texture in the framebuffer, and a mask outline in the stencil buffer.
Reenable the color channels with glColorMask
Setup the stencil buffer for the weapon with glStencilFunc(GL_GREATER, 0, -1); This will only draw the weapon texels where the stencil buffer is greater than zero, and reject pixels where the stencil is not updated.
Draw the weapon texture as normal.
Tim was pretty clear in his comment, but I want to present you the solution I find the most intuitive. It's 3D, so hold on... ;)
Basically, you can just use the Z coordinate of your images to create virtual "layers". It then doesnt' matter, in which order you draw them. Just alphatest every image individually, and draw it on correct Z value. If it still isn't enough, you could use separate texture containing "depth" of every pixel, and then use the 2nd texture to perform some sort of depth-testing.
Be sure to call glEnable(GL_DEPTH_TEST); if you want to use this approach.
As I see it, the problem is that you have one texture, but part of it represents the arm and part of it the rest of the character. The issue is that you want to draw the weapon over the character, but draw the arm over both.
This means, while drawing two objects, you want to put them into three different "layers". This fundamentally doesn't make sense, so you're kind of stuck.
Here's an idea though: use a fragment program (i.e., a shader).
I suggest you overload the character's texture's alpha channel to encode both transparency and layer. For example, let's use 0=transparent body, 64=opaque body, 128=transparent arm, 255=opaque arm.
From here, you draw your objects, but conditionally set the depth of your objects into three layers. Basically, you write a fragment program that draws your character into two different layers, the character gets pushed backward while the arm gets pulled forward. When the weapon is drawn, it is drawn without a shader, but it's tested against the characters' pixels' depths. It works something like this (untested, obviously).
Define a shader my_shader, which contains a fragment program:
uniform sampler2D character_texture;
void main(void) {
vec4 sample = texture2D(character_texture,gl_TexCoord[0].st);
int type; //Figure out what type of character texel we're looking at
if (fabs(sample.a-0.00)<0.01) type = 0; //transparent body
else if (fabs(sample.a-0.25)<0.01) type = 1; //opaque body
else if (fabs(sample.a-0.50)<0.01) type = 2; //transparent arm
else if (fabs(sample.a-1.00)<0.01) type = 3; //opaque arm
//Don't draw transparent pixels.
if (type==0 || type==2) discard;
gl_FragColor = vec4(sample.rgb,1.0);
//Normally, you (can) write "gl_FragDepth = gl_FragCoord.z". This
//is how OpenGL will draw your weapon. However, for the character,
//we alter that so that the arm is closer and the body is farther.
//Move body farther
if (type==1) gl_FragDepth = gl_FragCoord.z * 1.1;
//Move arm closer
else if (type==3) gl_FragDepth = gl_FragCoord.z * 0.9;
}
Here's some pseudocode for your draw function:
//...
//Algorithm to draw your character
glUseProgram(my_shader);
glBindTexture(GL_TEXTURE_2D,character.texture.texture_gl_id);
glUniform1i(glGetUniformLocation(my_shader,"character_texture"),1);
character.draw();
glUseProgram(0);
//Draw your weapon
glEnable(GL_DEPTH_TEST);
character.weapon.draw();
glDisable(GL_DEPTH_TEST);
//...