Running into serious anti alias problems with thin lines

Hi Everyone,
For some time now we at Windplanner have been making excessive use of Cesium in our product. We’ve created beautifull Wind Turbine visuals with our Windplanner application together with Cesium and made a lot of customers happy and on that aspect we absolutly love using Cesium.

However for about a year now we have been working on a new project involving transmission towers. In this project we use a lot of small details regarding towers and conductors (cables between the towers) and we’ve been running into some serious anti allias limitations of Cesium when it comes to properly handling polylines and models like transmission towers and transmission cables (very thin lines). Due to the small nature of the cables and the connections in the towers.

Regarding this issue we have been active in contacting the people at Cesium themselfs and looking for workarounds on the github and forums.

The first one, the solutions coming from Cesium, mentioned that one of the main issues with our problem is the current anti aliasing method FXAA and it’s limitation, of which imporiving there to MSAA would require Cesiums render engine to be upgraded internally “Or so I was told”

The second option, looking for workarounds, only helped a little. We are making use of the “Resolution Scaling” option. Which does some reasonable work - see pictures below - but heavily relies on the customer also having a really good pc to support it, this just isn’t the case most of the time. Other options were making cables thicker - see pictures below - and using a custom distance display condition. Which also makes it a bit better but does not equal the results we’d like to see.

Imgur: The magic of the Internet - Shows the towers and cables inside a panarama using our custom panorama viewer inside the cesium world.
Imgur: The magic of the Internet - shows the towers and cables in the plain cesium world

Here’s a list of results we got using some of the workarounds.

Like shown, at close range the tower and cables look fine. the problem arises when a user has to look at it from a distance. The cables become partly visible and the towers start getting some dither patterns.

We’ve also been looking at this post https://groups.google.com/g/cesium-dev/c/XXXBFSYgb7s/m/SLZ0WokbCAAJ but to no avail, perhaps because we don’t really know what settings would be good but using the values in that post doesn’t result in the visuals we want to show.

Last but not least proper anti alias for thin lines still looks like a challenge for Cesium. See also this post of 30th Sep 2019 Fix aliasing on thin models · Issue #8228 · CesiumGS/cesium · GitHub. If somebody has a quick solution or workaround please let us know because we are running in real problems with our customers and have no options left.

1 Like

I don’t have a solution for you but if you can put together a minimal reproduction in Sandcastle, it’s always easier for the team to help. Are you using an Entity with a PolyLine for each wire?

Hi there,

Quick question up top; reading from your post, the towers are model, and the lines are polylines (entities), right?

Starting with the lines; your cables are all black, and looks to be opacity 100%. Have you played with opacity (Cesium does weird things when going from 100% to any other value) and outline? Or even just the color itself, slightly graying it? You could try something like opacity at 90% and line width a bit wider. You could also look into the various polyline MaterialProperties, I’d start with making a material that does some black / opaque altered horizontal lines, but make sure the black part has the width you need (that should mess a bit with the anti-aliasing filter maybe just enough to get some better results).

Another approach might be to dynamically alter the width and / or color and / or outline color of the line based on a scale of distance, so 40m and below is width 1 (or whatever you’ve got as size at close range), and change the width slightly as you zoom away from it, for example around 400m use width 1.4, 1000m use width 1.6, and 2000m and above back to 1 (or turn off). You’ll have to experiment a lot with this to get it right and performing well. The way to do this is to create an event listener (either rendering event, or make up your own using a timer) that calculates the distance of an object to camera (something like Cesium.Cartesian3.distance ( object.position, viewer.camera.position ) ) and update the entities accordingly. Don’t know if you’re using the entity API or primitives etc., and I’d even look into if Cesium.callbackProperty() can be used for this (don’t know; it’s sometimes a bit sporadic if it works or not). I do this for a few other things and it works, but there are performance hits when there’s a lot of objects in the scene.

Finally, you could also look further into the post-processing options, maybe even write a filter that “undo” some of the anti-aliasing if you know what to look for (thin horizontal black lines). See the example for depth perspective and go from there, might be you can use or write a filter that’s helpful and fast enough. I think this was touched up on this post; Poor antialias result on 3D object - #3 by Dorian_Tourin-Lebret and for simplicity look at the last answer (the link is the updated version of the old Google groups post you found above; it has some extra info). I’d download a full Cesium, do a local build, and alter the source code for the antialiasing filter, make some notes, and suggest a way for having those values be configurable in Cesium in future versions.

Good luck, and let us all know how it goes.

Cheers,

Alex

@James_B I can maybe replicate the cables in a sandcastle but using the models wouldn’t be something that’s possible sadly. I don’t have the time for it currently so maybe in the weekend I can see what I can do

We use the polylineVolume rather then the Polyline in order to round the cable but I believe this is still part of the entity set.

