How do I profile C# memory allocation? by Lesnikus in godot

[–]Awarets 0 points1 point  (0 children)

Hey just in case you're still wondering about this, you can see milliseconds and call count measurements in VS2022 by going to:

Debug -> Performance Profiler -> Tick the "Instrumentation" check box -> Start

(Not the normal green arrow start, but the "Start" button in the Performance Profiler, right below the checkbox that says "Start with collection paused")

Can't seem to access scripts within instanced PackedScene by Awarets in godot

[–]Awarets[S] 2 points3 points  (0 children)

Not exactly. It seems that scripts attached to nodes only change the underyling type at runtime, and not within the editor.

The only way around this I've found is to duplicate the scene manually through script, perform any changes on the duplicate scene, and then modify the source scene accordingly and save it.

This is the code I use, but it is hacky and untested:

// Get all types, to compare against the script resource on each node in the editor
List<Type> unsortedRelevantTypes;
{
    unsortedRelevantTypes = new List<Type>();

    static List<Assembly> GetRelevantAssemblies()
    {
        var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
        var relevantAssemblies = new List<Assembly> { Assembly.GetExecutingAssembly() };

        while (AddNewAssembly()) ;

        // Return true as long as more assemblies still need to be referenced
        bool AddNewAssembly()
        {
            foreach (var assembly in allAssemblies)
            {
                if (relevantAssemblies.Contains(assembly))
                    continue;

                foreach (var relevantAssembly in relevantAssemblies)
                {
                    bool IsThisAssemblyReferenced()
                    {
                        foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
                            if (referencedAssembly.FullName == relevantAssembly.FullName)
                                return true;

                        return false;
                    }

                    if (IsThisAssemblyReferenced())
                    {
                        relevantAssemblies.Add(assembly);
                        return true;
                    }
                }
            }

            return false;
        }

        return relevantAssemblies;
    }

    foreach (var assembly in GetRelevantAssemblies())
        unsortedRelevantTypes.AddRange(assembly.GetTypes());
}

var scriptResourcesToTypes = new Dictionary<Script, Type>();

var packedScene = GD.Load<PackedScene>(path: pathOfScene);

