SSTU - Shadow Space Technologies Unlimited

SSTU - Shadow Space Technologies Unlimited

98.5k Downloads

Parts with transparency (fairings, flags, decals) - graphical/rendering oddities.

shadowmage45 opened this issue ยท 17 comments

commented

As far as I'm aware this is a stock bug; adding as a 'known issue'.

Will do some investigation regarding shaders and/or material conflicts though.

Need to verify if the problem exists with stock fairings?

commented

This issue appears to be fixed in 1.2 with the new highlighting mechanisms. They no longer mess with opacity, but instead just use _rimFalloff and what looks to be an additional render-texture for the surrounding glow.

Opacity handling in general appears to be broken though as the fairings are all showing up fully opaque. Have added that onto the 1.2 update list explicitly (investigate fairing transparency not working).

commented

Confirmed to exist with stock fairings - highlighted parts behind them are not visible. Flags seem to go both ways both in stock and SSTU - the stock airplane tail fin has the issue, as to the SSTU modular tanks, but none of the command pods do. Maybe it has something to do with the rendering order being messed up when highlighting a part.

commented

Err, I'll add that it seems to be a bit less consistent with SSTU parts - some meshes will disappear, some won't, occasionally one will re-appear, and it seems to be somewhat draw-distance related.

commented

There likely is some interaction going on with several of SSTU custom parts due to my ineptitude at handling shader and materials setup.

As far as I know the stock system modifies various shader values to do its highlighting/transparency... and I might well be coming along and overwriting those values or replacing the material without copying those values.

And yes there also appears to be some draw-order.... problems. Currently/previously whenever I would set the transparency for a part I would also update its render order/queue value. Something may have changed on this end of things...

Likely I'll need to wait for the stock bug to be fixed before I can start cleaning up my end of things.

commented

I found a hack that seems to fix this, will leave it here but of course up to you if you actually want to spend time on it.

Basically you just have to keep forcing the rendering priority to be correct every time the mouse enters or exits the part, because the highlighter messes it up. Simplified code below:

public void OnStart(StartState state)
{
    // ...
    part.AddOnMouseEnter(FixRenderOrder);
    part.AddOnMouseExit(FixRenderOrder);
}

private void FixRenderOrder(Part blah)
{
    foreach (MeshRenderer renderer in transparentTransform.GetComponentsInChildren<MeshRenderer>())
    {
        renderer.material.renderQueue = 6000;
    }
}

6000 is above what's used by the highlighter (4000 and 5000). I don't fully understand why things break, but this solution seems to work.

commented

Actually you know what it's probably worth waiting. I have heard that 1.1.3 will include changes to the highlighting system which may fix this.

commented

Noted, and thanks for the investigation either way. Would be nice to get this cleaned up one way or another

commented

Preliminary tests on 1.0.3 suggest that the fairing transparency issues remain (however, flags are fixed). I guess Squad managed to fix it for stock fairings and flags but not for everything.

commented

So the above fix doesn't really work. It's functional when the part itself is highlighted, but if the highlight is caused by a part farther up the hierarchy, it breaks.

I have a solution that seems to work, but it's more complicated (probably hard to make sense of out of context, haven't committed yet). I've also (at NathanKell's suggestion), PM'ed Claw to figure out how Squad fixed the issue for the stock fairings.

BTW, I'm doing this investigation for another mod, so I figured I would just post my findings here as I discover them. If you think it's obnoxious/not useful feel free to let me know.

commented

I'm more than happy for any information you may offer on this issue; would loved to get it sorted out/fixed up at some point. Just been a bit pressed for time these last weeks... busy at work and planning / going on vacation. Might have a bit of time over the next few weeks... but still pretty busy at work.

Indeed, figuring out how they fixed it for the stock fairings would be helpful; probably similar to what you were proposing with the mouse-over-event render-queue refix/resetting. They've probably special cased it somewhere in the highlighting code though, so likely not anything a mod would have access to...

I did notice that the SSTU Node-Fairing highlighting/opacity is 'correct' when the fairings are first created or toggled on/off; so the old render-queue setup #'s are still valid and working; but yes, as soon as any highlighting kicks in, it screws them all up.

commented

Interesting.