@Alexander_Johannesen Our next approach to a basic solution was indeed to start using the camera distance to determine the scale/opacity of a cable. However as you have mentioned yourself, this is most likely going to come together with a drop in performance as this will have to be executed for each individual cable but something that will be tested in the next week or so.

As for creating a custom post processing stage. Honestly I am not anywhere near good enough with post processing, shaders etc to confidently dabble in that region of programming.

In any case, thanks for the quick response, i’ll post my results of using the camera distance to scale/fade the cables in the following weeks.

Re: using the models, I think you could at least illustrate the problem by simply dropping a Cylinder in place of the pole model, it doesn’t have to be photorealistic. Re: polylineVolume, have you tried using a regular polyline instead to see how different it looks? It seems to me like it’d be a good fit for modeling a “cable” but of course I haven’t tried it.

No worries. I’ve got a few performance tricks up my sleave, so call again. The distance calculation itself can also be done against a logarithmic scale, it only needs to be near real-time up close. In addition, working with primitives instead is faster, and I’d write a small caching class to do change detection on the calculation and current state. I don’t know if you also have a polyline for the length of the wire, or for each segment. It might be faster to do segmentation on these calculations, as well as a calculation only on wires in the camera view (there’s a function that can determine that in the Camera object as well, although I don’t know the performance of that vs. some of the other techniques we’ve talked about).

Cheers,

Alex

Something similar happens to this with KMLs, in that their polylines quickly disappear if the camera is not at the right angle to view them.

Hello everyone,

I’ve got for you the long awaited sandcastle demonstrating the issue we and I believe some other people using Cesium are running into.

https://sandcastle.cesium.com/#c=jVdtb+o2FP4rFp+SNg0vLdyuQLVbirRq3LUqVaWpVJObGLDm2JHt0LE[…]c/ksWrdtRG/SPTJkwL7DHDZEMb3O1dfd2VmyGYThqw7LZUgvBPrCsIf8H

@Alexander_Johannesen I’ve been playing around with your suggesting of taking into account the distance of the camera towards the cables however due to the massive spike in performance required to update those cables on the fly using my solution just wasn’t good enough.

Mainly due to the fact that we have the option to create a fly through animation. combine that with possible hundreds or thousands of cables checking their distance compared to the camera results in massive performance drops and renders the animation unusable sadly.

Perhaps the tricks up your sleeve using primitives or something else might prove more usefull then what I tried.

It’s an interesting example, to be sure. I don’t have a solution for you but a couple of thoughts. First, did you notice that computeCable makes two “circles”? (12 * 60 = 720, so you’ll get each point twice.)

Second, have you tried just exaggerating the cable diameter by a fixed amount? Even at 10x actual radius (computeCable(0.3)) it doesn’t seem crazy, and you have to zoom so far out to create aliasing artifacts that you can barely see the line at all. It seems like a big ask to have a “globe” engine render centimeter-scale stuff correctly, but maybe it’s just not my use case.

@James_B I hadn’t noticed that yet, Oversight on my part, thanks for noticing it!

As to exagerating the cable. In our application we allow users to dynamicly change the thickness of the cable. However this does mean that it is now not as accurate anymore.

I get what you’re saying that we are asking much of a globe rendering engine but in all honesty, we do this because we believe in Cesium and it’s capabilities. Truthfully I think seeing Cesium as just a “globe” engine is underselling it’s capabilities :wink:

A small issue here is that you can’t see the transmission tower connected to the cable. The cable can only be exaggerated so much before it stops being believable compared to the tower it is connected to if you get what I mean.

2 Likes

Do you do the calculation in real-time or every second (and even different times for different models / lines), are you caching that distance, caching the API calls, etc? For example, if you set a value with the API in real-time, that is terribly slow, but if you divvy it up into chunks and do range detection with updates every, say, second, it will probably be just fine. It kinda depends on the cycle of calculations, and how you chunk your work. Do you only calculate the nearest items, or all of them?

Here’s what I think I would do; simply do range calculation on the various models every second, and try to even those out so they don’t all happen at once. Then check that distance against a range, so that the width of the cable is as an example 0-2m=0.5, 2-4m=0.75, 4-8m=1.0, 8-14m=1.2, and so on, Pop a decent set of ranges and values into a lookup table, and just check if the old distance requires a new API call based on the table. You don’t need to update these things in real-time, the performance hit is not worth the much faster caching that won’t really be noticed much. You might need a table with higher or lower resolution, but I’m sure you can find one that fits your application. It might just be not just line thickness in that table, but also colors, maybe outline width, allt hose things. Since each model will calculate at different times, it should be more than fast enough, but then again, I don’t know just how many models and lines we’re talking about.

Let me know some more details, I’m happy to play around and help out. Don’t know if you’re using any smarts on the entities in on the map, but I’ve got a plugin system that connects our metadata objects to entities and tilesets on the map, and the plugins will do some of the cahing and timing of the smarts by themselfs, I don’t need a real-time loop to make it happen.

Cheers,

Alex