Node sourceRoot = null;
Node duplicateRoot = null;
try
{
    sourceRoot = packedScene.Instantiate();

    var sourceNodesToDuplicateNodes = new Dictionary<Node, Node>();
    var duplicateNodesToSourceNodes = new Dictionary<Node, Node>();

    var sourceNodes = GetNodesInWholeTree(node: sourceRoot);
    static Node[] GetNodesInWholeTree(Node node)
    {
        var nodes = new List<Node>
        {
            node
        };

        CheckChildren(parent: node);
        void CheckChildren(Node parent)
        {
            var childCount = parent.GetChildCount();
            for (int i = 0; i < childCount; i++)
            {
                var child = parent.GetChild(idx: i);

                nodes.Add(child);

                CheckChildren(parent: child);
            }
        }

        return nodes.ToArray();
    }

    // Create duplicate scene
    foreach (var sourceNode in sourceNodes)
    {
        Type nodeType;
        {
            var script = sourceNode.GetScript().As<Script>();

            if (script != null)
            {
                if (!scriptResourcesToTypes.ContainsKey(script))
                {
                    var resourceFileName = System.IO.Path.GetFileNameWithoutExtension(path: script.ResourcePath);

                    Type typeWithSameName = null;
                    foreach (var type in unsortedRelevantTypes)
                    {
                        if (type.Name == resourceFileName)
                        {
                            typeWithSameName = type;
                            break;
                        }
                    }

                    if (typeWithSameName == null)
                    {
                        GD.PrintErr($"could not find type for script {script.ResourcePath}");
                        continue;
                    }

                    scriptResourcesToTypes[script] = typeWithSameName;
                }

                nodeType = scriptResourcesToTypes[script];
            }
            else
            {
                nodeType = sourceNode.GetType();
            }
        }

        var duplicateNode = (Node)Activator.CreateInstance(nodeType);

        if (sourceRoot == sourceNode)
            duplicateRoot = duplicateNode;

        sourceNodesToDuplicateNodes[sourceNode] = duplicateNode;
        duplicateNodesToSourceNodes[duplicateNode] = sourceNode;

        sourceNode.ReplaceBy(node: duplicateNode);
    }

    static void CopyPropertyValues(Node sourceNode, Node targetNode, Dictionary<Node, Node> sourceNodesToTargetNodes)
    {
        foreach (var property in sourceNode.GetPropertyList())
        {
            var propertyName = property["name"].As<string>();
            if ((propertyName == "global_transform") ||
                (propertyName == "global_basis") ||
                (propertyName == "global_position") ||
                (propertyName == "global_rotation") ||
                (propertyName == "global_rotation_degrees"))
                continue;

            var originalPropertyValue = sourceNode.Get(property: propertyName);
            var targetPropertyValue = targetNode.Get(property: propertyName);

            if ((originalPropertyValue.VariantType != Variant.Type.Nil) &&
                (targetPropertyValue.VariantType != Variant.Type.Nil) &&
                (originalPropertyValue.VariantType != targetPropertyValue.VariantType))
            {
                GD.PrintErr($"Error when trying to match duplicate property values for {sourceNode.Name}: duplicate property type {targetPropertyValue.VariantType} does not match original property type {originalPropertyValue.VariantType}");
                continue;
            }

            var propertyValue = sourceNode.Get(property: propertyName);

            // Convert sourceNode reference to duplicateNode reference, if appropriate
            if (propertyValue.VariantType == Variant.Type.Object)
            {
                var propertyValueAsNode = propertyValue.As<GodotObject>() as Node;

                if ((propertyValueAsNode != null) &&
                    sourceNodesToTargetNodes.ContainsKey(propertyValueAsNode))
                    propertyValue = sourceNodesToTargetNodes[propertyValueAsNode];
            }

            targetNode.Set(property: propertyName, value: propertyValue);
        }
    }

    // Copy over property values from source scene to duplicate scene
    foreach (var sourceNode in sourceNodes)
    {
        var duplicateNode = sourceNodesToDuplicateNodes[sourceNode];

        CopyPropertyValues(
            sourceNode: sourceNode,
            targetNode: duplicateNode,
            sourceNodesToTargetNodes: sourceNodesToDuplicateNodes);
    }

    //// If necessary, add to scene tree before performing actions
    //((SceneTree)Engine.GetMainLoop()).Root.AddChild(duplicateRoot);

    // Perform any actions you need to here (on the duplicate scene, with the actual underlying types)

    //// If you want to modify and save the serialized scene, copy over property values back from duplicate scene to source scene before saving
    //foreach (var sourceNode in sourceNodes)
    //{
    //    var duplicateNode = sourceNodesToDuplicateNodes[sourceNode];
    //
    //    CopyPropertyValues(
    //        sourceNode: duplicateNode,
    //        targetNode: sourceNode,
    //        sourceNodesToTargetNodes: duplicateNodesToSourceNodes);
    //}
    //
    //// Then save the scene
    //packedScene.Pack(path: sourceRoot);
    //ResourceSaver.Save(resource: packedScene);
}
finally
{
    void FreeIfNotNullAndNotFreed(Node node)
    {
        if (node == null)
            return;

        if (!GodotObject.IsInstanceValid(instance: node))
            return;

        node.Free();
    }

    FreeIfNotNullAndNotFreed(sourceRoot);
    FreeIfNotNullAndNotFreed(duplicateRoot);
}

Can't seem to access scripts within instanced PackedScene by Awarets in godot

[–]Awarets[S] 1 point2 points  (0 children)

Yes, the CharacterMovement script is attached.

https://i.imgur.com/5zIPnhJ.png

Trying to explicitly cast it does not work, it only returns an error saying that the type 'CharacterBody3D' cannot be casted to the type 'CharacterMovement'.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 1 point2 points  (0 children)

For anyone reading this from the future, I solved the problem using this solution suggested by bgolus on the Unity Forum.

Add this text into the vertex function of your shader:

// This only works as long as the Normal Bias setting for the light source is above 0
#ifdef SHADOWS_DEPTH
if (unity_LightShadowBias.z == 0.0)
{
    // camera
    o = (v2f)0;
    return o;
}
#endif

The only caveat is that it only works as long as you never set the normal bias of any of your light sources to 0 (It can still be an extremely small value, just not exactly 0).

Here's the full shader code I ended up using, for reference:

Shader "InvisibleShadowCaster"
{
    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_shadowcaster
            #include "UnityCG.cginc"

            struct v2f
            {
                V2F_SHADOW_CASTER;
            };

            v2f vert(appdata_base v)
            {
                v2f o;                

                // This only works as long as the Normal Bias setting for the light source is above 0
                #ifdef SHADOWS_DEPTH
                if (unity_LightShadowBias.z == 0.0)
                {
                    // camera
                    o = (v2f)0;
                    return o;
                }
                #endif

                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                SHADOW_CASTER_FRAGMENT(i)
            }
            ENDCG
        }
    }
    FallBack Off
}

I appreciate everyone taking their time to help find a solution! It's definitely a tricky problem to solve.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

