Stellarium / stellarium

Stellarium is a free GPL software which renders realistic skies in real time with OpenGL. It is available for Linux/Unix, Windows and macOS. With Stellarium, you really see what you can see with your eyes, binoculars or a small telescope.
https://stellarium.org
GNU General Public License v2.0
7.74k stars 820 forks source link

Add ability to draw sky images in front of celestial objects #3161

Open shrx opened 1 year ago

shrx commented 1 year ago

I am using StelMainScriptAPI.loadSkyImage to draw an image on the sky at the desired location. However, the image gets drawn behind the celestial objects like the Sun and stars. I would like to have the ability to draw it in front of celestial objects, or even better specify the layer onto which it is drawn. The use case is to be able to better predict interesting sunrises/sunsets and planet or star risings/settings behind a mountain or other interesting landscape sceneries.

Proposed solution: add a boolean drawInFront parameter or a string/int drawLayer parameter to the loadSkyImage function to specify on which layer the image should be drawn.

I have been looking into the API documentation and it appears that this could be achieved by specifying the "callOrder" of the image's layer with StelSkyLayerMgr but the necessary methods are not implemented / exposed.

github-actions[bot] commented 1 year ago

Thanks for adding your first issue to Stellarium. If you have questions, please do not hesitate to contact us.

gzotti commented 1 year ago

A "sky image" is "in the deep sky" behind the stars, not in the foreground. To draw a landscape foreground, the landscapes are used. These can be properly specified to be very accurate. Not sure why we would need another feature for the same purpose?

shrx commented 1 year ago

A "sky image" is "in the deep sky" behind the stars, not in the foreground. To draw a landscape foreground, the landscapes are used. These can be properly specified to be very accurate. Not sure why we would need another feature for the same purpose?

Hi, I wanted to use loadSkyImage because using a 360° landscape panorama does not provide enough resolution for my purposes, and I don't see a way to add an arbitrary image to the scene with LandscapeMgr similarly to the way loadSkyImage enables it.

See the comparison of the resolution between the landscape panorama and an image added with loadSkyImage: image

10110111 commented 1 year ago

You seem to be using a spherical landscape, while Stellarium also supports high-resolution "old style" landscapes. See section 7.1.4 of the User Guide for details.

gzotti commented 1 year ago

The old_style landscape can use a multi-part image, like 16 tiles with 4096x4096 pixels. The 4096 depend on your graphics card. If only part of the landscape is interesting, you don't need the full pano, just use the relevant tiles. A full-pano image 16384 pixels wide has 1.3 arcminutes per pixel. Modern GPUs support that directly. If not, or if that is not enough, old_style is the way to go. This is why we did not remove this type in 2014.

shrx commented 1 year ago

Thanks for the suggestions, will check the User Guide to see how to implement it with the old_style landscape. Indeed I only need a couple of degrees' worth of the horizon with a super high resolution.

shrx commented 1 year ago

It doesn't seem to be possible to achieve what I want with the old_style landscape approach you've suggested. If I only specify one texture file, it stretches it all around the horizon. It doesn't look like I can specify the horizontal angular size of my texture, only vertical.

[landscape]
name = TestLandscape
author = shrx
description = Test landscape
type = old_style
nbsidetex = 1
tex0 = image.png
nbside = 1
side0 = tex0:0:0:1:1
nb_decor_repeat = 1
decor_alt_angle = 1.867498305
decor_angle_shift = 0
decor_angle_rotatez = -122.95
calibrated = true

image

10110111 commented 1 year ago

You can specify N sides, and use e.g. a transparent PNG for those that you don't have.

shrx commented 1 year ago

You can specify N sides, and use e.g. a transparent PNG for those that you don't have.

That would mean I'd need to have about 200 extra redundant transparent textures to display just the one I need. It appears to me that the proper way to do it is to have the functionality of StelMainScriptAPI.loadSkyImage added to LandscapeMgr. I understand that it might not be simple to implement, though.

gzotti commented 1 year ago

Not sure if you even need to specify those extra sides as transparent PNGs. What if you just specify N sides and fill the one part that you have? If not, you can use a small transparent texture and use the same for all uninteresting parts. This solution works tonight. The other needs somebody to program it.

shrx commented 1 year ago

Specifying nbside = N and nbsidetex < N crashes Stellarium.

This solution with specifying 200 additional textures might work but it's clearly a bad hack to achieve something the landscape module is not meant to do.

gzotti commented 1 year ago

Adding mountains to the horizon is the primary dedicated task of the LandscapeMgr.

The right way to do is to start with a full pano. Usually, 4 or 8 tiles are used with satisfying results (arcminute pixels for naked-eye resolution). Using transparent tiles is a hack for those who don't provide the full pano, yes. The SkyImages module is not meant to place landscape images. 200x2048 images means 3 arcseconds per pixel. We have never had such a use case, and uncertainties around refraction will in any case make the simulation result questionable when it comes to arcseconds.

We could add yet another function to LandscapeMgr similar to SkyImgMgr to load high-res images to arbitrary locations, but sorry, not today, and not next week.

shrx commented 1 year ago

I could give it a go, if pull requests are welcome.

10110111 commented 1 year ago

If you're worried of making 200 texture files, this is unnecessary: you can just supply the same empty-texture file in the corresponding config entries. Moreover, you can just use a 1px×1px texture, so this won't take a noticeable amount of VRAM either.

But, if your only interest is the horizon, you can have a look at polygonal landscapes.

gzotti commented 1 year ago

I could give it a go, if pull requests are welcome.

In principle yes. This project lives from contributions where they are useful. Now, shall this be just for an extra image shown by scripting (just in front or right behind the currently set landscape?), or a new landscape type? As you see, the old_style landscape.ini is indeed not pretty. Just that it was the only one around 2008, and additions crave for compatibility so as not to break existing legacy data.

shrx commented 1 year ago

I'd rather keep it as close as possible to the functionality of the StelSkyLayerMgr method, so it would function as an extra image, not the whole landscape (for which there are already plenty of options, as shown in the User Guide).

gzotti commented 1 year ago

OK. Probably you'd need a list of extra images, and in draw(), draw the extra images either before or after the regular landscapes. (Or even allow specifying both ways and use two lists of extra images.)

shrx commented 1 year ago

I managed to draw an image in front of the landscape by adding the appropriate functions to LandscapeMgr, however the Sun and asterisms are still visible through the image:

image

I suspect it's due to the StelPainter's blending mode. It's currently set to "additive" (setBlending(true, GL_ONE, GL_ONE);), any suggestions what I should be using instead?

gzotti commented 1 year ago

The Landscapes themselves use GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA