How to set a default OpenGL texture unit - opengl

TL/DR: How do you specify a (default) texture unit for unused samplers in a sampler array?
I have the following scene in my OpenGL 4.1 application:
As you can see, there are 2 lights. Each light has its own shadow map. So my fragment shader looks like this:
#define MAX_LIGHTS 16
uniform samplerCube uShadowMaps[MAX_LIGHTS];
// sample the shadow map of the light
float Shadow(int light) {
vec3 direction = Position - uLightPositions[light];
float sampledDepth = 1.0;
switch (light) {
case 0: sampledDepth = texture(uShadowMaps[0], direction).r; break;
case 1: sampledDepth = texture(uShadowMaps[1], direction).r; break;
}
// ... the rest of the calculations ...
}
This code works because there are exactly 2 lights and each binds it's own shadow map. The code every light runs looks somewhat like this:
// make the name of the uniform
std::stringstream shadowMapName;
shadowMapName << "uShadowMaps[" << index << "]";
// bind the shadow map texture and bind the uniform
glActiveTexture(GL_TEXTURE3 + index); // index is the light number, 3 because there are 3 other textures already bound
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowMapTexture);
auto position = glGetUniformLocation(shaderProgram, shadowMapName.str().c_str());
glUniform1i(position, index + 3);
However, I want to have multiple lights in the scene eventually, so I want to write my shaders so they work for more lights. I added the next switch case in the shader like this:
// sample the shadow map for the light
float Shadow(int light) {
// ...
switch (light) {
case 0: sampledDepth = texture(uShadowMaps[0], direction).r; break;
case 1: sampledDepth = texture(uShadowMaps[1], direction).r; break;
case 2: sampledDepth = texture(uShadowMaps[2], direction).r; break;
}
// ...
}
This, unfortunately, results in a black window.
I assume this is because there's nothing bound to mShaderMaps[2]. And sure enough, if I add another light to the scene, it renders again.
So my question is: How do you specify a (default) texture unit for unused samplers?
Note: why switch? This does not work:
// sample the shadow map for the light
float Shadow(int light) {
// ...
sampledDepth = texture(uShadowMaps[light], direction).r;
// ...
}
Because light is not a dynamically uniform expression. See GLSL, Array of textures of differing size.
EDIT
The Shadow function is called like this:
// calculate diffuse color for the fragment
for (auto i = 0; i < min(uLightCount, MAX_LIGHTS); ++i) {
// ... calculate diffuse for the light
diffuseColor += diffuse * Shadow(i);
}
// ... some more stuff ...
// calculate specular color for the fragment
for (auto i = 0; i < min(uLightCount, MAX_LIGHTS); ++i) {
// ... calculate specular for the light
specularColor += specular * Shadow(i);
}

Well, it turns out it is really easy. I just create an empty shadow map and bind it to every shadow map in the array, each to its own texture unit. The code looks like this:
auto empty = ShadowMap::CreateEmpty(); // make an empty shadow map
for (auto i = 0; i < 12; ++i) { // 12 is the shadow map array size
std::stringstream shadowMapName;
shadowMapName << "uShadowMaps[" << i << "]";
glActiveTexture(GL_TEXTURE3 + i); // bind to a separate texture unit
glBindTexture(GL_TEXTURE_CUBE_MAP, empty->GetId());
auto position = glGetUniformLocation(shaderProgram, shadowMapName.str().c_str());
glUniform1i(position, i + 3);
}
The reason I couldn't get it working before was that I was binding a simple texture to unused shadow maps. But the bound shadow maps use cube maps, so I was binding a different texture types to the array, which does not work.

Related

D3D11/C++ Inaccuracies in uv interpolation in pixel shader. How to avoid?

