Diffuse light/shadow - opengl

I just implemented a light system in my engine. In the following screenshot you can see a light (the yellow square) in action:
Take into account that on top of the light illuminating the scenario, its also implemented a FOV which will occlude anything outside your field of view. Thats why the left part of the shadow seems so off.
As you can see the light's shadows are pretty "hard", as they won't even illuminate one bit of the area outside its direct reach.
In order to make the lights look better, I applied a filter to them, which pretty much limits the range to be illuminated, and also iluminate the area slightly within this limit:
In the big yellow circle you can see how the area is illuminated even if no direct light reaches it.
This solution however comes with some undesirable side effects. As you can see in the following screenshot, even if no light at all reaches an area, it will be illuminated if its too close to the light source:
I was wondering if there is any way to achieve what im trying to do by using shaders properly.
The main problem that I encounter comes from how I draw these shadows.
1) First I take the structures within the light's range.
At this point, I'm working with vertex, as they define the area of the shadow casting items:
2) Then, for each of these objects, I calculate the shadow they cast individually:
The shadow they cast is done by the CPU, by calpulating projections for each vertex of the body.
3) Then the GPU draws these shapes into a texture to compose the final shadow:
The problem I find is that making this difuse shadow effect, I need the final shadow. If I were to calculate the diffused shadows in step 2), a gap of light would appear between solids B and C.
But if I difuse the shadows in step 3, I no longer have the vertex information, as all the info I have are the 3 local textures added up together in one final texture.
So, is there anyway to achieve this? My first idea would be to pass a varying to the fragmentshader to calculate how much light comes into the dark area, but since I'll be processing this info on the final shadow, which has no vertex information, I'm completely lost about what approach I should use to make this.
I might be completely wrong on this approach, since I have very very limited experience with shaders.
Here is an example of what I have right now, and what I desire:
What I have: Plain illumination withing the light radius (which causes the light to clip through walls.
What I want: Shadow is more intense the farther away it is from where the light ends.

I think that no matter what you do, you're going to have to calculate the light falloff differently for the areas of the scene that don't have direct visibility to the original light source. I'm not sure how you're actually applying the shadow volume to the scene, but you might be able to do something like classify the edges as you're generating the shadow volume (i.e. did they come from a wall or from the line from the light to a corner?), and treat them accordingly.
In short I don't think there's any clever shader-specific trick you can pull off to fix this problem. It's a limitation of the algorithm you're using, so you need to improve the algorithm to take into account the different nature of the edges in your shadow volume.
--- Edit ---
Ok I think your best bet is going to be to create two shadow volumes (or rather shadow areas since we're working in 2D). One will be exactly as you have now, the other will be smaller -- you'll want to exclude the areas that are in "soft" shadow. Then you'll have three categories in your fragment shader: total shadow, soft shadow, and unshadowed.
To create the second shadow map, I think you'll want to do something like add a fixed angle to the edges that are created by the light shining around a corner.
--- Edit #2 ---
I think you can solve the problem of the gap between objects B and C by taking the silhouette of the shadow areas and the outer box of the scene. So for each of your shadow areas, you'd find the two outermost points that intersect the outer box, then throw out all the line segments in between and replace them with that portion of the box. I feel like I should be able to name that algorithm but it escapes me at the moment...
Original Scene:
Individual "hard" shadows:
Now union the shadows together:
Finally, trace around the shadows, keeping to the edges of the box. The corners you want to identify are the ones in yellow. As you are tracing around the perimeter of the shadows, you want to cut across the edge of the box until you reach the opposite corner. Not the easiest thing to code but if you've gotten this far I think you can figure it out :)
Alternatively, it might be easier to simply consider the lit areas. For example, you could do something like take the difference of the scene box and the unioned shadowed area This will usually give you multiple polygons; discard everything except the one that contains the light because the rest are the false gaps.

Related

Algorithm to correct wrong normal direction on 3D model

i am new to 3D math, but i am facing a problem that when i am importing a model to CAD program - (single sided light/ open scene graph) - there are a lot of faces from meshs, Black !
When i flip the normal manually for each of the faces i got the correct material and texture.
my question is, if i know vertices table and normals table for every mesh in the model, can i write an algorithm that will correct all wrong normal direction automatically, i mean it must detect the wrong normals without any help form users and correct them.
i thought about an idea that needs image processing, i know nothing about image processing, so if you can help with from where i should start to achieve this :
first i will assume every blacked face is a wrong normal.
second i will direct a light form the camera to the mesh, and if are all the pixels in black then flip the normal.
and do this for all meshs.
i think i will have a speed issue but that all what i think about.
thanks.
the wrong red plane and the black one, they are in the same model and both of them must have red color, but as i mentioned the black one his normals are flipped.
OSG has a visitor class in osgUtil that can calculate all the vertex normals for you, called smoothingVisitor. You just need to point it at your model after you've loaded it, eg:
// recalculate normals with the smoothing visitor
osgUtil::SmoothingVisitor sv;
loadedModel->accept(sv);
This will clobber existing vertex normals, or create new ones if they don't exist. Just looking quickly at it, it looks like it assumes your geometry is triangles, not quads as you've drawn, but I could be wrong.
I suspect something is up with the indexing, if not then it is probably better to ignore the normal's table entirely. I'm not really sure about the details, but I assume it is 1 normal/vertex, so approaching it would involve calculating poligon normals, which you can do with:
normalize(cross_product(vert0 - vert1, vert0 - vert2));
After that averaging the normals of the poligons sharing the vertex should do.
Calculating the dot product of the freshly calculated normal and the original normal would reveal if the original normal is way off.
Anyways for your problem StackOverflow isn't really the one, there are other Stack Exchange sites that are actually specialized for similar problems. Also there are way too few informations about the issue so helping isn't easy as well.

OpenGL/OpenTK Fill Interior Space

I am looking for a way to "fill" three-dimensional geometry with color, and quite possibly a texture at some time later on.
Suppose for a moment that you could physically phase your head into a concrete wall, logically you would see only darkness. In OpenGL, however, when you do this the world is naturally hollow and transparent due to culling and because of how the geometry is drawn. I want to simulate the darkness/color/texture within it instead.
I know some games do this by overlaying a texture/color directly over the hud--therefore blinding the player.
Is there another way to do this, though? Suppose the player is standing half in water; they can partially see below the waves. How would you fill it to prevent them from being able to see clearly below what is now half of their screen?
What is this concept even called?
A problem with the texture-in-front-of-the-camera method is a texture is 2D but you want to visualize a slice of a 3D volume. For the first thing you talk about, the head-inside-a-wall idea, I'll point you to "3D/volume texturing". For standing-half-in-water, you're after "volume rendering" with "absorption" (discussed by #user3670102).
3D texturing
The general idea here is you have some function that defines a colour everywhere in a 3D space, not just on a surface (as with regular texture mapping). This is nice because you can put geometry anywhere and colour it in the fragment shader based on the 3D position. Think of taking a slice through the volume and looking at the intersection colour.
For the head-in-a-wall effect you could draw a full screen polygon in front of the player (right on the near clipping plane, although you might want to push this forwards a bit so its not too small) and colour it based on a 3D function. Now it'll look properly solid and move ad the player does and not like you've cheaply stuck a texture over the screen.
The actual function could be defined with a 3D texture but that's very memory intensive. Instead, you could look into either procedural 3D colour (a procedural wood or brick shader is pretty common as an example). Even assuming a 2D texture is "extruded" through the volume will work, or better yet weight 3 textures (one for each axis) based on the angle of the intersection/surface you're drawing on.
Detecting an intersection with the geometry and the near clipping plane is probably the hardest bit here. If I were you I'd look at tricks with the z-buffer and make sure to draw everything as solid non-self-intersecting geometry. A simple idea might be to draw back faces only after drawing everything with front faces. If you can see back faces that part of the near plane must be inside something. For these pixels you could calculate the near clipping plane position in world space and apply a 3D texture. Though I suspect there are faster ways than drawing everything twice.
In reality there would probably be no light getting to what you see and it should be black, but I guess just ignore this and render the colour directly, unlit.
Absorption
This sounds way harder than it actually is. If you have some transparent solid that's all the one colour ("homogeneous") then it removes light the further light has to travel through it. Think of many alpha-transparent surfaces, take the limit and you have an exponential. The light remaining is close to 1/exp(dist) or exp(-dist). Google "Beer's Law". From here,
vec3 Absorbance = WaterColor * WaterDensity * -WaterDepth;
vec3 Transmittance = exp(Absorbance);
A great way to find distances through something is to render the back faces (or seabed/water floor) with additive blending using a shader that draws distance to a floating point texture. Then switch to subtractive blending and render all the front faces (or water surface). You're left with a texture containing distances/depth for the above equation.
Volume Rendering
Combining the two ideas, the material is both a transparent solid but the colour (and maybe density) varies throughout the volume. This starts to get pretty complicated if you have large amounts of data and want it to be fast. A straight forward way to render this is to numerically integrate a ray through the 3D texture (or procedural function, whatever you're using), at the same time applying the absorption function. A basic brute force Euler integration might start a ray for each pixel on the near plane, then march forwards at even distances. Over each step while you march you assume the colour remains constant and apply absorption, keeping track of how much light you have left. A quick google brings up this.
This seems related to looking through what's called "participating media". On the less extreme end, you'd have light fog, or smoky haze. In the middle could be, say, dirty water. And the extreme case would be your head-in-the-wall example.
Doing this in a physically accurate way isn't trivial, because the darkening effect is more pronounced when the thickness of the media is greater.
But you can fake this by making some assumptions and giving the interior geometry (under the water or inside the wall) darker by reduced lighting or using darker colors. If you care about the depth effect, look at OpenGL and fog.
For underwater, you can make the back side of the water a semi-transparent color that causes stuff above it to have a suitable change in color.
If you really want to go nuts with accuracy, look at Kajia's Rendering Equation. That covers everything (including stuff that glows), but generally needs simplification and approximations to be more useful.

Adding sunlight to a scene

I am rendering some interactive scene in 3D and I am wondering: How do I add sunlight to it? I'll try to explain the best how I have it setup now.
What you see right now is that the directional light (the sun) is denoted by the yellow dot, which I want to replace with a realistic sunlight.
The current order of drawing is:
For all objects:
Do a light depth pass for the shadow.
Then for all objects:
Do a draw pass for the object itself, using the light depth texture.
Where would I add adding a realistic sunlight? I have a few ideas though about it:
After the current drawing order, save the output into a texture, and use a shader that takes the texture and adds sunlight on top of it.
After the current drawing order, use a shader that adds the sunlight simply to what has been drawn so far, such that it will be drawn after everything is on the screen.
Or maybe draw the sunlight before the rest of the scene gets drawn?
How would you deal with rendering a nice sunlight that represents a real life sun?
To realistically simulate sunlight, you probably need to implement some form of global illumination. A lot of the lighting we see on objects comes not directly from the light source, but from light bounced off of other objects. Global illumination simulates the bounced light.
[Global Illumination] take[s] into account not only the light which comes directly from a light source (direct illumination), but also subsequent cases in which light rays from the same source are reflected by other surfaces in the scene, whether reflective or not (indirect illumination).
Another techniques that may not be physically accurate, but gives "nice" looking results is Ambient Occlusion:
ambient occlusion is used to represent how exposed each point in a scene is to ambient lighting. So the enclosed inside of a tube is typically more occluded (and hence darker) than the exposed outer surfaces; and deeper inside the tube, the more occluded (and darker) it becomes.

Deferred Lighting | Point Lights Using Circles

I'm implementing a deferred lighting mechanism in my OpenGL graphics engine following this tutorial. It works fine, I don't get into trouble with that.
When it comes to the point lights, it says to render spheres around the lights to only pass those pixels throught the lighting shader, that might be affected by the light. There are some Issues with that method concerning cullface and camera position precisely explained here. To solve those, the tutorial uses the stencil-test.
I doubt the efficiency of that method which leads me to my first Question:
Wouldn't it be much better to draw a circle representing the light-sphere?
A sphere always looks like a circle on the screen, no matter from which perspective you're lokking at it. The task would be to determine the screenposition and -scaling of the circle. This method would have 3 advantages:
No cullface-issue
No camereposition-in-lightsphere-issue
Much more efficient (amount of vertices severely reduced + no stencil test)
Are there any disadvantages using this technique?
My second Question deals with implementing mentioned method. The circles' center position could be easily calculated as always:
vec4 screenpos = modelViewProjectionMatrix * vec4(pos, 1.0);
vec2 centerpoint = vec2(screenpos / screenpos.w);
But now how to calculate the scaling of the resulting circle?
It should be dependent on the distance (camera to light) and somehow the perspective view.
I don't think that would work. The point of using spheres is they are used as light volumes and not just circles. We want to apply lighting to those polygons in the scene that are inside the light volume. As the scene is rendered, the depth buffer is written to. This data is used by the light volume render step to apply lighting correctly. If it were just a circle, you would have no way of knowing whether A and C should be illuminated or not, even if the circle was projected to a correct depth.
I didn't read the whole thing, but i think i understand general idea of this method.
Won't help much. You will still have issues if you move the camera so that the circle will be behind the near plane - in this case none of the fragments will be generated, and the light will "disappear"
Lights described in the article will have a sharp falloff - understandably so, since sphere or circle will have sharp border. I wouldn-t call it point lightning...
For me this looks like premature optimization... I would certainly just be rendering whole screenquad and do the shading almost as usual, with no special cases to worry about. Don't forget that all the manipulations with opengl state and additional draw operations will also introduce overhead, and it is not clear which one will outscale the other here.
You forgot to do perspective division here
The simplest way to calculate scaling - transform a point on the surface of sphere to screen coords, and calculate vector length. It mst be a point on the border in screen space, obviously.

Voxel Cone Traced Soft Shadows

I have recently implemented soft shadows using voxel cone tracing in OpenGL 4.3 by tracing a cone in the direction of the light and accumulating opacity values.
The key thing that I am trying to resolve or hide is the very voxelized shadowing effect as the occluded surface gets closer to the occluder, as well as hide the clear spots in the shadow due to surface voxelization. I am using low resolution voxels 64x64x64; however, even if I use higher resolution voxels, some of the low-res voxels at a higher mip-map level are still captured in the trace.
So here's what my first idea is: I want to be able to keep the softest parts of the shadow that is furthest away and replace the parts of the shadow that is closer to the occluder with a shadow map. The shadow map will fade as it is further away from each occluder and I will somehow blend it into with the cone traced shadows.
Can anyone think of a way to fade a shadow away based on distance from each object for a shadow-map and then have it blend smoothly into the cone-traced shadow?
Another idea I have would be to somehow ray-trace shadows onto surfaces that are closer to an occluder, but this would probably be too expensive.
Alternatively, I would welcome any other ideas to help improve my soft shadow algorithm.
I've also put up a video to show it in motion:
https://www.youtube.com/watch?v=SUiUlRojBpM
Still haven't found a way to resolve the shadowing issue.
I'm guessing the "clear spot" artifacts are occurring due to large voxel sizes only being partially filled with geometry: "accumulating opacity values.". How many samples are you taking when converting from rasterized pixels to voxels? If the sample volume/voxel volume is small then there could be issues with correctly rendering transparency - there will be noise indicated by lighter areas.
Also, are your voxels' transparency direction dependent? Based on the author's original paper. Directional dependence is important to ensure semi-opaque voxels are rendered correctly.
A quick picture to explain
"for a shadow-map and then have it blend smoothly into the cone-traced shadow?"
This seems like you are kind of shooting yourself in the foot. You get an even larger performance hit and get the disadvantages of both shadow mapping and voxel cone tracing. Voxel cone tracing is expensive but can give nice soft shadows and do global illumination. Shadow mapping is better at doing hard shadows and is faster for smaller scenes, but as you add more geometry you end up redrawing the same stuff multiple times, at least once for each light.
Great work btw. I came across your problem while doing preliminary research for my own DirectX implementation of voxel cone tracing.
[Edit]
I realized that I made a typo in the picture. The picture on the right should be 4/64, rather than 4/16. I forgot about the Z dimension.
Well, in this case you can do it by adding more lights. You can add more lights closer to the original one and then compose the shadow of a light with the shadows of a bunch of closer lights. That is the 'area light' effect.