As 2015 draws to a close, now may be a good time to check with your manager about any extra budget money for technology purchases. Large companies often set aside a fixed amount of money for software purchases, and often it’s a “use it or lose it” sort of deal.
So, if you’ve been considering using Triton or SilverLining on a new project – the time might be right to start the acquisition process. Even if you’re an existing customer, remember our SDK’s are licensed on a per-application basis – so if you have new projects expected to launch next year, it may make sense to purchase the licenses you need now. If your support and maintenance plan is due to expire soon, you might also consider purchasing a renewal early so you’ll continue to have access to software updates throughout 2016.
We’ve decided to discontinue our Triton and SilverLining packages in the Unity asset store.
The ongoing cost of supporting and maintaining our offerings for the Unity game development community exceeds the revenue it brings in – and the trends are not going in the right direction. There is continued downward price pressure on Unity assets, and at the same time the Unity ecosystem is increasing in complexity and becoming more expensive to support. From a business standpoint, it’s a fairly straightforward decision.
However – it’s still possible to use SilverLining’s skies and clouds within Unity 3D through AgileSrc LLC’s BlueSkies package. It is aimed at simulation and training developers, and is a native wrapper around the actual SilverLining C++ SDK. Definitely check it out!
Our C++ SDK’s remain alive and well, and are still going strong. Their higher price points compared to Unity readily support ongoing development. So don’t take this to mean Sundog isn’t doing well; in fact 2015 is shaping up to be our strongest year yet, by far.
As a courtesy to people who may have been evaluating Triton recently, we are still selling licenses for Triton for Unity in our online store. However, please be sure you’ve thoroughly tested Triton in your Unity project using our trial version first – we’ll continue to answer any questions you may have about Triton for Unity, but we are not planning any future updates to it.
Are you going to the I/ITSEC conference in Orlando next month? It’s the biggest training & simulation conference in the United States, after all.
If your company is displaying a visual system that incorporates our SilverLining or Triton SDK’s – let me know! We might be able to cross-promote each other’s products during the show – or at a minimum, I’d love to just have a look at it and say hello!
Sundog Software doesn’t exhibit at the show, but I’ll be present for its entire duration. If you’ll be in town, send me a note and we can set up a time to meet up. I’m always curious to hear about the challenges you’re facing in the field of visual simulation, too – it helps guide our future product development for you.
See you at the show!
The Triton Ocean SDK is designed to look great at typical fields of view – say, 30 – 45 degrees or so. But what happens if you’re simulating a telescope or magnified sensor, and use a really small field of view? Or, you have some sort of fisheye view with a field of view of 90 degrees or even more?
Normally, you only tell Triton about your projection matrix, and it’s tough for us to extract the actual field of view from it. As a result, you might not see much detail on the water when you’re zooming in to a spot out near the horizon, or there might be too much detail when you’re zoomed out to very high fields of view. The size of spray particles might also be affected, such that zoomed-in scenes have spray that’s too small, and zoomed-out scenes have spray that’s too large. Extreme fields of view can also mess up our algorithms for culling out wake effects with distance.
Fortunately, there’s an easy solution: use the Triton::Environment::SetZoomLevel() method! This tells Triton how to scale the detail in the scene to match the zoom level you’re trying to simulate. Each frame, call SetZoomLevel() with a factor that represents your field of view relative to some baseline. For example, if your “normal” field of view is 30 degrees and you zoom in to 3 degrees, you’d pass in a zoom level of 10.0. And if you zoom out to 90 degrees, the zoom level is 30/90 = 0.333.
By adjusting Environment::SetZoomLevel() as your field of view changes, you’ll ensure that Triton always shows the appropriate level of detail, wake effects, and particle sizes for any given FOV.
SkyMaxx Pro was already the top-selling add-on for X-Plane, but the demand we saw on the launch of version 3 was literally an order of magnitude greater than anything we’ve seen before.
We’ve been monitoring customer feedback, and the response has been overwhelmingly positive. Here’s our favorite review so far ;) No serious technical issues have come up, either.
Some customers have been sharing their screenshots of SkyMaxx Pro 3 online, and one even gave us explicit permission to use them. So here’s a few shots from a happy customer we’d like to share here! Click for full resolution, and thanks to Nicholas Garlick for sharing them.
A huge thank you to the X-Plane community for such a warm reception.
SkyMaxx Pro 3 adds our latest SilverLining-powered clouds to the X-Plane flight simulator, leading to a more immersive and realistic flying experience. It can also boost framerates, compared to X-Plane’s default cloud engine.
Check out the promo video! Go full-screen; it’s HD.
The SilverLining Sky, 3D Cloud, and Weather SDK supports pretty much every rendering technology you can imagine: DirectX 9 through 11.1, and OpenGL 2.0 through the latest. As such, we’re in a good position to measure both the performance and code complexity associated with each rendering framework.
SilverLining is designed such that all of its renderer-specific code is isolated into DLL’s. So, you select which renderer you are working with when initializing SilverLining, and it loads up for example the OpenGL 3.2 core profile DLL with all of the code needed to draw our skies, clouds, and weather effects in OpenGL 3.2. We also have a sample application included with our SDK for each renderer that draws a similar scene.
So, we can measure both the lines of code needed to support each renderer – and the performance seen with each one. As graphics API’s have evolved, they have pushed more and more work away from the driver and onto the engine developer. Is that increased complexity paying off with increased performance? Let’s have a look (click for a clearer image):
First, a word on our methodology. We modified our sample applications to ensure the same exact test scene was rendered in each, using the same random seed and initial conditions for the clouds (as seen in the image above.) We ran at 1920×1080 resolution, and measured frame-rates with FRAPS. So in each case, we are measuring the lines of code required to produce the exact same result, and measuring the performance as frames per second. Higher lines of code is “bad”, and higher FPS is “good.” Tests were run on an NVidia GTX970 video card, with an Intel i5-4690K processor, with v-sync off.
The results are interesting, to say the least. There is a significant increase in performance between OpenGL and DirectX, which lends credence to the theory that driver authors pay a little more attention to DirectX performance. SilverLining does not use any fixed-function pipeline calls, so we are comparing apples to apples here.
We did not see any increase between OpenGL 2.0 and OpenGL 3.2 core profile, but did see a jump going from DirectX 9 to DirectX 10. This implies removing the “baggage” of fixed function support did result in a performance boost for DirectX, but not in OpenGL.
Notably, going from DirectX 11 to 11.1 caused a large increase in the complexity of code required on our end, but actually resulted in a step backwards for performance. I believe this is largely due to removing the DirectX 11 Effects framework, which was necessary because run-time shader compilation and reflection are discouraged in DirectX 11.1. So we had to write our own code for managing constant buffers, sampler states, etc., which may not be as efficient as the code Microsoft provided. So, we’re facing an uphill battle on reclaiming that lost performance now. If there’s a benefit to removing support for run-time compilation in Direct3D, it eludes me thusfar.
Another noteworthy result is that it takes 58% more DirectX 11.1 code to do same thing as in OpenGL 3.2. DirectX is clearly on a trend of pushing more complexity onto application and engine developers over time, and DirectX 12 takes this even further. This makes life easier for driver developers, and in principle gives engine developers more direct access to the graphics hardware which can translate to better performance. However, we shouldn’t forget that it also makes learning graphics code even harder for new developers. The simple act of rendering a triangle to the screen – the “hello world” of 3D graphics – is a very intimidating wall of code in DirectX 11.1. I do worry that this complexity will push young developers away from the field of lower-level graphics coding, and instead push them toward higher-level environments such as Unity. Whether that’s a good thing or not is debatable. It also means much of the burden of optimizing graphics code has shifted from the driver developers to the engine developers, which will lead to more inconsistent performance across applications.
So, bottom line: yes, DirectX is faster than OpenGL in our tests – but it comes at the cost of increased code complexity. Of course, if you care about supporting devices that don’t run Windows operating systems, this whole argument is moot – only OpenGL can support Linux and MacOS as well, for example.
It’s also worth mentioning that squabbling over 1,080 frames per second vs. 1,670 frames per second is probably also meaningless in practical terms. The human brain can’t see any improvement above 60 frames per second! In the context of SilverLining, none of this actually matters unless your application is already right on the edge of 60 Hz performance, and the smallest thing might push it over the edge to 30 when vsync’ed.
The SilverLining Sky, 3D Cloud, and Weather SDK now includes experimental Direct3D 11.1 support in version 4.027. This means applications targeting DirectX 11.1 (requiring Windows 7 or newer) can use SilverLining without introducing dependencies on the June 2010 DirectX SDK or on the D3DCompile DLL’s for runtime shader compilation.
Using the DirectX 11.1 API’s does require at a minimum Windows 7 and the Windows 8.1 SDK. In SilverLining, all you need to do is specify DIRECTX11_1 as the renderer when calling Atmosphere::Initialize().
Although SilverLining has supported DirectX 11 for many years, supporting 11.1 required substantial code changes. As such, we consider this support experimental for now – we’ve tested it as well as we can, but there may be quirks we haven’t yet discovered. If you do run into any trouble, please let us know at email@example.com.
Moving to D3D 11.1 required us to:
- Eliminate dependencies on the DirectX 11 Effects framework, forcing us to re-write all of our .fx shaders as individual .hlsl shaders
- Eliminate run-time shader compilation, forcing us to write a “DirectXShaderAnalyzer” application internally to compile our .hlsl shaders to .cso files, and write out associated files mapping uniform names in the shaders to their offsets and sizes within each shader’s constant buffer, which SilverLining uses at runtime.
- Eliminate all calls to D3DX interfaces and replace them with alternate calls from the DirectXMath framework
- Explicitly set up sampler state objects for each shader, instead of relying on the Effects framework to do that for us
It was a lot of work, but it enables us to eliminate any runtime dependencies other than what comes out of the box in modern Windows installations.
Of course DirectX 12 is available now as well; for now, it is possible to run DirectX 11 code within a DirectX 12 environment, so SilverLining can still operate within a DX12 application. If you are using DirectX 12 however, please let us know – it will help us figure out the right priority for developing native DirectX 12 support.
One thing that sometimes trips up new users of the SilverLining Sky, 3D Cloud, and Weather SDK is that although we have a common API for all SilverLining::CloudLayer types, individual types of cloud layers have little differences in how that API is interpreted. Some clouds behave very differently than others in nature, and so this is to some extent unavoidable. We’ve made an effort to document all of these little quirks in our API documentation, but they’re easy to miss.
If all you need to do is create a common weather condition, have a look at SilverLining::AtmosphericConditions::SetPresetConditions for a simple way to just get the clouds set up for the conditions you want, without worrying about any of this.
But if you do need finer control over the clouds in your scene, here’s a rundown of every cloud type currently available in the SilverLining SDK – and things that are unique about each one.
Cumulus Congestus (and the “hi-res” version) – The “thickness” of the cloud layer actually represents the variation in base altitudes of individual clouds. The actual height of each cloud is governed by a cellular automata simulation, and they can vary greatly from cloud to cloud.
Cumulus Mediocris – As with cumulus congestus, the thickness represents the variation in base heights. It is also important to not use too high of a density value with cumulus mediocris; these clouds are very small, and if you try achieve a high cloud coverage with them, it will result in so many clouds that it will impact performance even on the best systems. Cumulus mediocris clouds are associated with fair weather in nature, so you shouldn’t go above say 30% density with them.
Stratus – If you set up an “infinite” stratus cloud, we assume you want it to extend from horizon to horizon, and this is done automatically. The length and width you specify for the cloud layer is ignored in this case. Also, “SetCurveTowardGround” will only work with infinite stratus clouds – otherwise, a localized stratus cloud would end up looking like an odd dome from the outside.
Stratocumulus – These clouds are rendered using GPU ray-casting, using actual 3D textures. 3D textures eat video memory alive, so don’t make these clouds too large. Also, make sure the thickness specified for stratocumulus clouds is high enough to enclose the individual clouds within the layer – otherwise, the top of the cloud layer will look like it’s chopped off. Under the hood, stratocumulus clouds are “grown” using the same algorithm as cumulus congestus clouds, so if you encounter performance or visual issues with stratocumulus, you’re often better off replacing them with an equivalent cumulus congestus layer.
Cumulonimbus – A cumulonimbus cloud layer only includes a single cumulonimbus cloud, which is stretched to fit the cloud layer dimensions you specify. So, don’t make these too large – around 5km cubed is about right. Unlike the other cloud types, cumulonimbus clouds are not procedurally created, but are loaded from pre-generated model files, chosen at random and in VRML format, stored in the resources/clouds/cumulonimbus folder.
Towering cumulus – These very large clouds consist of many particles, and so you should keep the density of their cloud layers low. Generally 20% or so is realistic for stormy conditions. Like the other cumulus cloud layers, the thickness only controls the variance in base altitudes.
Cirrus and cirrostratus – These high, wispy clouds are little more than giant textures in the sky, and their wispy edges mean they do not tile. If you create an “infinite” layer of these types, it will merely anchor the cloud above the viewpoint at all times. Given their high altitudes in nature, this usually ends up not being noticeable as the camera moves.
Also, be sure to read our earlier article on simulating specific weather conditions with our cloud layers.
Thanks to one of our customers, SilverLining now includes a CloudLayer::Intersect() method – this lets you perform intersection tests against individual clouds in a cumulus cloud layer. There are several applications for this in simulation and training, and it’s something that’s been requested a few times in the past.
CloudLayer::Intersect() takes in a ray, specified by an origin and a direction vector, and returns the range to the first cloud hit by that ray, if any. If there is no intersection, it just returns false. It’s pretty easy to use.
We hope this new capability leads to some innovative new uses of SilverLining!