Jakich UV użyć (lub jak obliczyć) do samplowania maski dla spot light?

0

Mam taki kod:

void BlinnPhong(
        inout float3 outputColor,
        PixelMaterial material,
        float3 lightColor,
        float3 lightDir,
        float3 viewDirection,
        float attenuation)
{
    const float diffuseFactor = dotMax(material.normal, lightDir);
    outputColor += lightColor * diffuseFactor * material.baseColor * attenuation;

    const float3 halfwayDirection = normalize(lightDir + viewDirection);
    float specularFactor = pow(dotMax(material.normal, halfwayDirection), material.roughness);
    if (diffuseFactor == 0.0f)
        specularFactor = 0.0f;
    outputColor += lightColor * specularFactor * material.metalness * attenuation;
}

void EvaluateSpotLights(inout float3 outputColor, PixelMaterial material, float3 pos, float3 viewDirection)
{
    for (uint i = 0; i < spotLights.Length; ++i) {
        SpotLight light = spotLights[i];
        
        const float3 posToLight = light.position - pos;
        const float3 lightDir = normalize(posToLight);

        //light.direction is already normalized
        const float theta = dotMax(lightDir, light.direction);
        const float epsilon = (light.innerOuterCutOff.x - light.innerOuterCutOff.y);
        const float intensity = saturate((theta - light.innerOuterCutOff.x) / epsilon);
        
        const float distance = length(posToLight);
        const float attenuation = (1.0f / (light.constnatLinearQuadratic.x +
                  light.constnatLinearQuadratic.y * distance +
                  light.constnatLinearQuadratic.z * (distance * distance))) * intensity;
        
        BlinnPhong(outputColor, material, light.color, lightDir, viewDirection, attenuation);
    }
}

screenshot-20231125102741.png

I chciałbym dodać do tego spotlight maskę. Mam przygotowane 2 dla testu:
screenshot-20231125102819.png
screenshot-20231125102827.png

Do funkcji BlinnPhong dodałem float mask i przemnożyłem to zaraz po attenuation

void BlinnPhong(
        inout float3 outputColor,
        PixelMaterial material,
        float3 lightColor,
        float3 lightDir,
        float3 viewDirection,
        float attenuation,
        float mask)
{
    const float diffuseFactor = dotMax(material.normal, lightDir);
    outputColor += lightColor * diffuseFactor * material.baseColor * attenuation * mask;

    const float3 halfwayDirection = normalize(lightDir + viewDirection);
    float specularFactor = pow(dotMax(material.normal, halfwayDirection), material.roughness);
    if (diffuseFactor == 0.0f)
        specularFactor = 0.0f;
    outputColor += lightColor * specularFactor * material.metalness * attenuation * mask;
}

Moje pytanie jest, jakich UV użyć do samplowania maski?

Użyłem UV z modelu, który renderuje

float mask = t_spotlightMask.Sample(g_pointWrap, input.mesh_uv).r;

ale wynik jest taki sam jak na pierszym screenshotcie, czyli w ogóle nic się nie zmieniło.

Próbowałem też przekonwertować lightDir na UV:

float theta = acos(lightDir.y);
float phi = atan2(lightDir.z, lightDir.x); 

float u = phi / (2 * PI) + 0.5;
float v = theta / PI;

ale maska nadal nie zakłada się poprawnie.

0

Dobra, zajrzałem w kod unity od spot light cookie i dowiedziałem się, że musze obliczyć macierz worldToLightPerspective, więc zrobiłem:

const glm::mat4& transform = getLightTransform();

const glm::mat4 lightView = glm::inverse(transform);
const glm::mat4 lightProj = glm::perspective(glm::radians(outerCutoff), 1.0f, 0.1f, 100.0f);
const glm::mat4 worldToLightPerspective = lightProj * lightView;

i w shaderze:

float2 ComputeLightCookieUVSpot(float4x4 worldToLightPerspective, float3 samplePositionWS)
{
    // Translate, rotate and project 'positionWS' into the light clip space.
    float4 positionCS = mul(worldToLightPerspective, float4(samplePositionWS, 1));
    float2 positionNDC = positionCS.xy / positionCS.w;

    // Remap NDC to the texture coordinates, from NDC [-1, 1]^2 to [0, 1]^2.
    return saturate(positionNDC * 0.5 + 0.5);
}

float2 maskUV = ComputeLightCookieUVSpot(light.worldToLightPerspective, worldPosition.xyz);
float mask = t_spotlightMask.Sample(g_pointWrap, maskUV).r;

działa wyśmienicie

1 użytkowników online, w tym zalogowanych: 0, gości: 1