Search code examples
openglstructglslshader

How to pass a custom struct from vertex shader to fragment shader


In the fragment shader, I defined two structures as follows

struct DirLight{
    vec3 direction;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

struct PointLight {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float constant;
    float linear; 
    float quadratic;
};

and in vertex shader, I defined the following variables, because I first want to do some transformations (like matrix multiplication that is not recommended in the fragment shader) on these uniform variables in the vertex shader.

uniform DirLight dirLight; // only one directional light
uniform int pointLightCnt; // number of point light sources
uniform PointLight pointLight[MAX]; // point lights

What should I do to transfer the structure in the vertex shader to the fragment shader?

Can I use a method similar to c++ like: Define the structure in the header file, include them in both the vertex shader and the fragment shader, then define the corresponding out variable in the vertex shader, and define the corresponding in variable in the fragment shader to achieve it?


Solution

  • I was going to go into a long explanation of how to implement your lighting structure so it is generic to any light type, but that is a separate issue.

    Your current issue is that the Vertex Function shouldn't need to use the lighting uniform at all; there's no data to pass between them. The only thing the Vertex shader should be doing is converting the local space to clip space and saving the intermediate world space as a separate part of the fragment shader's input so it can calculate the lighting properly.

    All the lighting calculations can be done on the pixel/fragment shader and any dynamic lighting (positions, penumbra calculations, direction changes, etc) should be done on the CPU and just passed on to the GPU in the lighting buffer/uniform all at once.

    This is in hlsl, but it's easily converted to glsl:

    //Uniform
    cbuffer matrix_cb : register(b0) {
        float4x4 g_MODEL;
        float4x4 g_VIEW;
        float4x4 g_PROJECTION;
    };
    
    struct vs_in_t {
        float3 position : POSITION;
        float4 color : COLOR;
        float2 uv : UV;
        float4 normal : NORMAL;
    };
    
    struct ps_in_t {
        float4 position : SV_POSITION;
        float4 color : COLOR;
        float2 uv : UV;
        float4 normal : NORMAL;
        float3 world_position : WORLD;
    };
    
    ps_in_t VertexFunction(vs_in_t input_vertex) {
        ps_in_t output;
    
        float4 local = float4(input_vertex.position, 1.0f);
        float4 normal = input_vertex.normal;
        float4 world = mul(local, g_MODEL);
        float4 view = mul(world, g_VIEW);
        float4 clip = mul(view, g_PROJECTION);
    
        output.position = clip;
        output.color = input_vertex.color;
        output.uv = input_vertex.uv;
        output.normal = normal;
        output.world_position = world.xyz;
    
        return output;
    }