I'm trying to draw a quad with a texture onto the screen such that texels and pixels perfectly align. Sounds pretty easy. I draw 2 triangles (as TRIANGLE_LIST, so 6 vertices) using these shaders:
struct VSOutput
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
VSOutput VS_Draw(uint index : SV_VertexId)
{
uint vertexIndex = index % 6;
// compute face in [0,0]-[1,1] space
float2 vertex = 0;
switch (vertexIndex)
{
case 0: vertex = float2(0, 0); break;
case 1: vertex = float2(1, 0); break;
case 2: vertex = float2(0, 1); break;
case 3: vertex = float2(0, 1); break;
case 4: vertex = float2(1, 0); break;
case 5: vertex = float2(1, 1); break;
}
// compute uv
float2 uv = vertex;
// scale to size
vertex = vertex * (float2)outputSize;
vertex = vertex + topLeftPos;
// convert to screen space
VSOutput output;
output.position = float4(vertex / (float2)outputSize * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0, 1);
output.uv = uv;
return output;
}
float4 PS_Draw(VSOutput input) : SV_TARGET
{
uint2 pixelPos = (uint2)(input.uv * (float2)outputSize);
// output checker of 4x4
return (((pixelPos.x >> 2) & 1) ^ ((pixelPos.y >> 2) & 1) != 0) ? float4(0, 1, 1, 0) : float4(1, 1, 0, 0);
}
where outputSize and topLeftPos are constants and expressed in pixel units.
Now for outputSize = (102,12) and topLeftPos=(0,0) I get (what I would expect):
link to image (as i'm not allowed to post images)
But for outputSize = (102,12) and topLeftPos=(0,0.5) I get: Output for x=0, y=0.5
link to image (as i'm not allowed to post images)
As you can see there is a uv-discontinuity where the 2 triangles connect and interpolation of uv is inaccurate). This basically happens (in x and y) only at positions around the .5 (actually below .49 it correctly snaps to texel 0 and above .51 it snaps correctly to texel 1, but in between i get this artifact).
Now for the purpose I need this for it is essential to have pixel perfect mapping. Can anyone enlighten me why this happens ?
There are a two things you need consider to understand what is happening:
Pixel corners in window space have integer coordinates and pixel centers in windows space have half-integer coordinates.
When triangle is rasterized, D3D11 interpolates all attributes to pixel centers
So what is happening is that when topLeftPos=(0,0), the value of input.uv * (float2)outputSize is always half-integer, and it is consistently rounded down to closest integer. However, when topLeftPos=(0,0.5), the (input.uv * (float2)outputSize).y should always be exactly integer. However, due to unpredictable floating-point precision issues, it is sometimes little less than exact integer, and in this case it is rounded down too much. This is where you see your stretched squares.
So if you want perfect mapping, your source square should be aligned with the pixel boundaries and not pixel centers.

Cumulative masking for Cocos2d-x

Let's say I have a Texture2D object. What I want to be able to do is to mask it using another Texture2D object (I already have a basic masking shader written), and then assign this new masked texture to the original Texture2D. At the next iteration, I then could be able to do this again but for another mask, and again, and again...
Drawing all the masks in a single texture using RenderTexture is not possible since 1) there would be huge performances issues 2) they are generated at runtime.
Here's what I want to do:
Does anyone else ever had this problem or know a solution? Thanks :)
EDIT:
Here's what I'm doing for now:
// Ok, so GroundLayer is a layer that setup GroundZones. GroundZones are ’slices’ of the screen that can be ‘dug’
// into, the act of digging being masking the main ground texture with another texture containing only a line.
// This is where cumulative masking come handy, since we don’t want to have to track each point where the user
// dug. We want to create a sort of mutable texture, but simpler.
void GroundLayer::digLine(Point start, Point end) {
// To dig a line, we need first to get the texture of the zone we will be digging into. Then we get the
// relative position of the start and end point in the zone's node space. Finally we use the custom shader to
// draw a mask over the existing texture.
for (auto it = _children.begin(); it != _children.end(); it++) {
GroundZone *zone = static_cast<GroundZone *>(*it); // We are sure that all the children are GroundZones
Point nodeStart = zone->convertToNodeSpace(start);
Point nodeEnd = zone->convertToNodeSpace(end);
// Now that we have our two points converted to node space, it's easy to draw a mask that contains a line
// going from the start point to the end point and that is then applied over the current texture.
Size groundZoneSize = zone->getContentSize();
RenderTexture *rt = RenderTexture::create(groundZoneSize.width, groundZoneSize.height);
rt->retain();
rt->beginWithClear(0, 0, 0, 0); {
// Draw a line going from start and going to end in the texture, the line will act as a mask over the
// existing texture
DrawNode *line = DrawNode::create();
line->drawSegment(nodeStart, nodeEnd, 20, Color4F::BLACK);
line->visit();
} rt->end();
// We mask current texture with the mask texture using a custom shader. The resulting texture will then be
// affected to the zone's texture, making a new texture that can be used again next function call.
Texture2D *currentTexture = zone->getTexture();
Texture2D *maskTexture = rt->getSprite()->getTexture();
maskTexture->setAliasTexParameters(); // Disable linear interpolation on the mask
// Setup the shader for currentTexture
// Custom shader is already loaded in the init method of GroundLayer
currentTexture->setShaderProgram(ShaderCache::getInstance()->getProgram(CustomShader_AlphaMask_frag_key));
GLProgram *shader = currentTexture->getShaderProgram();
int maskTexUniformLoc = glGetUniformLocation(shader->getProgram(), "u_alphaMaskTexture");
glUniform1i(maskTexUniformLoc, 1);
// Actually apply the shader over currentTexture
shader->use();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, maskTexture->getName());
glActiveTexture(GL_TEXTURE0);
// [I'm at lost here :( (or sooner...)]
}
}
Here's the shader I wrote:
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform sampler2D u_alphaMaskTexture;
void main() {
// Mask the texture with the alpha of the texture
float maskAlpha = texture2D(u_alphaMaskTexture, v_texCoord).a;
float texAlpha = texture2D(u_texture, v_texCoord).a;
float blendAlpha = (1.0 - maskAlpha) * texAlpha; // Show only where mask is invisible
vec3 texColor = texture2D(u_texture, v_texCoord).rgb;
gl_FragColor = vec4(texColor, blendAlpha);
return;
}

