How can I use a Viewport Texture as a Projected Decal

antigravityturtleantigravityturtle Posts: 7Member

I have a viewport texture displaying correctly on meshes as described here and I have been playing around with the Screen Space Decals plugin here, both of which have been extremely useful.

I am attempting to put them together to use the viewport texture as a decal, but when doing so, only one corner pixel from the viewport texture is stretched out to the entire decal plane, and I am struggling to figure out how to use the entire viewport texture on the decal instead of just a single pixel. It seems like perhaps the decal code is struggling to know how to scale the viewport texture correctly, but I haven't been able to fix the problem so far.

I'd be grateful if anyone has any thoughts on what might be going wrong.

Best Answer

  • MegalomaniakMegalomaniak Posts: 3,001
    Accepted Answer

    I wouln't trust the UV coordinates of the default objects in godot. At least in the past they were very problematic. If they have been updated within a couple of more recent versions I wouldn't be aware since I've avoided using them for a while now.

Answers

  • MegalomaniakMegalomaniak Posts: 3,001Admin

    Sounds to me like the issue is with the decal objects UV's but it's hard to analyze something like this without the code.

  • antigravityturtleantigravityturtle Posts: 7Member

    Yeah, makes sense. I'm starting to wonder if it is a problem with the decal shader trying to scale the viewport texture onto the decal mesh before the texture exists, since it is being generated live.

    Here is the shader code from the decal plugin https://github.com/Mr-Slurpy/Screen-Space-Decals

    shader_type spatial;
    shader_type spatial;
    render_mode unshaded, depth_draw_never, cull_front, depth_test_disable;
    
    uniform sampler2D decal : hint_black;
    uniform vec2 offset;
    uniform vec2 scale;
    uniform bool emulate_lighting;
    uniform float brightness;
    
    void fragment(){
        //float zdepth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r * 2.0 - 1.0;
        vec4 pos = inverse(WORLD_MATRIX) * inverse(INV_CAMERA_MATRIX) * INV_PROJECTION_MATRIX *     vec4(SCREEN_UV * 2.0 - 1.0, textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r * 2.0 - 1.0, 1.0);
    
        pos.xyz /= pos.w;
    
        bool inside = all(greaterThanEqual(pos.xyz, vec3(-1.0))) && all(lessThanEqual(pos.xyz, vec3(1.0)));
    
    if(inside){
        vec4 color = texture(decal, (pos.xy * -0.5 - 0.5) * scale + offset);
        if(emulate_lighting){
            float lum = dot(textureLod(SCREEN_TEXTURE, SCREEN_UV, 0).rgb, vec3(0.2125, 0.7154, 0.0721));
            lum += brightness;
            lum = clamp(lum, 0.0, 1.0);
            ALBEDO = color.rgb * lum;
        }else{
            ALBEDO = color.rgb;
        }
        ALPHA = color.a;
    }else{
        discard;
    }
    }
    

    Also the decal.gd script:

    tool
    extends MeshInstance    
    
    const SHADER = preload("decal.shader")
    
    export(Texture) var decal setget set_decal
    export(Vector2) var uv_offset = Vector2() setget set_uv_offset
    export(Vector2) var uv_scale = Vector2(1, 1) setget set_uv_scale
    export(bool) var emulate_lighting = true setget set_emulate_lighting
    export(float, -100.0, 100.0) var brightness = 0.0 setget set_brightness
    
    func _init():
        mesh = CubeMesh.new()
        mesh.material = ShaderMaterial.new()
        mesh.material.shader = SHADER
    
    func set_decal(new_decal):
        decal = new_decal
        mesh.material.set_shader_param("decal", decal)
    
    func set_uv_offset(new_offset):
        uv_offset = new_offset
        mesh.material.set_shader_param("offset", uv_offset)
    
    func set_uv_scale(new_scale):
        uv_scale = new_scale
        mesh.material.set_shader_param("scale", uv_scale)
    
    func set_emulate_lighting(new_value):
        emulate_lighting = new_value
        mesh.material.set_shader_param("emulate_lighting", emulate_lighting)
    
    func set_brightness(new_brightness):
        brightness = new_brightness
        mesh.material.set_shader_param("brightness", brightness * 0.01)
    
  • MegalomaniakMegalomaniak Posts: 3,001Admin

    At a quick glance looks alright, but I have no clue as to what your initial UV Scale variable is . Is the decal mesh(and thus its UV's) created in a separate script or imported from a file?

  • antigravityturtleantigravityturtle Posts: 7Member

    I believe the decal mesh is just created in line 13 of the decal.gd script posted previously, inside the _init function:

    mesh = CubeMesh.new()

    The uv_scale variable I leave at the default Vector2(1,1) to stretch the texture to the entire decal mesh, which works fine for normal textures, but not for the viewport texture. From there, I think the shader code controls how the cube mesh is projected down onto the other geometry along the local z axis to give the decal effect, but I'd have to study up on shader scripting to understand the details of how it functions.

  • MegalomaniakMegalomaniak Posts: 3,001Admin
    Accepted Answer

    I wouln't trust the UV coordinates of the default objects in godot. At least in the past they were very problematic. If they have been updated within a couple of more recent versions I wouldn't be aware since I've avoided using them for a while now.

  • antigravityturtleantigravityturtle Posts: 7Member

    Yep, that did it! I brought in a cube with custom UVs from Blender and tweaked the shader code to line things up, and all is working. Thanks for your help, @Megalomaniak !

Leave a Comment

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