I'm wondering if some of my transparency problems then stem from the fact that I'm constantly changing the material on the object while in the editor without updating the shader / not using the right shader (don't remember offhand how I was handling it...).

Will see if I can find some time to play around with this in the next few weeks. Would be nice to get the fairing transparency/highlighting cleaned up (and flags too..).

commented

So I just dug into ModuleSeeThroughObject (used for the stock service bays) and it looks like it works by setting all the material shaders to KSP/Specular (Transparent) in the editor. Haven't tested yet but I'm pretty sure it's something about that shader that makes transparency work.

commented

The flags appeared to be fixed the last time I checked. I think updating properties like transparency works fine, it's really that part highlighting messes with the render order, but somehow specific shaders avoid this...

commented

Okay, update:

I thought this would be sufficient, but it turns out to cause problems if the fairing texture has an alpha channel:

Shader shader = Shader.Find("KSP/Specular (Transparent)"); // or KSP/Bumped Specular (Transparent) if you have normal maps

foreach (MeshRenderer r in transparentObject.GetComponentsInChildren<MeshRenderer>(true))
{
    r.material.shader = shader;
}

If the texture has an alpha channel, it turns out that the transparent shaders use it for alpha even though they're only supposed to use it for specularity (meaning that the object is transparent even if you want it to be opaque). If there's no alpha channel then you're fine. A constant specularity can still be set on the material.

If you need specularity from the alpha channel, I did come up with a hacky solution that seems to work (simplified below):

public class MyModule : PartModule
{
    private HighlightUpdateChecker highlightUpdater;

    public void OnStart(StartState state)
    {
        if (state == StartState.Editor)
        {
            highlightUpdater = new HighlightUpdateChecker(part, FixTransparency);
            FixTransparency();
        }
    }

    public void OnUpdate()
    {
        if (HighLogic.LoadedSceneIsEditor)
            highlightUpdater.Update();
    }

    public void FixTransparency()
    {
        transparentTransform.SetRenderQueue(6000);
    }
}


public class HighlightUpdateChecker
{
    private Part part;

    private Part highlightingPart;

    public EventData<bool> UpdateEvent { get; private set; } = new EventData<bool>("HighlightUpdateEvent");

    public HighlightUpdateChecker(Part p)
    {
        if (p == null) throw new ArgumentNullException("Part cannot be null!");

        part = p;
        highlightingPart = part.GetHighlightingPart();

        part.AddOnMouseEnter(MouseOverUpdate);
        part.AddOnMouseExit(MouseOverUpdate);
    }

    public HighlightUpdateChecker(Part p, EventData<bool>.OnEvent updateEvent) : this(p)
    {
        UpdateEvent.Add(updateEvent);
    }

    public void Update()
    {
        if (part.GetHighlightingPart() != highlightingPart)
        {
            UpdateHighlight();
        }
    }

    private void MouseOverUpdate(Part p)
    {
        UpdateHighlight();
    }

    private void UpdateHighlight()
    {
        highlightingPart = part.GetHighlightingPart();
        UpdateEvent.Fire(part.HighlightActive);
    }
}

public static class Extensions
{
    public static Part GetHighlightingPart(this Part part)
    {
        if (part.parent != null)
        {
            Part highlightingPart = part.parent.GetHighlightingPart();
            if (highlightingPart != null)
                return highlightingPart;
        }

        return part.HighlightActive && part.MouseOver ? part : null;
    }

    public static void SetRenderQueue(this Transform transform, int queue)
    {
        foreach (MeshRenderer meshRenderer in transform.GetComponentsInChildren<MeshRenderer>())
        {
            meshRenderer.material.renderQueue = queue;
        }
    }
}

Basically what this does is check for any possible highlighting update and sets the render queue to something above what KSP uses for highlighting when that happens. This ensures that the transparent object is always rendered first.

commented

Oh, and in case you're wondering I've been experimenting with all this because I'm developing a new fairing mod (I agree that the stock module leaves a lot to be desired). Let me know if you have any questions about the code I posted or the mod I'm trying to get working.

commented

Thanks for the additional information. I might actually set aside some time to work on getting a working implementation over the next few weeks' code-cleanup effort.

I am a bit curious about your custom fairing work, but I have patience and can wait until you think it is ready to be seen/used/tested :) Is it going to be a full-procedural setup, or ?
Anyhow, if you need any help with mesh generation, let me know; though you can already access most of my mesh-generation code through the repository if needed.

Would be nice to have an alternative to point people towards when they ask me to make new fairings, which seems to happen every few weeks :)

commented

My thought was actually to get away from procedural mesh generation. The basic idea is to have the nose and sides of the fairing be fixed models, and be able to adjust the number of side segments to vary the height. There are certain use-cases where absolutely need to be procedural (interstages, aeroshells), but for your garden-variety payload fairings, there are really only a few things that matter: how wide and long they are, and maybe what the shape of the cone is. I actually liked the way the old KW Rocketry fairings looked, if they were cumbersome to use. Diameter adjustment can either be accomplished with separate models or scaling, and maybe I will add the ability to swap different pre-defined models for the nose at some point.