Draw transparent holes in a texture/plain color

I'm running into a problem and I don't know what is the best practise for it. I have a background that moves upward, which is in fact "slices" that moves toghether, as if the screen was splitted in 4-5 parts horizontally. I need to be able to draw a hole (circle) in the background (see-through), at a specified position which will change dynamically at each frame or so.
Here is how I generate a zone, I don't think there's much of a problem there:
// A 'zone' is simply the 'slice' of ground that moves upward. There's about 4 of
// them visible on screen at the same time, and they are automatically generated by
// a method irrelevant to the situation. Zones are Sprites.
// ---------
void LevelLayer::Zone::generate(LevelLayer *sender) {
// [...]
// Make a background for the zone
Sprite *background = this->generateBackgroundSprite();
background->setPosition(_contentSize.width / 2, _contentSize.height / 2);
this->addChild(background, 0);
}
This is the Zone::generateBackgroundSprite() method:
// generates dynamically a new background texture
Sprite *LevelLayer::Zone::generateBackgroundSprite() {
RenderTexture *rt = RenderTexture::create(_contentSize.width, _contentSize.height);
rt->retain();
Color4B dirtColorByte = Color4B(/*initialize the color with bytes*/);
Color4F dirtColor(dirtColorByte);
rt->beginWithClear(dirtColor.r, dirtColor.g, dirtColor.b, dirtColor.a);
// [Nothing here yet, gotta learn OpenGL m8]
rt->end();
// ++++++++++++++++++++
// I'm just testing clipping node, it works but the FPS get significantly lower.
// If I lock them to 60, they get down to 30, and if I lock them there they get
// to 20 :(
// Also for the test I'm drawing a square since ClippingNode doesn't seem to
// like circles...
DrawNode *square = DrawNode::create();
Point squarePoints[4] = { Point(-20, -20), Point(20, -20), Point(20, 20), Point(-20, 20) };
square->drawPolygon(squarePoints, 4, Color4F::BLACK, 0.0f, Color4F(0, 0, 0, 0));
square->setPosition(0, 0);
// Make a stencil
Node *stencil = Node::create();
stencil->addChild(square);
// Create a clipping node with the prepared stencil
ClippingNode *clippingNode = ClippingNode::create(stencil);
clippingNode->setInverted(true);
clippingNode->addChild(rt);
Sprite *ret = Sprite::create();
ret->addChild(clippingNode);
rt->release();
return ret;
}
**
So I'm asking you guys, what would you do in such a situation? Is what I am doing a good idea? Would you do it in another more imaginative way?
PS This is a rewrite of a little app I made for iOS (I want to port it to Android), and I was using MutableTextures in the Objective-C version (it was working). I'm just trying to see if there's a better way using RenderTexture, so I can dynamically create background images using OpenGL calls.
EDIT (SOLUTION)
I wrote my own simple fragment shader that "masks" the visible parts of a texture (the background) based on the visible parts of another texture (the mask). I have an array of points that determine where my circles are on the screen, and in the update method I draw them to a RenderTexture. I then take the generated texture and use it as the mask I pass to the shader.
This is my shader:
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform sampler2D u_alphaMaskTexture;
void main() {
float maskAlpha = texture2D(u_alphaMaskTexture, v_texCoord).a;
float texAlpha = texture2D(u_texture, v_texCoord).a;
float blendAlpha = (1.0 - maskAlpha) * texAlpha; // Show only where mask is not visible
vec3 texColor = texture2D(u_texture, v_texCoord).rgb;
gl_FragColor = vec4(texColor, blendAlpha);
return;
}
init method:
bool HelloWorld::init() {
// [...]
Size visibleSize = Director::getInstance()->getVisibleSize();
// Load and cache the custom shader
this->loadCustomShader();
// 'generateBackgroundSlice()' creates a new RenderTexture and fills it with a
// color, nothing too complicated here so I won't copy-paste it in my edit
m_background = Sprite::createWithTexture(this->generateBackgroundSprite()->getSprite()->getTexture());
m_background->setPosition(visibleSize.width / 2, visibleSize.height / 2);
this->addChild(m_background);
m_background->setShaderProgram(ShaderCache::getInstance()->getProgram(Shader_AlphaMask_frag_key));
GLProgram *shader = m_background->getShaderProgram();
m_alphaMaskTextureUniformLocation = glGetUniformLocation(shader->getProgram(), "u_alphaMaskTexture");
glUniform1i(m_alphaMaskTextureUniformLocation, 1);
m_alphaMaskRender = RenderTexture::create(m_background->getContentSize().width,
m_background->getContentSize().height);
m_alphaMaskRender->retain();
// [...]
}
loadCustomShader method:
void HelloWorld::loadCustomShader() {
// Load the content of the vertex and fragement shader
FileUtils *fileUtils = FileUtils::getInstance();
string vertexSource = ccPositionTextureA8Color_vert;
string fragmentSource = fileUtils->getStringFromFile(
fileUtils->fullPathForFilename("Shader_AlphaMask_frag.fsh"));
// Init a shader and add its attributes
GLProgram *shader = new GLProgram;
shader->initWithByteArrays(vertexSource.c_str(), fragmentSource.c_str());
shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);
shader->link();
shader->updateUniforms();
ShaderCache::getInstance()->addProgram(shader, Shader_AlphaMask_frag_key);
// Trace OpenGL errors if any
CHECK_GL_ERROR_DEBUG();
}
update method:
void HelloWorld::update(float dt) {
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Create the mask texture from the points in the m_circlePos array
GLProgram *shader = m_background->getShaderProgram();
m_alphaMaskRender->beginWithClear(0, 0, 0, 0); // Begin with transparent mask
for (vector<Point>::iterator it = m_circlePos.begin(); it != m_circlePos.end(); it++) {
// draw a circle on the mask
const float radius = 40;
const int resolution = 20;
Point circlePoints[resolution];
Point center = *it;
center = Director::getInstance()->convertToUI(center); // OpenGL has a weird coordinates system
float angle = 0;
for (int i = 0; i < resolution; i++) {
float x = (radius * cosf(angle)) + center.x;
float y = (radius * sinf(angle)) + center.y;
angle += (2 * M_PI) / resolution;
circlePoints[i] = Point(x, y);
}
DrawNode *circle = DrawNode::create();
circle->retain();
circle->drawPolygon(circlePoints, resolution, Color4F::BLACK, 0.0f, Color4F(0, 0, 0, 0));
circle->setPosition(Point::ZERO);
circle->visit();
circle->release();
}
m_alphaMaskRender->end();
Texture2D *alphaMaskTexture = m_alphaMaskRender->getSprite()->getTexture();
alphaMaskTexture->setAliasTexParameters(); // Disable linear interpolation
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
shader->use();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, alphaMaskTexture->getName());
glActiveTexture(GL_TEXTURE0);
}
What you might want to look at is framebuffers, i'm not too familiar with the mobile API for OpenGL but I'm sure you should have access to framebuffers.
An idea of what you might want to try is to do a first pass where you render the circles's that you want to set to alpha on your background into a new framebuffer texture, then you can use this texture as an alpha map on your pass for rendering your background. So basically when you render your circle you might set the value in the texture to 0.0 for the alpha channel otherwise to 1.0, when rendering you can then set the alpha channel of the fragment to the same value as the alpha of texture of the first pass' of the rendering process.
You can think of it as a the same idea as a mask. But just using another texture.
Hope this helps :)

