I am trying to implement shadow-mapping in my scene, but all I get is zeros in my fragment shader when I call texture() (I've tested it with == 0.0). My question: Am I sending the depth texture to the shader correctly?
Here is my fragment shader code:
bool getShadow() {
vec4 lightProjPositionScaled = lightProjPosition/lightProjPosition.w;
vec2 texCoords = lightProjPositionScaled.xy*0.5 + 0.5; // bias
return lightProjPositionScaled.z + 0.0005 > texture(shadowMap, texCoords).x;
}
Here is my relevant java codeInit (edited due to BDL's comment)
gl.glEnable(GL2.GL_TEXTURE_2D);
// generate stuff
IntBuffer ib = IntBuffer.allocate(1);
gl.glGenFramebuffers(1, ib);
frameBuffer = ib.get(0);
ib = IntBuffer.allocate(1);
gl.glGenTextures(1, ib);
shadowMap = ib.get(0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBuffer);
gl.glBindTexture(GL2.GL_TEXTURE, shadowMap);
gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_DEPTH_COMPONENT, 1024, 1024, 0, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, null);
gl.glDrawBuffer(GL2.GL_NONE);
gl.glReadBuffer(GL2.GL_NONE);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
// prevents 'shadow acne'
gl.glPolygonOffset(2.5f, 0);
// prevents multiple shadows
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
// prevents (or expects!!!) pixel-y textures
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST);
// store one value in all four components of pixel
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY);
Display (1st pass, for shadows):
// render shadows
gl.glUseProgram(shadowProgram);
gl.glUniformMatrix4fv(lightMatrixLocShadow, 1, false, lightMatrix.getMatrix(), 0); // yep (haha change viewMatrix -> lightMatrix)
gl.glUniformMatrix4fv(projMatrixLocShadow, 1, false, projMatrix.getMatrix(), 0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, sha.frameBuffer);
gl.glViewport(0, 0, 1024, 1024);
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
renderScene(gl, sunMatrix);
gl.glCopyTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_DEPTH_COMPONENT, 0, 0, 1024, 1024, 0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
Display (2nd pass, for rendering the scene):
// render display (regular)
gl.glUseProgram(displayProgram);
gl.glDrawBuffer(GL2.GL_FRONT);
gl.glReadBuffer(GL2.GL_FRONT);
gl.glUniformMatrix4fv(viewMatrixLoc, 1, false, viewMatrix.getMatrix(), 0);
gl.glUniformMatrix4fv(projMatrixLocDisplay, 1, false, projMatrix.getMatrix(), 0);
gl.glUniformMatrix4fv(lightMatrixLocDisplay, 1, false, lightMatrix.getMatrix(), 0);
gl.glUniform4fv(sunPositionLoc, 1, sunWorldPosition, 0); // send sun's position to shader
gl.glUniform1f(sunBrightnessLoc, sunBrightness);
gl.glUniform1i(shadowMapLoc, 0);
gl.glViewport(0, 0, screenWidth, screenHeight);
// day-night cycle
float[] color = SkyManager.getSkyColor(time);
gl.glClearColor(color[0], color[1], color[2], 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glActiveTexture(GL2.GL_TEXTURE0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, sha.shadowMap);
renderScene(gl, sunMatrix);
Another strange outcome is that only fragments on the z=0 plane relative to the light matrix (the light's rotating, and the plane rotates with it) are lit. All other fragments, behind and in front of the light, are shadowed.
One issue was with the line gl.glBindTexture(GL2.GL_TEXTURE, shadowMap);
I was binding the texture to GL_TEXTURE instead of GL_TEXTURE_2D.
Related
I'm writing a 3D game in Java using libGDX. In my game there's a model instance of a room which his walls are just rectangles. I'm tryimg to add an effect of "bullet holes" which are just a texture that appear on the wall when the player shoots at it. I'm trying to figure what the optimal way to implement it? The obvious way is just creating a model instance that built from a single rect with the hole texture for each bullet hole - but this way there will be a draw call for each one of these holes, which is not performance-wise AFAIK.
A piece of code which I create the walls:
Texture wallTexture = new Texture(Gdx.files.internal("wall.png"));
wallTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
Material wallMaterial = new Material(TextureAttribute.createDiffuse(wallTexture));
MeshPartBuilder meshBuilder = modelBuilder.part("walls", GL20.GL_TRIANGLES,
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal |
VertexAttributes.Usage.TextureCoordinates, wallMaterial);
meshBuilder.setUVRange(0, 0, C.ROOM_SIZE, 3);
corner00.set(C.ROOM_SIZE, 0, 0);
corner10.set(0, 0, 0);
corner11.set(0, 0, 6);
corner01.set(C.ROOM_SIZE, 0, 6);
normal.set(0, 1, 0);
line1000.setNormalDirection(auxVector2.set(0, 1).angle());
meshBuilder.rect(corner00, corner10, corner11, corner01, normal);
corner00.set(C.ROOM_SIZE, C.ROOM_SIZE, 0);
corner10.set(C.ROOM_SIZE, 0, 0);
corner11.set(C.ROOM_SIZE, 0, 6);
corner01.set(C.ROOM_SIZE, C.ROOM_SIZE, 6);
normal.set(-1, 0, 0);
line1110.setNormalDirection(auxVector2.set(-1, 0).angle());
meshBuilder.rect(corner00, corner10, corner11, corner01, normal);
corner00.set(0, C.ROOM_SIZE, 0);
corner10.set(C.ROOM_SIZE, C.ROOM_SIZE, 0);
corner11.set(C.ROOM_SIZE, C.ROOM_SIZE, 6);
corner01.set(0, C.ROOM_SIZE, 6);
normal.set(0, -1, 0);
line0111.setNormalDirection(auxVector2.set(0, -1).angle());
meshBuilder.rect(corner00, corner10, corner11, corner01, normal);
corner00.set(0, 0, 0);
corner10.set(0, C.ROOM_SIZE, 0);
corner11.set(0, C.ROOM_SIZE, 6);
corner01.set(0, 0, 6);
normal.set(1, 0, 0);
line0001.setNormalDirection(auxVector2.set(1, 0).angle());
meshBuilder.rect(corner00, corner10, corner11, corner01, normal);
Model levelModel = modelBuilder.end();
levelModelInstance = new ModelInstance(levelModel);
This part occurs only once upon loading the level. The bullet holes are supposed to appear in-game.
I am struggling to render smooth lines using GL_LINES.
I have borrowed the MultisampleConfigChooser from the following link: MultisampleConfigChooser.java
It seemed to find the multisample configuration without any errors.
Here is the code I use to render the lines on the screen:
GLES20.glUseProgram(this.lineDrawProgram);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(
mPositionHandle, 2,
GLES20.GL_FLOAT, false,
6*4, linesData);
linesData.position(2);
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(
mColorHandle, 4,
GLES20.GL_FLOAT, false,
6*4, linesData);
linesData.position(0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, matrix, 0);
GLES20.glDrawArrays(GLES20.GL_LINES, 0, this.numLines*2);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mColorHandle);
Blending is enabled with GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA.
One more mention is that I am drawing the lines to a texture which is bound to an FBO as a color attachment. I have not added any extra code to enable multisampling for the FBO.
Here is the code I use to setup the FBO and texture:
int[] fbo = new int[1];
int[] tex = new int[1];
enGLES20.glGenTextures(1, tex, 0);
GLES20.glGenFramebuffers(1, fbo, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGBA, this.width, this.height, 0,GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
GES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, tex[0], 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
The resulting lines still look like crap:
Please help me get these lines to look smooth.
BTW there are many different small lines in the screenshot, no curved lines or anything exotic.
I'm pretty new to OpenGL. I thought I understood FBOs, but I have trouble making them work.
My program draws to multisampled fbo basic graphical information (colorFbo).
From colorFbo I blit to postprocessFbo.
Then there's counterFbo with unsigned int values, where I simply fill silhouette of each object with object's id.
I'd like to postprocess the postprocessFbo and counterFbo, however, I don't see any effect of counterFbo... Where's the problem, please?
Here are parts my code:
Initialization:
colorFbo = new Framebuffer(true, false); //multisampled, rgba
counterFbo = new Framebuffer(false, true); //not MS, red
...seting polygonmode, viewport, depthtest, blending...
modelProgram = loadProgram("model");
counterProgram = loadProgram("counter");
...
postprocessProgram = loadProgram("postprocess");
...
postprocessFbo = new Framebuffer(false, false); //not MS, rgba
Render loop:
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbo());
Main.clear(0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
drawing objects using model program...
glBindFramebuffer(GL_FRAMEBUFFER, counterBuffer.fbo());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_MULTISAMPLE);
drawing objects using counter program...
blit colorFbo to postprocessFbo...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(postprocessProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, postprocessFbo.fboColorTexture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, counterFbo.fboColorTexture());
glBindVertexArray(screenQuadArray);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Counter fragment shader:
#version 330
out uint counter;
in vec3 vPosition;
uniform uint id;
void main() {
counter = id;
}
Postprocess fragment shader:
#version 330
uniform sampler2D colorTex;
uniform usampler2D counterTex;
out vec4 finalColor;
in vec2 texCoord;
void main() {
finalColor = texture(colorTex, vec2(tex));
uint id = texture(counterTex, vec2(tex)).s;
if (id > 0) {
finalColor = black;
}
}
Framebuffer constructor:
public Framebuffer(boolean multisampled, boolean redOnly) {
int internalFormat = redOnly ? GL_R32UI : GL_RGBA;
int format = redOnly ? GL_RED_INTEGER : GL_RGBA;
int dataType = redOnly ? GL_UNSIGNED_INT : GL_UNSIGNED_BYTE;
int interpolation = redOnly ? GL_NEAREST : GL_LINEAR;
int textureType = multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
// Prepare FBO textures
fboColorTexture = glGenTextures();
fboDepthStencilTexture = glGenTextures();
if (multisampled) {
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fboColorTexture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, SAMPLES, internalFormat, Main.width(), Main.height(), false);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fboDepthStencilTexture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, SAMPLES, GL_DEPTH24_STENCIL8, Main.width(), Main.height(), false);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
} else {
glBindTexture(GL_TEXTURE_2D, fboColorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, Main.width(), Main.height(), 0, format, dataType, (float[]) null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, interpolation);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, interpolation);
glBindTexture(GL_TEXTURE_2D, fboDepthStencilTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, Main.width(), Main.height(), 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, (float[]) null);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
}
fbo = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureType, fboColorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, textureType, fboDepthStencilTexture, 0);
glDrawBuffers(GL_COLOR_ATTACHMENT0);
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
System.err.println("Framebuffer not complete.");
System.exit(1);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
You seem to be missing assigning the texture unit to the texture name. So when I load textures I normally do this in the initialization ...
uColorTex = glGetUniformLocation(shaders.shaderProgram, "colorTex");
uCounterTex = glGetUniformLocation(shaders.shaderProgram, "counterTex");
... and when drawing ...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, postprocessFbo.fboColorTexture());
glUniform1i(uColourTex, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, counterFbo.fboColorTexture());
glUniform1i(uCounterTex, 1);
The issue was in counter program itself (in glVertexAttribPointer), which I didn't write about.
I needed only position in the counter program, so I wrote this:
glVertexAttribPointer(positionAttribLoc, 3, GL_FLOAT, false, FLOAT_VEC3_SIZE, 0);
But I forgot, that the data is always in the same position, so I can't "save space", because I'm only binding, the vertex data stays the same:
glVertexAttribPointer(positionAttribLoc, 3, GL_FLOAT, false, SIZEOF_MODEL_VERTEX, 0);
Thanks for the answers, and sorry I didn't show more code, I thought the issue could be anywhere and didn't want to overwhelm anyone reading with too much code.
I've seen references to this error before but no solution.
Where I am drawing the text, there is only a solid box of the specified color being drawn.
The code is like this:
TrueTypeFont font;
Font awtFont = new Font("Arial Unicode MS", Font.BOLD, 12); //name, style (PLAIN, BOLD, or ITALIC), size
font = new TrueTypeFont(awtFont, true); //base Font, anti-aliasing true/false
while (!Display.isCloseRequested() ) {
render();
font.drawString(10, 10, "ABC123", Color.black); //x, y, string to draw, color
//ENABLE THESE:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//RENDER LIKE THIS:
glPushMatrix();
bodyPosition = body.getPosition().mul(30);
glTranslatef(Position.x, Position.y, 0);
GL11.glDisable(GL11.GL_TEXTURE_2D);
glPopMatrix();
I am using bitblt to to capture a window. If the aero theme is enabled, The background of the captured image is black. If I disable the DWM and capture the window then the captured image is very good.
Here is part of my code.
HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(desktopDC);
HDC windowDC = User32.INSTANCE.GetDC(window);
HWND window= User32Extra.INSTANCE.FindWindow(null, "Start menu");
GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, desktopDC, 0, 0, WinGDIExtra.SRCCOPY );
GDI32Extra.INSTANCE.BitBlt(hdcMemDC,windowBounds.left, windowBounds.top, windowWidth, windowHeight, windowDC, windowBounds.left+windowBounds1.right-windowBounds.right+(windowExtraGap/2), windowBounds.top+windowBounds1.bottom-windowBounds.bottom+(windowExtraGap/2), WinGDIExtra.SRCCOPY);
How to capture the start Menu with proper background?
Are there any other methods to get the proper image of aero window?
use desktop DC and cut to window
RECT rc, rc2;
GetClientRect(hWnd, &rc);
GetWindowRect(hWnd, &rc2);
int width = rc2.right - rc2.left;
int height = rc2.bottom - rc2.top;
HDC hdcScreen = GetDC(NULL); //!!!! Get desktop DC
HDC hBmpFileDC = CreateCompatibleDC(hdcScreen);
HBITMAP hBmpFileBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBmpFileDC, hBmpFileBitmap);
BitBlt(hBmpFileDC, 0, 0, width, height, hdcScreen, rc2.left, rc2.top, SRCCOPY | CAPTUREBLT);
HGDIOBJ prev = SelectObject(hBmpFileDC, hOldBitmap);
SaveBitmap(szLogFilename, hBmpFileBitmap);
DeleteDC(hBmpFileDC);
DeleteObject(hBmpFileBitmap);
another variant
RECT rc;
GetClientRect(hWnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
HDC hdcScreen = GetDC(hWnd);
////////////////////////////
PrintWindow(hWnd, hdcScreen, 0);
PrintWindow(hWnd, hdcScreen, PW_CLIENTONLY);
////////////////////////////
HDC hBmpFileDC = CreateCompatibleDC(hdcScreen);
HBITMAP hBmpFileBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBmpFileDC, hBmpFileBitmap);
BitBlt(hBmpFileDC, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT);
HGDIOBJ prev = SelectObject(hBmpFileDC, hOldBitmap);
SaveBitmap(szLogFilename, hBmpFileBitmap);
DeleteDC(hBmpFileDC);
DeleteObject(hBmpFileBitmap);
before call any capture method I call PrintWindow. It acts window to redraw itself. And as a result screen capture will have correct picture. The most stable result I got with double call of PrintWindow.