Jump to content
  • Advertisement

Niruz91

Member
  • Content Count

    11
  • Joined

  • Last visited

Community Reputation

205 Neutral

About Niruz91

  • Rank
    Member

Personal Information

  • Interests
    Art
    Business
    Programming
    QA
  1. Thanks for the replies! Apparently yes it was because of GL_TRIANGLE_STRIP instead of GL_TRIANGLES, I think it must've auto corrected and then I didn't even think twice but now it works like it should. Man I feel so stupid but thanks for the help
  2. I've been trying to get font rendering to work, and I got the atlas to work, but when I render the text I end up with this:       Basically whenever I render more than one character from the Atlas it becomes messed up, I've checked if the offset is wrong and it seems to be fine and the texture coordinates are aligned with the vertex positions. I'm really not sure what might be wrong, here's the complete code: #define MAX_WIDTH 1024 namespace FontFactory { struct FreeTypeFontCharacter { GLfloat mAdvanceX; // advance: the horizontal advance e.g. the horizontal distance (in 1/64th pixels) from the origin to the origin of the next glyph. Accessed via face->glyph->advance.x. GLfloat mAdvanceY; // same as above but for Y GLfloat mBitmapWidth; // width: the width (in pixels) of the bitmap accessed via face->glyph->bitmap.width. GLfloat mBitmapHeight; // height: the height (in pixels) of the bitmap accessed via face->glyph->bitmap.rows. GLfloat mBitmapLeft; // bearingX: the horizontal bearing e.g. the horizontal position (in pixels) of the bitmap relative to the origin accessed via face->glyph->bitmap_left. GLfloat mBitmapTop; // bearingY: the vertical bearing e.g. the vertical position (in pixels) of the bitmap relative to the baseline accessed via face->glyph->bitmap_top. GLfloat mUVOffsetX; GLfloat mUVOffsetY; }; struct FreeTypeTextureAtlas { FreeTypeTextureAtlas(FT_Face& face, int height, GLuint tUniform) { //Font = Face //Glyph = Character FT_Set_Pixel_Sizes(face, 0, height); FT_GlyphSlot glyphSlot = face->glyph; float rowWidth = 0; float rowHeight = 0; mWidth = 0; mHeight = 0; memset(mCharacters, 0, sizeof(mCharacters)); for (int i = 32; i < 128; i++) { if (FT_Load_Char(face, i, FT_LOAD_RENDER)) { std::cout << "Loading character %c failed \n", i; continue; } if (rowWidth + glyphSlot->bitmap.width + 1 >= MAX_WIDTH) { mWidth = std::fmax(mWidth, rowWidth); mHeight += rowHeight; rowWidth = 0; rowHeight = 0; } rowWidth += glyphSlot->bitmap.width + 1; rowHeight = std::fmax(rowHeight, glyphSlot->bitmap.rows); } mWidth = std::fmax(mWidth, rowWidth); mHeight += rowHeight; glGenTextures(1, &mTextureID); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mTextureID); glUniform1i(tUniform, 0); mTextureUniform = tUniform; glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, mWidth, mHeight, 0, GL_RED, GL_UNSIGNED_BYTE, 0); //glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 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_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); float ox = 0; float oy = 0; for (int i = 32; i < 128; i++) { if (FT_Load_Char(face, i, FT_LOAD_RENDER)) continue; if (ox + glyphSlot->bitmap.width + 1 >= MAX_WIDTH) { oy += rowHeight; rowHeight = 0; ox = 0; } glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, glyphSlot->bitmap.width, glyphSlot->bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, glyphSlot->bitmap.buffer); mCharacters[i].mAdvanceX = glyphSlot->advance.x >> 6; mCharacters[i].mAdvanceY = glyphSlot->advance.y >> 6; mCharacters[i].mBitmapWidth = glyphSlot->bitmap.width; mCharacters[i].mBitmapHeight = glyphSlot->bitmap.rows; mCharacters[i].mBitmapLeft = glyphSlot->bitmap_left; mCharacters[i].mBitmapTop = glyphSlot->bitmap_top; mCharacters[i].mUVOffsetX = ox / (GLfloat)mWidth; mCharacters[i].mUVOffsetY = oy / (GLfloat)mHeight; rowHeight = std::fmax(rowHeight, glyphSlot->bitmap.rows); ox += glyphSlot->bitmap.width + 1; } } ~FreeTypeTextureAtlas() { glDeleteTextures(1, &mTextureID); } GLfloat mWidth; GLfloat mHeight; GLuint mTextureID; GLuint mTextureUniform; FreeTypeFontCharacter mCharacters[128]; GLuint mDepth; }; class TextRenderer { public: FT_Library library; FT_Face face; FreeTypeTextureAtlas* a48; FreeTypeTextureAtlas* a24; FreeTypeTextureAtlas* a12; GLuint vbo; GLuint vao; GLfloat m_posUV; GLuint m_colorIN; GLuint m_texture; int Initialize(Shader& shader) { if (FT_Init_FreeType(&library)) { std::cout << "Could not Initialize freetype library.\n"; return 0; } if (FT_New_Face(library, "arialbd.ttf", 0, &face)) { std::cout << "Could not open font arialbd.ttf\n"; return 0; } m_colorIN = shader.getUniformLocation("inputColor"); m_texture = shader.getUniformLocation("texture"); glGenBuffers(1, &vbo); glGenVertexArrays(1, &vao); a48 = new FreeTypeTextureAtlas(face, 48, m_texture); a24 = new FreeTypeTextureAtlas(face, 24, m_texture); a12 = new FreeTypeTextureAtlas(face, 12, m_texture); } void Render(Shader& shader, GLfloat inwidth, GLfloat inheight) { float sx = 2.0 / inwidth; float sy = 2.0 / inheight; RenderText("JJJ", a48, -1 + 9.5 * sx, 1 - 190.5 * sy, sx, sy, shader); RenderText("o", a48, -1 + 18.5 * sx, 1 - 230.5 * sy, sx, sy, shader); RenderText("x x x", a48, -1 + 26.5 * sx, 1 - 270.5 * sy, sx, sy, shader); } void RenderText(const char* text, FreeTypeTextureAtlas* atlas, float x, float y, float sx, float sy, Shader& shader) { shader.bindShader(); const unsigned char* p; std::vector<glm::vec4> coords; float lastx2 = 0; float lasty2 = 0; float lastw = 0; float lasth = 0; int counter = 0; for (p = (const unsigned char*)text; *p; p++) { unsigned char test = *p; float x2 = x + atlas->mCharacters[*p].mBitmapLeft * sx; float y2 = -y - atlas->mCharacters[*p].mBitmapTop * sy; float w = atlas->mCharacters[*p].mBitmapWidth * sx; float h = atlas->mCharacters[*p].mBitmapHeight * sy; x += atlas->mCharacters[*p].mAdvanceX * sx; y += atlas->mCharacters[*p].mAdvanceY * sy; if ((lastx2 == x2) || (lasty2 == y2) || (lastw == w) || (lasth == h)) counter++; lastx2 = x2; lasty2 = y2; lastw = w; lasth = h; if (!w || !h) continue; coords.push_back( //1 glm::vec4( x2, -y2, atlas->mCharacters[*p].mUVOffsetX, atlas->mCharacters[*p].mUVOffsetY) ); coords.push_back( // 2 glm::vec4( x2 + w, -y2, atlas->mCharacters[*p].mUVOffsetX + (atlas->mCharacters[*p].mBitmapWidth / atlas->mWidth), atlas->mCharacters[*p].mUVOffsetY) ); coords.push_back( // 3 glm::vec4( x2, -y2 - h, atlas->mCharacters[*p].mUVOffsetX, atlas->mCharacters[*p].mUVOffsetY + (atlas->mCharacters[*p].mBitmapHeight / atlas->mHeight)) ); coords.push_back( // 4 glm::vec4( x2 + w, -y2, atlas->mCharacters[*p].mUVOffsetX + (atlas->mCharacters[*p].mBitmapWidth / atlas->mWidth), atlas->mCharacters[*p].mUVOffsetY) ); coords.push_back( // 5 glm::vec4( x2, -y2 - h, atlas->mCharacters[*p].mUVOffsetX, atlas->mCharacters[*p].mUVOffsetY + (atlas->mCharacters[*p].mBitmapHeight / atlas->mHeight)) ); coords.push_back( // 6 glm::vec4( x2 + w, -y2 - h, atlas->mCharacters[*p].mUVOffsetX + (atlas->mCharacters[*p].mBitmapWidth / atlas->mWidth), atlas->mCharacters[*p].mUVOffsetY + (atlas->mCharacters[*p].mBitmapHeight / atlas->mHeight)) ); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glActiveTexture(GL_TEXTURE0); glUniform1i(atlas->mTextureUniform, 0); glBindTexture(GL_TEXTURE_2D, atlas->mTextureID); shader.setUniform4f("inputColor", glm::vec4(0, 1, 0, 1)); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, coords.size() * sizeof(glm::vec4), coords.data(), GL_DYNAMIC_DRAW); glBindVertexArray(vao); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)0); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, coords.size()); glDisableVertexAttribArray(0); shader.unbindShader(); } }; } It's based off this link https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02 but I can't quite get it right, has anyone had this result before?
  3. Thanks for the replies!      The only reason I changed that was because I noticed that the depth maps were flipped when I used min/max.x and min/max.y.      There might be, the bottom left depth map look like a cube when I use the x values for all the corners and rectangular when I use the x and y values like this:         This might be the case, but the radius is always the same in world space, and then the points get projected to light space so they're different and since I use the light space coordinates for the bounding box they should be inequal?      And I'm pretty bad at explaining things but what I was getting at with the videos is that. In the first video the camera looks along the negative Z axis, so when I move right to left I move along the X axis. Which means that the depth map also moves left to right along the X axis.   However if I rotate the camera 45 degrees like in the second video, if I then move left and right I now move along the Z axis which is the same as moving along the Y axis on the depth map (if you look imagine looking at everything from above).    That's where the "problem" lies, the light AABB gets cut off exactly as the view frustum does in the first video because they're moving in the same directions. But in the second video when I move left/right the depth maps move up and down.    Yeah.... I hope some of that makes sense. But yeah since the orthographic views are rectangular I'm probably doing something wrong like you guys said. It's just weird because the algorithm is just     1. Get the frustum corners in world space 2. Find the longest radius 3. Take the center +- radius to get the min/max   Then multipy the min /max with the light view matrix and you should be good to go.
  4. Okay, so since I create the matrix using:  lightOrthoMatrix = glm::ortho(maxOrtho.x, minOrtho.x, maxOrtho.y, minOrtho.y, near, far); That means that if I rotate the camera 45 degrees and move to the left/right, the orthographic matrix will start moving either up and down or sideways. These videos and my amazing paint image should explain it:    Correct movement:      Incorrect movement:     You can see how the map gets cut off in the second video since it's no longer moving with the camera.   Also made this image to sort of illustrate the point:     if I rotate the camera then the min/max x and y aren't the same anymore. However if I start rotating the points along with the camera I get light shimmering again since the shadow map changes size. I can sort of alleviate the issue by doing this: lightOrthoMatrix = glm::ortho(minOrtho.x, maxOrtho.x, minOrtho.x, maxOrtho.x, near, far); Just changing the y values to the x values. Now I know that this is incorrect but I don't know how else to pad the frustum, everyone else seems to be doing it with just taking the radius and setting that to the max/min values and everythings perfect. I mean I guess I could leave it like this but I'll be wasting a lot of resolution and it's an incorrect solution
  5. So, I've mostly gotting everything working except for one minor detail that I can't seem to get rid off, the AABB doesn't seem big enough to cover the entire frustum and it gets a bit warped whenever I rotate the camera. I've just padded the xy with an offset until I got it to go away but that wastes too much resolution. Here's when I look down the negative z axis:     And when I rotate it a bit:     Then it goes away complete as I'm perpendicular to the z axis, and if I keep going the edges are on the other side of the screen instead     I have no clue why that happens and I havent seen anyone mentioning that you need to widen the X/Y radius to get it to go away, so I'm assuming I'm doing something wrong somewhere. Here's the complete code as of now: void CascadedShadowTechnique::renderToShadowMap(Mesh* mesh, Mesh* secondMesh) { //Get the active cameras frustum parameters Frustum cameraFrustum = CameraMan.getActiveCamera()->mFrustum; //Start off by calculating the split distances GLfloat cascadeSplits[MAX_SPLITS] = {}; //Between 0 and 1 GLfloat lambda = 1.0f; //min 0 max 1 GLfloat minDistance = 0.3f; GLfloat maxDistance = 1.0f; GLfloat nearClip = cameraFrustum.mNear; GLfloat farClip = cameraFrustum.mFar; GLfloat clipRange = farClip - nearClip; //Change min/maxDistance to have get different sized splits GLfloat minZ = nearClip + minDistance * clipRange; GLfloat maxZ = nearClip + maxDistance * clipRange; GLfloat range = maxZ - minZ; GLfloat ratio = maxZ / minZ; for (unsigned int i = 0; i < MAX_SPLITS; ++i) { GLfloat p = (i + 1) / static_cast<GLfloat>(MAX_SPLITS); // n(f/n)^i/m GLfloat log = minZ * std::pow(ratio, p); GLfloat uniform = minZ + range * p; GLfloat d = lambda * (log - uniform) + uniform; cascadeSplits[i] = (d - nearClip) / clipRange; } for (unsigned int cascadeIterator = 0; cascadeIterator < MAX_SPLITS; ++cascadeIterator) { GLfloat prevSplitDistance = cascadeIterator == 0 ? minDistance : cascadeSplits[cascadeIterator - 1]; GLfloat splitDistance = cascadeSplits[cascadeIterator]; // Get the 8 points of the view frustum in world space glm::vec3 frustumCornersWS[8] = { glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3( 1.0f,-1.0f, -1.0f), glm::vec3(-1.0f,-1.0f, -1.0f), glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3( 1.0f,-1.0f, 1.0f), glm::vec3(-1.0f,-1.0f, 1.0f), }; glm::mat4 invViewProj = glm::inverse(CameraMan.getActiveCamera()->mProjectionMatrix * CameraMan.getActiveCamera()->getViewMatrix()); for (unsigned int i = 0; i < 8; ++i) { glm::vec4 inversePoint = invViewProj * glm::vec4(frustumCornersWS[i], 1.0f); frustumCornersWS[i] = glm::vec3(inversePoint/inversePoint.w); } // Get the corners of the current cascade slice of the view frustum for (unsigned int i = 0; i < 4; ++i) { glm::vec3 cornerRay = frustumCornersWS[i + 4] - frustumCornersWS[i]; glm::vec3 nearCornerRay = cornerRay * prevSplitDistance; glm::vec3 farCornerRay = cornerRay * splitDistance; frustumCornersWS[i + 4] = frustumCornersWS[i] + farCornerRay; frustumCornersWS[i] = frustumCornersWS[i] + nearCornerRay; } //Calculate the frustum center glm::vec3 frustumCenter = glm::vec3(0.0f); for (unsigned int i = 0; i < 8; ++i) frustumCenter += frustumCornersWS[i]; frustumCenter /= 8.0f; GLfloat far = -INFINITY; GLfloat near = INFINITY; //Get the longest radius in world space GLfloat radius = 0.0f; for (unsigned int i = 0; i < 8; ++i) { GLfloat distance = glm::length(frustumCornersWS[i] - frustumCenter); radius = glm::max(radius, distance); } radius = std::ceil(radius); //Create the AABB from the radius glm::vec3 maxOrtho = frustumCenter + glm::vec3(radius, radius, radius); glm::vec3 minOrtho = frustumCenter - glm::vec3(radius, radius, radius); //Just checking when debugging to make sure the AABB is the same size GLfloat lengthofTemp = glm::length(maxOrtho - minOrtho); GLfloat testing = radius*2.0f; //Calculate the viewMatrix from the frustum center and light direction glm::vec3 lightDirection = frustumCenter - glm::normalize(glm::vec3(-0.447213620f, -0.89442790f, 0.0f)); lightViewMatrix = glm::lookAt(lightDirection, frustumCenter, glm::vec3(0.0f, 1.0f, 0.0f)); //Get the AABB in light view space maxOrtho = glm::vec3(lightViewMatrix*glm::vec4(maxOrtho, 1.0f)); minOrtho = glm::vec3(lightViewMatrix*glm::vec4(minOrtho, 1.0f)); //Store the far and near planes far = maxOrtho.z; near = minOrtho.z; lightOrthoMatrix = glm::ortho(maxOrtho.x, minOrtho.x, maxOrtho.y, minOrtho.y, near, far); // Create the rounding matrix, by projecting the world-space origin and determining // the fractional offset in texel space glm::mat4 shadowMatrix = lightOrthoMatrix * lightViewMatrix; glm::vec4 shadowOrigin = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); shadowOrigin = shadowMatrix * shadowOrigin; shadowOrigin = shadowOrigin * mShadowMapSize / 2.0f; glm::vec4 roundedOrigin = glm::round(shadowOrigin); glm::vec4 roundOffset = roundedOrigin - shadowOrigin; roundOffset = roundOffset * 2.0f / mShadowMapSize; roundOffset.z = 0.0f; roundOffset.w = 0.0f; glm::mat4 shadowProj = lightOrthoMatrix; shadowProj[3] += roundOffset; lightOrthoMatrix = shadowProj; // Store the split distance in terms of view space depth const float clipDist = cameraFrustum.mFar - cameraFrustum.mNear; cascadeSplitArray[cascadeIterator] = cameraFrustum.mNear + splitDistance * clipDist; cascadedMatrices[cascadeIterator] = lightOrthoMatrix * lightViewMatrix; //Now finally render the scene into FBO ShaderMan.bindShader(SHADOW_DEPTH_PASS_SHADER); glBindFramebuffer(GL_FRAMEBUFFER, mCascadedShadowFBO); glViewport(0, 0, mShadowMapSize, mShadowMapSize); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mCascadedTextureArray, 0, cascadeIterator); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_CLAMP); glCullFace(GL_FRONT); glm::mat4 lightViewProjection = lightOrthoMatrix * lightViewMatrix; glUniformMatrix4fv(ShaderMan.getActiveShader().getUniformLocation("lightViewProjectionMatrix"), 1, GL_FALSE, &lightViewProjection[0][0]); mesh->renderDepth(); secondMesh->renderDepth(); glBindFramebuffer(GL_FRAMEBUFFER, 0); ShaderMan.unbindShader(); glDisable(GL_DEPTH_CLAMP); } } I'm pretty confident that the frustums are calculated correctly, but I can't find any reason for what's happening.
  6. Finally got them stabilized, now I'm not sure exactly what I did wrong because just using a sphere around the frustum didn't remove any rotation shimmering, and I triple checked that it had the same size constantly. Ended up finding some code over here which I found made more sense than anything I've read in any paper: http://www.gamedev.net/topic/650743-improving-cascade-shadow/ And how I used it in my code:   //Calculate the viewMatrix from the frustum center and light direction Frustum cameraFrustum = CameraMan.getActiveCamera()->mFrustum; glm::vec3 lightDirection = glm::normalize(glm::vec3(-0.447213620f, -0.89442790f, 0.0f)); lightViewMatrix = glm::lookAt((cameraFrustum.frustumCenter - lightDirection), cameraFrustum.frustumCenter, glm::vec3(0.0f, 1.0f, 0.0f)); //Get the longest radius in world space GLfloat radius = glm::length(cameraFrustum.frustumCenter - cameraFrustum.frustumCorners[6]); for (unsigned int i = 0; i < 8; ++i) { GLfloat distance = glm::length(cameraFrustum.frustumCorners[i] - cameraFrustum.frustumCenter); radius = glm::max(radius, distance); } radius = std::ceil(radius); //Create the AABB from the radius glm::vec3 maxOrtho = cameraFrustum.frustumCenter + glm::vec3(radius); glm::vec3 minOrtho = cameraFrustum.frustumCenter - glm::vec3(radius); //Get the AABB in light view space maxOrtho = glm::vec3(lightViewMatrix*glm::vec4(maxOrtho, 1.0f)); minOrtho = glm::vec3(lightViewMatrix*glm::vec4(minOrtho, 1.0f)); //Just checking when debugging to make sure the AABB is the same size GLfloat lengthofTemp = glm::length(maxOrtho - minOrtho); //Store the far and near planes far = maxOrtho.z; near = minOrtho.z; lightOrthoMatrix = glm::ortho(minOrtho.x, maxOrtho.x, minOrtho.y, maxOrtho.y, near, far); // Create the rounding matrix, by projecting the world-space origin and determining // the fractional offset in texel space glm::mat4 shadowMatrix = lightOrthoMatrix * lightViewMatrix; glm::vec4 shadowOrigin = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); shadowOrigin = shadowMatrix * shadowOrigin; GLfloat storedW = shadowOrigin.w; shadowOrigin = shadowOrigin * 4096.0f / 2.0f; glm::vec4 roundedOrigin = glm::round(shadowOrigin); glm::vec4 roundOffset = roundedOrigin - shadowOrigin; roundOffset = roundOffset * 2.0f / 4096.0f; roundOffset.z = 0.0f; roundOffset.w = 0.0f; glm::mat4 shadowProj = lightOrthoMatrix; shadowProj[3] += roundOffset; lightOrthoMatrix = shadowProj; Two things I noted is that the uses a ceil operation on the radius, and then creates a new orthographic matrix with adjusted values. I'm not entirely sure how it works just yet since I'm still happy that it finally is working. Video just for kicks    
  7. I'm actually thinking about giving up and using spheres. From Jonathan Blows article I found this    Using this method, would you still need to clip the Scene AABB against the view frustum to get a tight fit around any possible shadow casters?
  8. Maybe I'm doing something wrong here.. I tried your code like this:  glm::vec2 unitsPerTexel = 2.0f*glm::vec2(longestDiagonal.x, longestDiagonal.y) / glm::vec2((GLfloat)1024, (GLfloat)1024); minO.x = glm::floor(minO.x / unitsPerTexel.x)*unitsPerTexel.x; maxO.x = glm::floor(maxO.x / unitsPerTexel.x)*unitsPerTexel.x; minO.y = glm::floor(minO.y / unitsPerTexel.y)*unitsPerTexel.y; maxO.y = glm::floor(maxO.y / unitsPerTexel.y)*unitsPerTexel.y; lightOrthoMatrix = glm::ortho(minO.x, maxO.x, minO.y, maxO.y, near, far); Which produced the same results unfortunately, this was my original code... I'm suspecting something else is wrong somewhere but I don't know what that could be GLfloat worldUnitsPerTexel = lengthOfDiagonal / 1024.0f; //glm::vec3 vWorldUnitsPerTexel = glm::vec3(worldUnitsPerTexel, worldUnitsPerTexel, 0.0f); glm::vec3 vWorldUnitsPerTexel = glm::vec3((maxO.x - minO.x) / 1024.0f, (maxO.y - minO.y) / 1024.0f, 0.0f); minO /= vWorldUnitsPerTexel; minO = glm::floor(minO); minO *= vWorldUnitsPerTexel; maxO /= vWorldUnitsPerTexel; maxO = glm::floor(maxO); maxO *= vWorldUnitsPerTexel;
  9. I'm not sure how much use this is, but here's a video of the shadows view, it seems to be stables as I'm moving/rotating around:      EDIT: Made another video that clearly shows the texel jumps as well as how the shadows are moving with a slower camera  
  10. Yeah, I tried changing the code too and it produced the same results. I found this though, but I'm not sure exactly what he means by it:      from http://gamedev.stackexchange.com/questions/73851/how-do-i-fit-the-camera-frustum-inside-directional-light-space and yeah, I still can't quite figure out what's wrong.
  11. I've been trying to get a single directional shadows orthogonal matrix to fit around the view frustum before I move on to splitting it up and calculating a tighter bound for it. However I can't seem to get the shimmering effect to go away. I've been following microsofts example https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx like everyone else but I can't get the shimmering to go away, unless I'm missing something here. And yeah, don't mind the large texels from the shadows, the scene/view frustum is pretty big because I wanted to test it properly. Here's the effect:    And the code:  GLfloat far = -INFINITY; GLfloat near = INFINITY; //Multiply all the world space frustum corners with the view matrix of the light Frustum cameraFrustum = CameraMan.getActiveCamera()->mFrustum; lightViewMatrix = glm::lookAt((cameraFrustum.frustumCenter - glm::vec3(-0.447213620f, -0.89442790f, 0.0f)), cameraFrustum.frustumCenter, glm::vec3(0.0f, 0.0f, 1.0f)); glm::vec3 arr[8]; for (unsigned int i = 0; i < 8; ++i) arr[i] = glm::vec3(lightViewMatrix * glm::vec4(cameraFrustum.frustumCorners[i], 1.0f)); glm::vec3 minO = glm::vec3(INFINITY, INFINITY, INFINITY); glm::vec3 maxO = glm::vec3(-INFINITY, -INFINITY, -INFINITY); for (auto& vec : arr) { minO = glm::min(minO, vec); maxO = glm::max(maxO, vec); } far = maxO.z; near = minO.z; //Get the longest diagonal of the frustum, this along with texel sized increments is used to keep the shadows from shimmering //far top right - near bottom left glm::vec3 longestDiagonal = cameraFrustum.frustumCorners[0] - cameraFrustum.frustumCorners[6]; GLfloat lengthOfDiagonal = glm::length(longestDiagonal); longestDiagonal = glm::vec3(lengthOfDiagonal); glm::vec3 borderOffset = (longestDiagonal - (maxO - minO)) * glm::vec3(0.5f, 0.5f, 0.5f); borderOffset *= glm::vec3(1.0f, 1.0f, 0.0f); maxO += borderOffset; minO -= borderOffset; GLfloat worldUnitsPerTexel = lengthOfDiagonal / 1024.0f; glm::vec3 vWorldUnitsPerTexel = glm::vec3(worldUnitsPerTexel, worldUnitsPerTexel, 0.0f); minO /= vWorldUnitsPerTexel; minO = glm::floor(minO); minO *= vWorldUnitsPerTexel; maxO /= vWorldUnitsPerTexel; maxO = glm::floor(maxO); maxO *= vWorldUnitsPerTexel; lightOrthoMatrix = glm::ortho(minO.x, maxO.x, minO.y, maxO.y, near, far); //For more accurate near and far planes, clip the scenes AABB with the orthographic frustum //calculateNearAndFar(); At first I thought I was simply using a too big scene for such a small texture, but even with smaller near/far values I get pixel shimmering. I based the texel increment/longest diagonal solution on the code that goes along with that article but i can't quite get it right       EDIT: this is how the frustum is calculated each frame, and how the shadow textures are setup void Camera::updateFrustum() { //Just to visualise it http://www.panohelp.com/lensfov.html float nearHeight = 2 * tan(mFOV / 2) * mNear; float nearWidth = nearHeight * mRatio; float farHeight = 2 * tan(mFOV / 2) * mFar; float farWidth = farHeight * mRatio; glm::vec3 fc = mPos + mFront * mFar; glm::vec3 nc = mPos + mFront * mNear; mFrustum.frustumCorners[0] = fc + (mUp * farHeight / 2.0f) - (mRight * farWidth / 2.0f); mFrustum.frustumCorners[1] = fc + (mUp * farHeight / 2.0f) + (mRight * farWidth / 2.0f); mFrustum.frustumCorners[2] = fc - (mUp * farHeight / 2.0f) - (mRight * farWidth / 2.0f); mFrustum.frustumCorners[3] = fc - (mUp * farHeight / 2.0f) + (mRight * farWidth / 2.0f); mFrustum.frustumCorners[4] = nc + (mUp * nearHeight / 2.0f) - (mRight * nearWidth / 2.0f); mFrustum.frustumCorners[5] = nc + (mUp * nearHeight / 2.0f) + (mRight * nearWidth / 2.0f); mFrustum.frustumCorners[6] = nc - (mUp * nearHeight / 2.0f) - (mRight * nearWidth / 2.0f); mFrustum.frustumCorners[7] = nc - (mUp * nearHeight / 2.0f) + (mRight * nearWidth / 2.0f); mFrustum.frustumCenter = mPos + mFront * ((mFar - mNear) / 2.0f); } mShadowMapWidth = 1024; mShadowMapHeight = 1024; // Directional light shadow map buffer glGenFramebuffers(1, &mDirectionalShadowFBO); glBindFramebuffer(GL_FRAMEBUFFER, mDirectionalShadowFBO); glGenTextures(1, &mDirectionalShadowDepthTexture); glBindTexture(GL_TEXTURE_2D, mDirectionalShadowDepthTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, mShadowMapWidth, mShadowMapHeight, 0, GL_DEPTH_COMPONENT, GL_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_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, mDirectionalShadowDepthTexture, 0); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); // This code removes the shimmering effect along the edges of shadows due to // the light changing to fit the camera. if( m_eSelectedCascadesFit == FIT_TO_SCENE ) { // Fit the ortho projection to the cascades far plane and a near plane of zero. // Pad the projection to be the size of the diagonal of the Frustum partition. // // To do this, we pad the ortho transform so that it is always big enough to cover // the entire camera view frustum. XMVECTOR vDiagonal = vFrustumPoints[0] - vFrustumPoints[6]; vDiagonal = XMVector3Length( vDiagonal ); // The bound is the length of the diagonal of the frustum interval. FLOAT fCascadeBound = XMVectorGetX( vDiagonal ); // The offset calculated will pad the ortho projection so that it is always the same size // and big enough to cover the entire cascade interval. XMVECTOR vBoarderOffset = ( vDiagonal - ( vLightCameraOrthographicMax - vLightCameraOrthographicMin ) ) * g_vHalfVector; // Set the Z and W components to zero. vBoarderOffset *= g_vMultiplySetzwToZero; // Add the offsets to the projection. vLightCameraOrthographicMax += vBoarderOffset; vLightCameraOrthographicMin -= vBoarderOffset; // The world units per texel are used to snap the shadow the orthographic projection // to texel sized increments. This keeps the edges of the shadows from shimmering. FLOAT fWorldUnitsPerTexel = fCascadeBound / (float)m_CopyOfCascadeConfig.m_iBufferSize; vWorldUnitsPerTexel = XMVectorSet( fWorldUnitsPerTexel, fWorldUnitsPerTexel, 0.0f, 0.0f ); } And this code above is the one in the microsoft example
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!