我有这个代码:
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);
}
}
我想对这个聚光灯应用蒙版纹理。
我已将
float mask
添加到 BlinnPhong
函数中,并在 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;
}
问题是:我应该使用什么紫外线才能获得正确的结果?
我尝试过使用网格顶点 uv:
//pixel shader
float mask = t_spotlightMask.Sample(g_pointWrap, input.mesh_uv).r;
但是结果和上图一样。
我也尝试过将
lightDir
转换为 uv
:
float theta = acos(lightDir.y);
float phi = atan2(lightDir.z, lightDir.x);
float u = phi / (2 * PI) + 0.5;
float v = theta / PI;
但面膜仍然没有正确敷贴。
编辑:
在尝试了几种不同的方法之后,我成功实现了这样的目标:
但正如你所看到的,有些东西仍然关闭......(标记为红色)
float maskSize = 512;
float2 scale = 1.0f / float2(maskSize * 0.5f, maskSize * 0.5f);
float2 offset = float2(0.0f, 0.5f);
float2 uv = clipPosition.xy * scale + offset;
float mask = t_spotlightMask.Sample(g_pointWrap, uv).r;
我研究了 Unity 的聚光灯 cookie 着色器代码,发现我必须计算
worldToLightPerspective
矩阵:
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;
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;
现在效果很好