What is the best way to display millions of images in Java? - java

You see that ?
Each brick of each house is an image of 16x16 pixels.
What you can see here a version based on simple JavaFX, with some Imageview moved on X and Y to give the effect of "construction".
I just adapt this to Swing using paintComponent.
The problem:
- With JavaFX: my computer has trouble. What you see on the picture took 2 seconds to load and it is then moving very slow and jerky.
- With Swing: I do not know how to adapt each block according to brightness, shadows, etc.. So it looks like this:
What method should I chose? Both have major drawbacks. I would have liked to keep the JavaFX method but also to find something else than Imageview. It should not be a good idea.

For information on Swing optimizations and implementations, see other answers as my answer is JavaFX specific.
Should you stick with a JavaFX implementation, here are a couple of things to try:
Use node.setCache(true) to switch on node caching.
Use node.setCacheHint(CacheHint.SPEED) to enable high speed node transforms.
Provide an implementation with no effects and another with effects and see if the one without effects performs noticeably better. (If that's the case you may need to use a more efficient effect chain or forgo some effects altogether).
Check the JavaFX system requirements to ensure that your setup meets the minimum requirements for hardware acceleration in terms of hardware/os/driver combinations.
If you are using Regions and css based processing be careful that the css system is not causing too much overhead (by, for example, having a version of the code which does not use css and comparing it's performance).
If needed, implement a level of detail zoom, (e.g. when zoomed out provide a single image for the entire house rather than a separate image for each house tile).
Make sure you are only loading a given Image once and reusing it in multiple ImageViews.
Use a profiler to identify bottlenecks.
Vary the test cpu or graphics card to see if either of those are a bottleneck.
Try a Java 8 preview, which features many internal performance optimizations for JavaFX.
If you are loading a lot of images, use background loading and have an animation or progress bar playing in front while the images are loading.
If you are loading lots of images, scale them upfront in the Image constructor so that they don't take up too much memory or require (potentially) extra processing power for the extra pixels (only really a consideration if you are using a lot of different very high resolution textures - which you don't seem to be doing).
For example:
Image tile = new Image("tile.png");
Group house = new Group();
house.setCache(true);
house.setCacheHint(CacheHint.SPEED);
Effect lighting = new Lighting();
for (int i = 0; i < houseWidth; i++) {
// here is the critical part => don't do new ImageView(new Image("tile.png"))
ImageView tileView = new ImageView(tile));
tileView.setEffect(lighting);
tileView.setCache(true);
tileView.setCacheHint(CacheHint.SPEED);
house.add(tileView);
}
Mantrid's suggestions are interesting. I do believe that, with JavaFX you don't need to implement a dirty rectangle algorithm yourself (as the underlying platform is able to take care of dirty region processing for you). It may be that, because it is a generic mechanism, it isn't providing the level of optimization required for your specific case, in which case you need to handle the dirty processing yourself (e.g. by removing nodes from the scenegraph and re-adding them as appropriate).
Additionally, pre-calculating the blur/brightness/etc on the images could be done by defining effects in JavaFX, applying the effects to an offscreen ImageView node, then taking a snapshot of the offscreen ImageView node to get a pre-calculated image. This technique would allow you to reuse your existing JavaFX effects pipeline without the need to re-implement it using the ConvolveOp mechanism. Perhaps you may get the same performance level by just setting cache to true and cacheHint to speed on the ImageView nodes, as I believe this does a similar kind of thing behind the scene (i.e. increases speed at the cost of increased memory usage).
The JavaFX scenegraph is pretty efficient and can handle thousands of nodes. However, you may have more than that in your application. If the above optimization points don't help you, you may want to calculate your node count and post a reference to your question (and perhaps some source) to the open-jfx mailing list where the JavaFX developers who know the details of JavaFX application optimization are.
JavaFX 8 has far better support for 3D scenegraphs in than the (mostly useless) 3D scenegraph in JavaFX 2.2. It seems that your current application is psuedo-3d where you transform 2D objects, individually apply lighting effects and adjust the brightness of each tile to get a 3D look. If that's the case, using a fully hardware accelerated 3D scenegraph with a unified 3D lighting model may end up performing better, looking better and being easier to work with - you would have to evaluate it in the context of your application to see if it is worth switching your app from a 2D JavaFX scenegraph to a 3D JavaFX scenegraph or from JavaFX to Swing or some other tech like libgdx.
Addendum
Answers to some of Mizur's additional questions:
So why are they so power-consuming?
As can be seen from my answer, there are many aspects that go into performance, so singling out one particular reason as to why something is power-consuming is sometimes difficult and often not possible. Sometimes it is a combination of things which contribute to performance issues. The biggest wins usually come from optimizing stuff executed in inner most loops or by changing the strategy used to solve a problem.
If they need so much, please let me move tiles, or please just be displayed, no?
In terms of only consuming resources for the stuff you move, the JavaFX scenegraph has some optimizations for that and things like the cachehints can further improve performance for that. Perhaps they aren't enough for your particular use case or the way in which you are using the system. You may need to change your algorithms to reduce the system load.
Is there a way to generate images of each building with this technique of Imageview, then to integrate these images of buildings in the final scene?
Yes - you could render a building to an offscreen scene using many images and nodes, snapshot the offscreen scene to create a single image, then overlay that image over your final scene.