Cubemap shadow mapping not working

I'm attempting to create omnidirectional/point lighting in openGL version 3.3. I've searched around on the internet and this site, but so far I have not been able to accomplish this. From my understanding, I am supposed to
Generate a framebuffer using depth component
Generate a cubemap and bind it to said framebuffer
Draw to the individual parts of the cubemap as refrenced by the enums GL_TEXTURE_CUBE_MAP_*
Draw the scene normally, and compare the depth value of the fragments against those in the cubemap
Now, I've read that it is better to use distances from the light to the fragment, rather than to store the fragment depth, as it allows for easier cubemap look up (something about not needing to check each individual texture?)
My current issue is that the light that comes out is actually in a sphere, and does not generate shadows. Another issue is that the framebuffer complains of not being complete, although I was under the impression that a framebuffer does not need a renderbuffer if it renders to a texture.
Here is my framebuffer and cube map initialization:
framebuffer = 0;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenTextures(1, &shadowTexture);
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowTexture);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);GL_COMPARE_R_TO_TEXTURE);
for(int i = 0; i < 6; i++){
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i , 0,GL_DEPTH_COMPONENT16, 800, 800, 0,GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
}
glDrawBuffer(GL_NONE);
Shadow Vertex Shader
void main(){
gl_Position = depthMVP * M* vec4(position,1);
pos =(M * vec4(position,1)).xyz;
}
Shadow Fragment Shader
void main(){
fragmentDepth = distance(lightPos, pos);
}
Vertex Shader (unrelated bits cut out)
uniform mat4 depthMVP;
void main() {
PositionWorldSpace = (M * vec4(position,1.0)).xyz;
gl_Position = MVP * vec4(position, 1.0 );
ShadowCoord = depthMVP * M* vec4(position, 1.0);
}
Fragment Shader (unrelated code cut)
uniform samplerCube shadowMap;
void main(){
float bias = 0.005;
float visibility = 1;
if(texture(shadowMap, ShadowCoord.xyz).x < distance(lightPos, PositionWorldSpace)-bias)
visibility = 0.1
}
Now as you are probably thinking, what is depthMVP? Depth projection matrix is currently an orthogonal projection with the ranges [-10, 10] in each direction
Well they are defined like so:
glm::mat4 depthMVP = depthProjectionMatrix* ??? *i->getModelMatrix();
The issue here is that I don't know what the ??? value is supposed to be. It used to be the camera matrix, however I am unsure if that is what it is supposed to be.
Then the draw code is done for the sides of the cubemap like so:
for(int loop = 0; loop < 6; loop++){
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X+loop, shadowTexture,0);
glClear( GL_DEPTH_BUFFER_BIT);
for(auto i: models){
glUniformMatrix4fv(modelPos, 1, GL_FALSE, glm::value_ptr(i->getModelMatrix()));
glm::mat4 depthMVP = depthProjectionMatrix*???*i->getModelMatrix();
glUniformMatrix4fv(glGetUniformLocation(shadowProgram, "depthMVP"),1, GL_FALSE, glm::value_ptr(depthMVP));
glBindVertexArray(i->vao);
glDrawElements(GL_TRIANGLES, i->triangles, GL_UNSIGNED_INT,0);
}
}
Finally the scene gets drawn normally (I'll spare you the details). Before the calls to draw onto the cubemap I set the framebuffer to the one that I generated earlier, and change the viewport to 800 by 800. I change the framebuffer back to 0 and reset the viewport to 800 by 600 before I do normal drawing. Any help on this subject will be greatly appreciated.
Update 1
After some tweaking and bug fixing, this is the result I get. I fixed an error with the depthMVP not working, what I am drawing here is the distance that is stored in the cubemap.
http://imgur.com/JekOMvf
Basically what happens is it draws the same one sided projection on each side. This makes sense since we use the same view matrix for each side, however I am not sure what sort of view matrix I am supposed to use. I think they are supposed to be lookAt() matrices that are positioned at the center, and look out in the cube map side's direction. However, the question that arises is how I am supposed to use these multiple projections in my main draw call.
Update 2
I've gone ahead and created these matrixes, however I am unsure of how valid they are (they were ripped from a website for DX cubemaps, so I inverted the Z coord).
case 1://Negative X
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(-1,0,0),glm::vec3(0,-1,0));
break;
case 3://Negative Y
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(0,-1,0),glm::vec3(0,0,-1));
break;
case 5://Negative Z
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(0,0,-1),glm::vec3(0,-1,0));
break;
case 0://Positive X
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(1,0,0),glm::vec3(0,-1,0));
break;
case 2://Positive Y
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(0,1,0),glm::vec3(0,0,1));
break;
case 4://Positive Z
sideViews[i] = glm::lookAt(glm::vec3(0), glm::vec3(0,0,1),glm::vec3(0,-1,0));
break;
The question still stands, what I am supposed to translate the depthMVP view portion by, as these are 6 individual matrices. Here is a screenshot of what it currently looks like, with the same frag shader (i.e. actually rendering shadows) http://i.imgur.com/HsOSG5v.png
As you can see the shadows seem fine, however the positioning is obviously an issue. The view matrix that I used to generate this was just an inverse translation of the position of the camera (as the lookAt() function would do).
Update 3
Code, as it currently stands:
Shadow Vertex
void main(){
gl_Position = depthMVP * vec4(position,1);
pos =(M * vec4(position,1)).xyz;
}
Shadow Fragment
void main(){
fragmentDepth = distance(lightPos, pos);
}
Main Vertex
void main(){
PositionWorldSpace = (M*vec4(position, 1)).xyz;
ShadowCoord = vec4(PositionWorldSpace - lightPos, 1);
}
Main Frag
void main(){
float texDist = texture(shadowMap, ShadowCoord.xyz/ShadowCoord.w).x;
float dist = distance(lightPos, PositionWorldSpace);
if(texDist < distance(lightPos, PositionWorldSpace)
visibility = 0.1;
outColor = vec3(texDist);//This is to visualize the depth maps
}
The perspective matrix being used
glm::mat4 depthProjectionMatrix = glm::perspective(90.f, 1.f, 1.f, 50.f);
Everything is currently working, sort of. The data that the texture stores (i.e. the distance) seems to be stored in a weird manner. It seems like it is normalized, as all values are between 0 and 1. Also, there is a 1x1x1 area around the viewer that does not have a projection, but this is due to the frustum and I think will be easy to fix (like offsetting the cameras back .5 into the center).
If you leave the fragment depth to OpenGL to determine you can take advantage of hardware hierarchical Z optimizations. Basically, if you ever write to gl_FragDepth in a fragment shader (without using the newfangled conservative depth GLSL extension) it prevents hardware optimizations called hierarchical Z. Hi-Z, for short, is a technique where rasterization for some primitives can be skipped on the basis that the depth values for the entire primitive lies behind values already in the depth buffer. But it only works if your shader never writes an arbitrary value to gl_FragDepth.
If instead of writing a fragment's distance from the light to your cube map, you stick with traditional depth you should theoretically get higher throughput (as occluded primitives can be skipped) when writing your shadow maps.
Then, in your fragment shader where you sample your depth cube map, you would convert the distance values into depth values by using a snippet of code like this (where f and n are the far and near plane distances you used when creating your depth cube map):
float VectorToDepthValue(vec3 Vec)
{
vec3 AbsVec = abs(Vec);
float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));
const float f = 2048.0;
const float n = 1.0;
float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp;
return (NormZComp + 1.0) * 0.5;
}
Code borrowed from SO question: Omnidirectional shadow mapping with depth cubemap
So applying that extra bit of code to your shader, it would work out to something like this:
void main () {
float shadowDepth = texture(shadowMap, ShadowCoord.xyz/ShadowCoord.w).x;
float testDepth = VectorToDepthValue(lightPos - PositionWorldSpace);
if (shadowDepth < testDepth)
visibility = 0.1;
}

