I have an issue with the water in my terrain, which is currently just a quad with a transparent blue colour.
When close up to it, it looks like this:
As you can see, it's simple enough - A flat transparent quad representing water.
However, when I get further away, this happens:
For those who can't see the GIF, or need an external link (or can't understand what's going on), the terrain is glitching around the water. If you look near the water near enough, you will see the terrain glitching above/below it.
Here is the code where I prepare the 3D view:
static void ready3D()
{
glViewport(0, 0, Display.getWidth(),Display.getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLU.gluPerspective(45, (float) Display.getWidth()/Display.getHeight(), 50f, 500f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
Does anyone know what the issue is, and how I could improve the precision of the depth buffer (presuming the depth buffer is the issue)?
It's difficult to tell from the GIF, but what I'm gathering is that you're experiencing an instance of Z-Fighting.
There are several solutions that tend to be most effective for dealing with Z-Fighting:
Increase the Resolution of the Z-Buffer.
Adjust the relative positions of the Water & Land to separate them further, thus reducing the chance of the two geometries colliding like this
Make use of the Stencil Buffer to ensure that objects are drawn correctly.
I've also seen solutions that try to disable Depth Testing when handling certain objects, but those are almost never good as a general solution.
Increasing depth buffer wouldn't help a lot as having an open world causes a big distance from zNear to zFar which maps to your depth buffer. One of common tricks is implementing logarithmic depth buffer. This gives you an ability to accent where do you need details but in current situation this need changes with altitude of your vehicle+camera system. So logarithmic buffer is not a solution and increasing "linear" buffer wouldn't affect a lot. I recommend to read this and this awesome articles about depth buffer.
Second point is that your landscape seems procedurally generated. If it is so vertices could spawn really close to water plane height. And winning in this floating point comparison war is not simple with just depth buffer manipulations (if possible at all).
Third point is that in general you don't want extra runtime job and that's the reason stencil buffer usage is questionable here (As JPhi1618 noticed).
So if you have an opportunity to modify your landscape generation algorithm from my point of view it is worth it. From JPhi1618 words again:
if Y is less than the level of the water even a little bit, make it way less than the water.
Related
I am using Java with OpenCV Library to detect Face,Eyes and Mouth using Laptop Camera.
What I have done so far:
Capture Video Frames using VideoCapture object.
Detect Face using Haar-Cascades.
Divide the Face region into Top Region and Bottom Region.
Search for Eyes inside Top region.
Search for Mouth inside Bottom region.
Problem I am facing:
At first Video is running normally and suddenly it becomes slower.
Main Questions:
Do Higher Cameras' Resolutions work better for Haar-Cascades?
Do I have to capture Video Frames in a certain scale? for example (100px X100px)?
Do Haar-Cascades work better in Gray-scale Images?
Does different lighting conditions make difference?
What does the method detectMultiScale(params) exactly do?
If I want to go for further analysis for Eye Blinking, Eye Closure Duration, Mouth Yawning, Head Nodding and Head Orientation to Detect Fatigue (Drowsiness) By Using Support Vector Machine, any advices?
Your help is appreciated!
The following article, would give you an overview of the things going under the hood, I would highly recommend to read the article.
Do Higher Cameras' Resolutions work better for Haar-Cascades?
Not necessarily, the cascade.detectMultiScale has params to adjust for various input width, height scenarios, like minSize and maxSize, These are optional params However, But you can tweak these to get robust predictions if you have control over the input image size. If you set the minSize to smaller value and ignore maxSize then it will work for smaller and high res images as well, but the performance would suffer. Also if you imagine now, How come there is no differnce between High-res and low-res images then you should consider that the cascade.detectMultiScale internally scales the images to lower resolutions for performance boost, that is why defining the maxSize and minSize is important to avoid any unnecessary iterations.
Do I have to capture Video Frames in a certain scale? for example
(100px X100px)
This mainly depends upon the params you pass to the cascade.detectMultiScale. Personally I guess that 100 x 100 would be too small for smaller face detection in the frame as some features would be completely lost while resizing the frame to smaller dimensions, and the cascade.detectMultiScale is highly dependent upon the gradients or features in the input image.
But if the input frame only has face as a major part, and there are no other smaller faces dangling behind then you may use 100 X 100. I have tested some sample faces of size 100 x 100 and it worked pretty well. And if this is not the case then 300 - 400 px width should work good. However you would need to tune the params in order to achieve accuracy.
Do Haar-Cascades work better in Gray-scale Images?
They work only in gray-scale images.
In the article, if you read the first part, you will come to know that it face detection is comprised of detecting many binary patterns in the image, This basically comes from the ViolaJones, paper which is the basic of this algorithm.
Does different lighting conditions make difference?
May be in some cases, largely Haar-features are lighting invariant.
If you are considering different lighting conditions as taking images under green or red light, then it may not affect the detection, The haar-features (since dependent on gray-scale) are independent of the RGB color of input image. The detection mainly depends upon the gradients/features in the input image. So as far as there are enough gradient differences in the input image such as eye-brow has lower intensity than fore-head, etc. it will work fine.
But consider a case when input image has back-light or very low ambient light, In that case it may be possible that some prominent features are not found, which may result in face not detected.
What does the method detectMultiScale(params) exactly do?
I guess, if you have read the article, by this time, then you must be knowing it well.
If I want to go for further analysis for Eye Blinking, Eye Closure
Duration, Mouth Yawning, Head Nodding and Head Orientation to Detect
Fatigue (Drowsiness) By Using Support Vector Machine, any advices?
No, I won't suggest you to perform these type of gesture detection with SVM, as it would be extremely slow to run 10 different cascades to conclude current facial state, However I would recommend you to use some Facial Landmark Detection Framework, such as Dlib, You may search for some other frameworks as well, because the model size of dlib is nearly 100MB and it may not suit your needs i f you want to port it to mobile device. So the key is ** Facial Landmark Detection **, once you get the full face labelled, you can draw conclusions like if the mouth if open or the eyes are blinking, and it works in Real-time, so your video processing won't suffer much.
I have a program that utilizes Path2D.Float to draw a vector object (a large fractal design). My code allows zooming and panning. I have an axis object that has methods to convert world coordinates (pairs of doubles) to display coordinates (pairs of floats) based on the current scaling settings (stored in the axis object).
Anyways, the vector graphic is large and detailed and contains many line segments in world coordinates. Each time the user zooms or pans, new Path2D objects are created and rendered to the screen.
Everything is perfectly smooth when zoomed out. The problem occurs when I zoom in to a certain depth. Apparently the Path2D lines get very long and this slows down their rendering (even though the vast majority is outside the viewing area!). It's not my conversion algorithms consuming resources. I profiled it and it's definitely the Java graphics drawing algorithm that's slowing down due to the size of the lines in comparison to the small clipping region.
I was hoping there was a way to get Java to deal with the clipping of large lines automatically. I do call setClip() from the graphics object before drawing. I don't see what's taking so much time. Is there something problematic/inefficient about the clipping algorithm when lines are long in comparison the clipping rectangle? I don't think I'm zooming so far that my conversion from world coordinates to display coordinates is causing overflow. I'll have to check for this. If that's the case I'll try using Path2D.double instead.
Anyways, any help appreciated. I'm sure I'll eventually figure this out but I hope someone that's encountered the same problem can give me a pointer so it doesn't take so long to figure out.
I've not used paths when zooming, but I have used them for drawing some very complex shapes with textures & gradients etc. Some issues I had were:
In my experience, I had to avoid creating new Path2D objects on a per frame basis because of performance issues, not just for their recreation execution, but because it caused a lot of garbage collection with generating & then dropping so many so quickly, which slowed things down. If your shape doesn't change, cache the generated path.
Avoid clipping with paths - where possible stick to rectangles - paths seem to give rough edges on curves and are more costly to use.
Even when clipping to smaller regions, simply asking to draw large regions could slow things down. Consider when the user zooms in to tessellate your shape, i.e. the shape is only as big as your viewport. Perhaps as you say maybe there is an issue with the clip function when dealing with large volume areas, so tessellation might help here.
I am building a 2D top-down tile based game in Java. Naturally you can pan around and zoom in on the game, currently zooming in on 10 different levels, where each tile ranges 10x10 pixels to 100x100 pixels appropriately. Currently, the the tiles for each zoom level are stored in separate sprite sheets, read in at the startup of the program and stored in a buffered image array. I am sure this can't be the best way to go about this.
I am looking for any tips to enhance efficiency for the long-term, would it be better to have the 100x100 tiles only and scale them dynamically in java; somehow use vector graphics in java (I'm sure how, but I'm sure google could help me) or what?
Many thanks!
I'd go dynamic.
Normally in computer graphics you use matrices that, applied to the graphics context, modify everything you draw on it.
This is used to modify position, scale, rotation, etc. Rather than subtract the camera position to every tile, you apply the translation once to the graphics context, and then you draw your tiles in world position. The graphics context will take care of placing the tiles in the correct screen space.
I suggest you the following reads:
http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html
http://www.javalobby.org/java/forums/t19387.html
If you're doing fixed zooming (i.e. each zoom level is a fixed distance from the camer), as opposed to fluid zooming (the player can zoom in by 3.3x, 7.5x, and not just 1x, 2x, 3x, etc.) then it's massively wasteful to try to solve this by simply applying a zoom transform. It's tempting because that's the least complicated approach, and it's easy to understand from an implementation standpoint, but that means that at maximum zoom-out, you're going to be rendering an area that's 10x larger in the X direction, and 10x larger in the Y direction - so the area of the world that you have to render is 100x larger than at maximum zoom-in. I also doubt that you'll like the way your textures get squished by the hardware as you're zooming out. Computer graphics isn't the same as optics - subpixel rendering, and other things that happen in computer graphics aren't going to make your textures look very good if you hand that task off the the software/hardware.
Even if you do fluid zooming, I would still do level-of-detail textures, and dynamically swap them out depending on the distance between the world being rendered, and the camera.
Also, 10 zoom levels? Are you sure you really need 10 zoom levels? Zoom is usually used in 2D games to allow you to perform different activities at different levels of detail because a particular zoom level is especially well suited for a certain set of activities. I don't remember any 2D game that needed 10 zoom levels to accomplish this. 3-5 is the most I've ever seen, and I've never felt that it wasn't enough. It also seems like a lot of art work to produce the images at every zoom level for 10 zoom levels.
You're also likely going to find that applying an AffineTransform sounds like a good idea, but that it's extremely computationally expensive, and if you need 60fps performance, you're highly unlikely to achieve it this way. Don't take my word for it though, go try it and see how badly it falls over on itself.
I'm planning on implementing a new set of figures in my game: plain circles. The number of drawn sprites (in this case circles) starts with 2-3, and can go up endlessly (potentially). The maximum will probably be around 60 though. In total there will have to be 5 types of circles, each with a different color and probably size too. Now seeing as I won't implement it until monday I thought I'd ask it at stackoverflow.
Does anybody already know which method is faster?
Bitmaps are almost always faster than any kind of draw. With the right preparation drawing a bitmap is simply dumping memory to the screen. Drawing a circle involves a significant number of calculations, including anti-aliasing. I presented a paper which covered this at JavaOne 2009, but papers that old seem to have been removed from the site.
It does depend on how big your bitmap would need to be, but for sizes under 10 pixels bitmap sprites are much faster than even simple graphic operations like drawing crosses and lines. You also need to make sure that your sprite won't require any kind of transform when it is drawn, and that it is a form compatible with the screen memory.
If every circle is to be a different color or thickness, or worse a different size, then that's another matter. The cost of creating each bitmap would outweigh the savings.
You should also remember the first rule of optimization: don't do it unless you have to.
I have successfully implemented a simple 2-d game using lwjgl (opengl) where objects fade away as they get further away from the player. This fading was initially implemented by computing distance to origin of each object from the player and using this to scale the objects alpha/opacity.
However when using larger objects, this approach appears a bit too rough. My solution was to implement alpha/opacity scaling for every pixel in the object. Not only would this look better, but it would also move computation time from CPU to GPU.
I figured I could implement it using an FBO and a temporary texture.
By drawing to the FBO and masking it with a precomputed distance map (a texture) using a special blend mode, I intended to achieve the effect.
The algorithm is like so:
0) Initialize opengl and setup FBO
1) Render background to standard buffer
2) Switch to custom FBO and clear it
3) Render objects (to FBO)
4) Mask FBO using distance-texture
5) Switch to standard buffer
6) Render FBO temporary texture (to standard buffer)
7) Render hud elements
A bit of extra info:
The temporary texture has the same size as the window (and thus standard buffer)
Step 4 uses a special blend mode to achieve the desired effect:
GL11.glBlendFunc( GL11.GL_ZERO, GL11.GL_SRC_ALPHA );
My temporary texture is created with min/mag filters: GL11.GL_NEAREST
The data is allocated using: org.lwjgl.BufferUtils.createByteBuffer(4 * width * height);
The texture is initialized using:
GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, dataBuffer);
There are no GL errors in my code.
This does indeed achieve the desired results.
However when I did a bit of performance testing I found that my FBO approach cripples performance. I tested by requesting 1000 successive renders and measuring the time. The results were as following:
In 512x512 resolution:
Normal: ~1.7s
FBO: ~2.5s
(FBO -step 6: ~1.7s)
(FBO -step 4: ~1.7s)
In 1680x1050 resolution:
Normal: ~1.7s
FBO: ~7s
(FBO -step 6: ~3.5s)
(FBO -step 4: ~6.0s)
As you can see, this scales really badly. To make it even worse, I'm intending to do a second pass of this type. The machine I tested on is supposed to be high end in terms of my target audience, so I can expect people to have far below 60 fps with this approach, which is hardly acceptable for a game this simple.
What can I do to salvage my performance?
As suggested by Damon and sidewinderguy I successfully implemented a similar solution using a fragment shader (and vertex shader). My performance is little bit better than my initial cpu-run object-based computation, which is MUCH faster than my FBO-approach. At the same time it provides visual results much closer to the FBO-approach (Overlapping objects behave a bit different).
For anyone interested the fragment shader basically transforms the gl_FragCoord.xy and does a texture lookup. I am not sure this gives the best performance, but with only 1 other texture activated I do not expect performance to increase by omitting the lookup and computing the texture value directly. Also, I now no longer have a performance bottleneck, so further optimizations should wait till it is found to be required.
Also, I am very grateful for the all the help, suggestions and comments I received :-)