modifying blur/brightness/etc on the images before they are drawn
I haven't used it myself, but here's a hint - use Swing/AWT Kernel+ConvolveOp mechanism: http://www.java-tips.org/java-se-tips/java.awt.image/styling-digital-images-with-convolveop.html
BufferedImage biSrc = ...
BufferedImage biDest = ...
float[] data = new float[] { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f, 0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
convolve.filter(biSrc, biDest);
operations are defined via a 3x3 matrix (data). you can do a search for examples for brigthness, blur etc.
the picture took 2 seconds to load but it is moving very slow and jerky after
use Dirty Rectangles algorithm: Dirty Rectangles

Related

Rendering: To draw-once or to re-draw? Would JOGL + Java2D + Java Swing be cumbersome?

1) Re-Draw Vs Draw
Kind of a philosophical question, but... what is the "correct" or "accepted" way to render a game (2d, I understand how OGL perspecives work...) at different resolutions? Should I include separate sizes for my images (like Android APKs) and resize each object individually at draw on one canvas, or should I draw on a set-resolution drawing canvas, then resize that image onto another display canvas? I'm speaking generally, but, if you need me to be specific I'm using Java to build the engine.
Foreseeable benefits/issues:
#1) Resize at Draw
+ No additional drawing step
+ Sweet resolution
- Possible math/physics/placement issues
- Tons of math each step for scale
- Lots of resources
#2) Resize at Render
+ No additional math; one step
+ One set of images; smaller res. package
+ One set canvas size (easier to do math/phys./placement)
- Additional drawing step
- Poor resolution =(
It would seem that #2 is the obvious choice because of the number of benefits vs issues, but... is it? Is there a standard way to resize 2D games?
2) JOGL + Java2D + Java Swing
Would it be cumbersome to use JOGL, Java2D, and Java Swing at the same time? Would it be worth it to do 2D or layouts in JOGL? Why or why not?
EDIT: Using a BufferedImage to draw on and rendering the BufferedImage to the size of the panel with respect to aspect ratio is incredibly inefficient in swing. Apparently it's better to draw immediately to the panel, while resizing each image/element individually. Not my first hypothesis...
EDIT 2: Silly me... just scale and translate the graphics context to the size of the adjusted resolution before any other operations. The performance boost is super-dooper awesome. THIS is the correct answer to the question. DRAW ONCE, to scale/translation. B)
I can't answer your second question fully as I do not have much experience with JOGL or Java2D, but I don't see any reason for them to ever conflict or be cumbersome.
For your first question, I can definitely say that it depends. What's your target audience? Is your game memory intensive (Ever notice that many games have a high res/low res option)? Is this a game that will be available for vastly different screen sizes? If so you might want to provide 2-3 different "packages" of your assets, each scaled at a different size of the original (the largest one). The math to draw the images isn't as much as you think.
In addition:
If you build the game the right way, you wouldn't have to do much math at all. If you have some sort of Camera class that takes care of the viewing of your GameWorld then you simply have to scale the Camera's image instead of scaling each image independently.

Efficient 3D block rendering with Libgdx

To start with,I am pretty new to 3D programming and libgdx.
I looked at a few tutorials and I already render the scene I want. I have some 1x1x1 blocks, created with ModelBuilder.createRect() for every visible face, so if another block covers a face of this block, there is no rect created for this block. Also the top and bottom rect is not needed, as I can never see them (except for the floor). So I thought, that this is pretty efficient. I also have Backface culling enabled and I do Viewfrustum culling. However, if I look in a direction, where many blocks are in my viewfrustum the FPS go down to 15-20. This is still okay for me, as my laptop is over 5 years old and its performance is not the best, but this answer made me think.
"ModelBuilder is used for debug only". Okay, but how should i then create my boxes? Why should i create a Model in a Modeling app (like Blender), for simple squares? By doing this i couldn't even cull the faces, which are occupied by other blocks.
So my question is:
How can i create and render those boxes the most efficient way?
ModelBuilder#createRect will create a new model for each rectangle. When rendering a (part of a) model instance, it implies a draw call. Therefor ModelBuilder#createRect is extremely inefficient. It is better to combine multiple rectangle into a single (part of a) Model. This can be done using:
modelBuilder.begin();
MeshPartBuilder mpb = modelBuilder.part(....);
mpb.rect(...); // first rect.
mpb.rect(...); // second rect.
// etc.
Model model = modelBuilder.end();
Note that this is still not efficient enough for e.g. a voxel engine. If you are aiming to optimize for voxels, you'll probably want to build the mesh (after frustum culling and depth sorting) in a custom RenderableProvider. Here's an example: https://github.com/libgdx/libgdx/tree/master/tests/gdx-tests/src/com/badlogic/gdx/tests/g3d/voxel