GLSL Distance Field transparency

I am after smooth texture based outline effect in OpenGL. So far I tried mostly all kinds of edge detection algorithms which result mostly in crude and jagged outlines. Then I read about Distance Field. I found an example which does pretty nice distance field. Here is the GLSL code:
#version 420
layout(binding=0) uniform sampler2D colorMap;
flat in vec4 diffuseOut;
in vec2 uvsOut;
out vec4 outputColor;
const float ALPHA_THRESHOLD = 0.9;
const float NUM_SPOKES = 36.0; // Number of radiating lines to check in.
const float ANGULAR_STEP =360.0 / NUM_SPOKES;
const int ZERO_VALUE =128; // Color channel containing 0 => -128, 128 => 0, 255 => +127
int in_StepSize=15; // Distance to check each time (larger steps will be faster, but less accurate).
int in_MaxDistance=30; // Maximum distance to search out to. Cannot be more than 127!
vec4 distField(){
vec2 pixel_size = 1.0 / vec2(textureSize(colorMap, 0));
vec2 screenTexCoords = gl_FragCoord.xy * pixel_size;
int distance;
if(texture(colorMap, screenTexCoords).a == 0.0)
{
// Texel is transparent, search for nearest opaque.
distance = ZERO_VALUE + 1;
for(int i = in_StepSize; i < in_MaxDistance; i += in_StepSize)
{
if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 1.0))
{
i = in_MaxDistance + 1; // BREAK!
}
else
{
distance = ZERO_VALUE + 1 + i;
}
}
}
else
{
// Texel is opaque, search for nearest transparent.
distance = ZERO_VALUE;
for(int i = in_StepSize; i <= in_MaxDistance; i += in_StepSize)
{
if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 0.0))
{
i = in_MaxDistance + 1; // BREAK!
}
else
{
distance = ZERO_VALUE - i;
}
}
}
return vec4(vec3(float(distance) / 255.0) * diffuseOut.rgb, 1.0 - texture(colorMap, screenTexCoords).a);
}
void main()
{
outputColor= distField();
}
The result of this shader covers the whole screen using the diffuse color for filling the screen area outside the Distance Field outline.Here is how it looks like :
What I need is to leave all the area which has the solid red fill outside the distance field as transparent.
I came to the solution by using Distance Field gray scale 8 bit alpha map.Stefan Gustavson
describes in detail how to do it.Basically one needs to generate the distance field version of the original texture.Then this texture is rendered with the primitive normally in the first pass into an FBO.In the second pass the alpha blending mode should be on.The texture from the first pass in used with the screen quad.At this stage the the fragment shader samples the alpha from that texture.This results in both smooth edges and alpha transparency around the edges.
Here is the result:
Based on the screenshot I'm assuming you're rendering a fullscreen quad? If that's the case Tim just provided the answer, try:
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Before you render the quad. Obviously if you're going to render non-transparent stuff too, I advise you to render those first so you won't get depth buffer problems. When you're done drawing the transparent stuff, call:
glDisable( GL_BLEND );
To turn alphablending off again.