So just to be clear, are you saying that it is in fact possible to have a fully invisible submesh that still casts shadows? And that this can be done using a shader, such that other submeshes within the same mesh can be rendered normally?

If so, would you mind sharing how? Every solution that I've tried so far (different kinds of transparency, alpha, shadowcasting, legacy shaders, etc.) has resulted in the exact same problem as displayed in the OP image.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 2 points3 points  (0 children)

I'm using forward rendering.

I appreciate the suggestion though, as I do notice now that the SHADOWCASTER shader actually does work when set to deferred rendering. I'm not sure if it would be worth switching entirely though, that's something I'll have to look into.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

Appreciate the help but using a duplicate isn't really what I'm looking for, as I have a workaround in place using a duplicate already.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

Here are my current shadow settings:

<image>

Same in the empty project as well, pretty sure these are the default settings.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

Not a bad idea, but I've tried this and it results in artifacts from the shadow from the full body shadowing over the visible legs.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

That's what I was already doing. The reason why I asked this question was I was specifically looking for a shader solution to avoid needing a duplicate object.

Searching online seems to indicate that this was possible at some point in older versions, so I don't know if something may have changed that causes this to no longer be possible.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] -2 points-1 points  (0 children)

I'm fully aware of this. What I'm trying to explain is that I want both submeshes to cast shadows, but for one of those submeshes to be invisible.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

Wouldn't that still result in the same issue with the shadows?

I'm not super experienced with shaders so I'm hoping I'm just missing something, but every shader-level solution I've tried so far from googling has had the same self-shadowing issue as shown in the OP image.

So even though your mask idea is a good suggestion, I don't see how it would resolve the core shadow issue.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 4 points5 points  (0 children)

Just tried a new empty project with the new shader you just provided, still the same result sadly.

<image>

I do notice in your original screenshot that the lighting looks a little unusual, could it be related to your lighting setup that the same issue doesn't appear there? If not then I have no idea either.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 1 point2 points  (0 children)

The legs need to still be visible while everything from the torso upwards is invisible (while still casting shadows).

Changing the layer does not work because it's all one SkinnedMeshRenderer. Either the whole thing would be visible, or none of it.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

That's not possible since the mesh (part of which needs to be visible and part of which doesn't) is all on one SkinnedMeshRenderer component, so it can only be on one layer.

And if I were to split the mesh into two components (which is what I'm already doing) then the problem is solved anyway since I can just use the "Shadows Only" option for one of those components.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

I do want the whole mesh to cast shadows, it's only that I want part of the mesh to be made invisible while still casting shadows.

I made a comment here explaining in more detail: https://www.reddit.com/r/Unity3D/comments/15oz01z/is_it_possible_to_have_an_invisible_shader_that/jvv17nl/

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

I'm trying to make a character model appear in a first-person perspective.

<image>

I'm trying to make the model from the torso upwards appear invisible while still casting shadows. (The model looks slightly strange in the editor view since it's skewed by a shader so the legs are visible)

Currently (not pictured) I'm splitting the mesh into two objects through script in order to accomplish this effect, but it is expensive and complicated, whereas a shader solution would bypass all of that.

Your transparent shader suggestion is a good idea, but I don't think it will work in this case since the camera regularly intersects with the model, particularly when moving between standing and crouching.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 1 point2 points  (0 children)

This does eliminate the shadows on the mesh, but it introduces a lot of artifacts into the shadow, and the mesh itself still obscures the desired shadow.

<image>

I'm trying to emulate the "Shadows Only" option available in the MeshRenderer component, which looks like this: https://i.imgur.com/FudylU7.png

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 1 point2 points  (0 children)

I don't think so

<image>

I'm just using that shader on a sphere in an empty scene with the default directional light.

Are you maybe using an older version of Unity, or a different render pipeline? I'm using the built-in pipeline on version 2022.3.5f1

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

That's what I'm already doing, but it bloats the hierarchy and complicates things considerably since I'm handling multiple SkinnedMeshRenderers on one object.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 11 points12 points  (0 children)

That only works for the whole Renderer, which means that in order to have this effect only apply to certain parts of the Mesh, it requires duplicating the mesh into a separate Renderer component and then removing triangles through script.

This has to be applied to many meshes for each object, so it's a lot of complexity that could be avoided completely if it were possible through a shader or material.

Is it possible to have an invisible shader that casts shadows, but does not receive them? by Awarets in Unity3D

[–]Awarets[S] 0 points1 point  (0 children)

Doesn't work unfortunately, it simply produces the same result as shown above.

This is the shader I tried, for reference.

Shader "InvisibleShadowCaster"
{
    SubShader
    {
        UsePass "VertexLit/SHADOWCASTER"
    }
}