3D Shadow implementation idea

Lets assume your eye is in the surface point P1 on an object A and there is a target object B and there is a point-light source behind object B.
Question: am i right if i look to the light source and say "i am in a shadow" if i cannot see the light because of object B ?. Then i flag that point of object A as "one of the shadow points of B on A" .
If this is true, then can we build a "shadow geometry"(black-colored) object on the surface of A then change it constantly because of motion of light,B,A, etc... in realtime ? Lets say a sphere(A) has 1000 vertices and other sphere (B)has 1000 vertices too, so does this mean 1 milion comparations? (is shadowing, O(N^2) (time) complexity?). I am not sure about the complexity becuse the changing the P1(eye) also changes the seen point of B (between P1 and light source point). What about the second-order shadows and higher (such as lights being reflecting between two objects many times) ?
I am using java-3D now but it doesnt have shadow capabilities so i think of moving to other java-compatible libraries.
Thanks.
Edit: i need to disable the "camera" when moving the camera to build that shadow. How can i do this? Does this decrease the performance badly?
New idea: java3D has built-in collision detection. I will create lines(invisible) from light to target polygon-vertex then check for a collision from another object. If collision occurs, add that vertex corrd. to the shadow list but this would work only for point-lights :( .
Anyone who supplys with a real shade library for java3d, will be much helpful.
Very small sample Geomlib shadow/raytracing in java3D would be the best
Ray-tracing example maybe?
I know this is a little hard but could have been tried by at least a hundred people.
Thanks.
Shadows is probably the most complex topic in 3D graphics programming, and there are many approaches, but the best option should be identified according to the task requirements. The algorithm you are talking about is the simplest way to implement shadows from a spot light source onto the plane. It should not be done on the CPU, as you already use GPU for 3D rendering.
Basically the approach is to render the same object twice: once from the camera view point, and once from the light source point. You will need to prepare model view matrices to convert between these two views. Once you render the object from the light point, you get the depth map, in which each point lies closest to the light source. Then, for each pixel of the normal rendering, you should convert its 3D coordinates into the previous view, and check against the corresponding depth value. This essentially gives you a way to tell which pixels are covered by shadow.
The performance impact comes from rendering the same object twice. If your task doesn't assume high scalability of shadow casting solution, then it might be a way to go.
A number of relevant questions:
How Do I Create Cheap Shadows In OpenGL?
Is there an easy way to get shadows in OpenGL?
What is the simplest method for rendering shadows on a scene in OpenGL?
Your approach can be summarised like this:
foreach (point p to be shaded) {
foreach (light) {
if (light is visible from p)
// p is lit by that light
else
// p is in shadow
}
}
The funny fact is that's how real-time shadows are done today on the GPU.
However it's not trivial for this to work efficiently. Rendering the scene is a streamlined process, triangle-by-triangle. It would be very cumbersome if for every single point (pixel, fragment) in every single triangle you'd need to consider all other triangles in other to check for ray intersection.
So how to do that efficiently? Answer: Reverse the process.
There's a lot fewer lights than pixels on the scene, usually. Let's take advantage of this fact and do some preprocessing:
// preprocess
foreach (light) {
// find all pixels p on the scene reachable from the light
}
// then render the whole scene...
foreach (point p to be shaded) {
foreach (light) {
// simply look up into what was calculated before...
if (p is visible by the light)
// p is lit
else
// p is in shadow
}
}
That seems a lot faster... But two problems remain:
how to find all pixels visible by the light?
how to make them accessible quickly for lookup during rendering?
There's the tricky part:
In order to find all points visible by a light, place a camera there and render the whole scene! Depth test will reject the invisible points.
To make this result accessible later, save it as a texture and use that texture for lookup during the actual rendering stage.
This technique is called Shadow Mapping, and the texture with pixels visible from a light is called a Shadow Map. For a more detailed explanation, see for example the Wikipedia article.
Basically yes, your approach will produce shadows. But doing it point by point is not feasible performance wise (for realtime), unless its done at the GPU. I'm not familiar with what the API's offer today, but I'm sure any recent engine will offer some shadow out of the box.
Your 'New idea' is how shadows were implemented back in the days when rendering was still done with the CPU. If the number of polygons isn't too big (or you can efficently reject entire bunches by having grouping volumes etc.) it can be done with fairly little CPU power.
3D shadow rendering on vanilla Java is never going to be efficient. You best use graphical libraries written to utilize the full capabilities range of the graphical card, such as OpenGL or DirectX. As you are using Canvas (from the screenshot you provided), you can even paint that Canvas from native code using JNI. So you could use all the technology from graphial libraries, do just a little fiddling and paint your Canvas directly from the native code. There would be very little work involved to make it work, compared to writing your own 3D engine.
Wiki link about AWT native access: http://en.wikipedia.org/wiki/Java_AWT_Native_Interface
Documentation: http://docs.oracle.com/javase/7/docs/technotes/guides/awt/AWT_Native_Interface.html

Is it good practice to cache parts of a 2D drawing?

I'm making a 2D game in Java and one of the main issues causing low FPS (on my slow laptop) is having to re-draw complex structures to a Graphics instance, such as dials with markings.
The dial and its markings will never change unless the window is resized, so I thought it would be a good idea to draw to a BufferedImage and just re-draw the image rather than re-drawing the details. The position of the needle obviously changes, so this can just be drawn on top.
I've never heard about this being done to improve the FPS of 2D games so I'm wondering if it's actually good practice to store a cache of images or if there's a better way to solve this sort of problem? Are there any issues associated with this that I haven't considered?
Caching images isn't a bad idea: you can rely on raster rendering to be pretty well optimised on most any platform. In my experience (which is admittedly mostly on mobile devices where 2D graphics are concerned) the Graphics.drawXXX() methods are often considerably slower than Graphics.drawImage().
In my experience the vast majority of 2D games out there make use of sprites (i.e. images) for rendering just about everything. Often that's true even when the graphics look like they are rendered using primitives!
Another useful technique to think about is not redrawing regions at all unless you really need to!
EDIT:
As others have mentioned, the major tradeoff is that you're going to be using more memory. You're also going to have to make sure you free up those images once you no longer need them.
Is it good practice to cache parts of a 2D drawing?
You're making a trade-off between drawing speed and storage space. Only you can determine which is more important.
You might consider rendering your dials in advance and saving the images as GIF, JPG, or PNG files. You would have to scale these images to your window size before you draw them.
Are you using double buffering for your Graphics panel?
Yes, that is a good practice, and it's done all the time. Drawing to an image first before displaying it on the screen is called double buffering, and that method can be used in different ways according to the needs of the program.
The downside of double buffering is memory, since it takes more memory to store the second image, but that sounds like a trade-off you'll need to make.

What buffering strategy should I use for my 2D scrolling map?

So, I'm creating a 2d top-down game in Java.
I'm following instructions from Java 2D: Hardware Accelerating - Part 2 - Buffer Strategies to take advantage of hardware acceleration.
Basically, what I'm thinking is this:
I'd like to be able to easily add more sections to the map. So I'd rather not go the route suggested in a few of the tutorials I've seen (each map tile has an adjacency list of surrounding tiles; beginning with a center tile, populate the screen with a breadth-first search).
Instead, my idea would be to have screen-sized collections of tiles (say 32x32 for simplicity), and each of these screen "chunks" would have an list referencing each adjacent collection. Then, I would create a buffer for the current screen and the 8 adjacent screens and draw the visible portion in the VRAM buffer.
My question is, would this be a correct way to go about this, or is there a better option? I've looked through quite a few tutorials, but they all seem to offer the same (seemingly high maintenance) options.
It would seem this would be a better choice, as doing things at the tile level would require 1024 times as many adjacency lists. Also, the reason I was considering putting only the visible portion in VRAM, while leaving the "current" screen and its adjacent screens in standard buffers was because I'm new to hardware acceleration and am not entirely sure how much space is acceptable to assume to be available. Because Java attempts to accelerate standard buffers anyways, it should theoretically be as fast as putting each in VRAM?
Any and all suggestions are welcome!
I haven't looked at any of the popular tile-based game engines, but I'd consider using the fly-weight pattern to render only the tiles that are visible in the viewport of a JScrollPane. JTable is both an example and a usable implementation.
Addendum: One advantage of the JTable approach is view-model separation, which allows one to relegate the acquisition of tile-related resources to the model. This makes it easier to optimize without having to change the view.
Even without scroll bars, one can leverage scrollRectToVisible() by extending JComponent or an appropriate subclass. The setDoubleBuffered() method may be helpful, too.

Categories