最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

glsl - Shade a mesh uniformly by using the lighting at the center of the mesh - Stack Overflow

programmeradmin3浏览0评论

I am trying to accomplish what is discussed in this video (timestamp is at the part of interest)

Essentially, I have a mesh (a billboarded quadmesh with a texture) that may be fully lit, fully shaded or partially shaded. I want my shader to force the mesh to be shaded equally all over. The idea is to achieve what is displayed in the video: A stylized border between light and shadow that looks like grass, without the grass being visible anywhere else.

In the video, the author describes how he changed the "vertices in the fragment shader to be equal to the origin". Without more info I am having difficulty getting it to work. My approach so far is to modify the LIGHT_VERTEX value to be the center of the model.

This is my shader so far (with billboarding code removed for brevity):

shader_type spatial;
//render_mode alpha_to_coverage, cull_disabled;

instance uniform vec4 albedo_color : source_color;
uniform sampler2D alpha_texture;

varying vec3 world_center;

void vertex() {     
    world_center = (MODEL_MATRIX * vec4(0.0, 0.25, 0.0, 1.0)).xyz;

}

void fragment() {       
    LIGHT_VERTEX = world_center;
    
    vec4 tex = texture(alpha_texture, UV);
    ALBEDO = albedo_color.rgb;
    ALPHA = tex.a;
}

According to godot docs, LIGHT_VERTEX is:

A writable version of VERTEX that can be used to alter light and shadows. Writing to this will not change the position of the fragment.

As I understand it, if I were to set LIGHT_VERTEX to the world coordinates of the center of the quad, the lighting calculations should be performed for each fragment, but only taking into account the lighting at the theoretical center of the quad.

Unfortunately, the results are all over the place.

As the camera rotates (and thus the billboard rotates) the lighting changes.

Here is the full shader with billboard code copied from the godot default billboarded shader:

shader_type spatial;
//render_mode alpha_to_coverage, cull_disabled;

instance uniform vec4 albedo_color : source_color;
uniform sampler2D alpha_texture;

varying vec3 world_center;

void vertex() {
    // Billboard Mode: Y-Billboard (quad rotates around Y-axis to always face the camera)
    vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), MAIN_CAM_INV_VIEW_MATRIX[2].xyz));
    vec3 forward = normalize(cross(MAIN_CAM_INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0)));

    mat4 billboardMatrix = mat4(
        vec4(right, 0.0),
        vec4(0.0, 1.0, 0.0, 0.0),
        vec4(forward, 0.0),
        MODEL_MATRIX[3]  // Preserve original position
    );

    MODELVIEW_MATRIX = VIEW_MATRIX * billboardMatrix;
    MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);

    // Transform the normal correctly into world space
    vec3 worldNormal = (MODEL_MATRIX * vec4(0.0, 1.0, 0.0, 0.0)).xyz;
    NORMAL = normalize(worldNormal); // Ensures proper lighting
    //NORMAL = vec3(0.0, 1.0, 0.0);
    world_center = (MODEL_MATRIX * vec4(0.0, 0.25, 0.0, 1.0)).xyz;

}

void fragment() {       
    LIGHT_VERTEX = world_center;
    
    vec4 tex = texture(alpha_texture, UV);
    ALBEDO = albedo_color.rgb;
    ALPHA = tex.a;
}

And this is what the scene looks like when I don't modify LIGHT_VERTEX. As you can see, there are grass meshes that are partially shaded and "ruin" the bordered shadow effect in the video.

发布评论

评论列表(0)

  1. 暂无评论