Is there an easy way to hide objects that are under another object?

CodeGuru12CodeGuru12 Posts: 4Member
edited October 11 in Shaders

Is there a way to hide objects under another object? I have a multimesh with a shader creating moving grass, but it pokes through my farm plot blocks. You can see the effect here

I found some code to cull things behind a plane from this youtube video

Someone suggested using a viewport texture to draw shapes where the grass would get drawn too, but I wasn't able to figure out how to do it. This plane culling thing seems like the most straight forward if I can get it to work. But I have no idea how to make it clip the grass only on the spots where I place obejcts.

shader_type spatial;

uniform vec4 portal_plane = vec4(1.0, 0.5, 0.0, 0.0);

bool portal_culls(vec3 vertex, mat4 cam) {
    vec3 pos = (cam * vec4(vertex, 1.0)).xyz;
    return !any(isnan(portal_plane))
        && portal_plane.x * pos.x
            + portal_plane.y * pos.y
            + portal_plane.z * pos.z
            + portal_plane.w < 0.0;
}

void fragment() {
    if (portal_culls(VERTEX, CAMERA_MATRIX)) {
        discard;
    }
    ALBEDO = vec3(1.0, 0.0, 0.0);
}

Tags :

Answers

  • CodeGuru12CodeGuru12 Posts: 4Member
    edited October 11

    Can't edit my question I guess, so I'll throw this here. It does work outside the viewport, but it either works for all of my grass if I apply it to the grass, or just for the box if I apply it to that. Not sure how to apply it to only a small area where a box would be placed, or multiple boxes.

  • MegalomaniakMegalomaniak Posts: 4,034Admin

    You can edit the OP by clicking on the little gear wheel located to the right of the title. I've edited the OP to fix the code formatting.

  • xyzxyz Posts: 204Member
    edited October 15

    Plane clipping wouldn't be suitable for this if the area becomes more and more complex with time. Better to use texture approach and eliminate growth in the shader based on texture content.

  • TwistedTwiglegTwistedTwigleg Posts: 4,855Admin

    You could try masking by rendering to a color mask, though it’s a bit more expensive for performance. I wrote a tutorial on making and using color masks.

    Another thing you could maybe use is vertex colors and discard/skip if the vertex is a certain color. I’m not sure if you can modify vertex colors at runtime though.

  • xyzxyz Posts: 204Member

    @TwistedTwigleg said:
    Another thing you could maybe use is vertex colors and discard/skip if the vertex is a certain color. I’m not sure if you can modify vertex colors at runtime though.

    Similar possible approach - if each blatt is an instance in a multimesh you can just send visibility info to the shader via per-instance custom data and let the vertex shader cull it.

  • cyberealitycybereality Posts: 2,089Moderator

    Yes, I think that would work with instances. However, I believe the only way to modify vertex colors is with MeshDataTool, and that requires making a new mesh and sending it to the GPU which would be too slow for this use case.

  • CodeGuru12CodeGuru12 Posts: 4Member

    Similar possible approach - if each blatt is an instance in a multimesh you can just send visibility info to the shader via per-instance custom data and let the vertex shader cull it.

    Would that be using the INSTANCE_CUSTOM? If yes, I see that in the documentation, but it only seems to have info for

    x: Rotation angle in radians.
    y: Phase during lifetime (0 to 1).
    z: Animation frame.

    according to the docs. How would I use it to hide certain blades of grass? Could you show an example?

    Regarding vertex color at runtime. This tutorial shows it's possible if you use a texture.

  • xyzxyz Posts: 204Member
    edited October 18

    It's possible with a texture as already mentioned, but using instance custom data is far less work, so I'd suggest trying that first.

    Custom instance data can mean whatever you want it to mean. You set that data from script using MultiMesh.set_instance_custom_data(). and read it from shader via INSTANCE_CUSTOM built-in, as you said. Data is sent as Color object but it's just 4 floats that your shader can use for whatever purpose it needs. In this case, it'd be visibility info.

    You just need to determine instance ids of blatts that are covered, use one of the custom floats as a flag that determines visibility (say 0 is invisible, 1 is visible), check that custom value in the vertex shader and skip drawing the instance if flag is not set.

    Or more elegantly just scale the blatt to the ground by the value of that flag to avoid branching in shader (assuming blatt base is at y=0)

    So in your script at startup, set all instances to be visible:

    for b in blatt_instances:
        multimesh.set_instance_custom_data(b, Color(1.0, 0.0, 0.0, 0.0) )
    

    In your script when some blatts become invisible:

    for b in newly_culled_blatt_instances:
        multimesh.set_instance_custom_data(b, Color(0.0, 0.0, 0.0, 0.0) )
    

    And in your vertex shader:

        VERTEX.y *= INSTANCE_CUSTOM.r;
    
  • CodeGuru12CodeGuru12 Posts: 4Member

    @xyz Thanks! I should have guess I could put whatever I want in there. Appreciate the detailed example as well. Should work perfectly for what I'm trying to do.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file