188 lines
5.8 KiB
Plaintext
188 lines
5.8 KiB
Plaintext
struct VSInput {
|
|
[[vk::location(0)]] float3 inPosition;
|
|
[[vk::location(1)]] float4 inColor;
|
|
[[vk::location(2)]] float3 inNormal;
|
|
[[vk::location(3)]] float2 inUV;
|
|
[[vk::location(4)]] float3 inTangent;
|
|
[[vk::location(5)]] float3 inBitangent;
|
|
};
|
|
|
|
struct VSOutput
|
|
{
|
|
float4 pos : SV_Position;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD0;
|
|
float3 normal : NORMAL;
|
|
float3 fragPos : TEXCOORD1; // position monde
|
|
float3 viewPos : TEXCOORD2; // position caméra
|
|
};
|
|
|
|
// set 0 - Camera
|
|
struct CameraUBO {
|
|
float4x4 view;
|
|
float4x4 projection;
|
|
};
|
|
[[vk::binding(0, 0)]] ConstantBuffer<CameraUBO> camera;
|
|
|
|
// set 1 - Transform
|
|
struct TransformUBO {
|
|
float4x4 model;
|
|
};
|
|
[[vk::binding(0, 1)]] ConstantBuffer<TransformUBO> transform;
|
|
|
|
// set 2 - Material
|
|
[[vk::binding(1, 2)]] Sampler2D albedoTexture; // texture + sampler combinés, pas de warning
|
|
[[vk::binding(2, 2)]] Sampler2D normalTexture; // deuxième texture si besoin
|
|
|
|
struct LightData {
|
|
float4 position; // w = type
|
|
float4 direction; // w = range
|
|
float4 color; // w = intensity
|
|
float innerCosAngle;
|
|
float outerCosAngle;
|
|
float attenuation;
|
|
float padding;
|
|
};
|
|
|
|
struct LightsBuffer {
|
|
LightData lights[32];
|
|
int lightCount;
|
|
};
|
|
|
|
[[vk::binding(0, 3)]] StructuredBuffer<LightsBuffer> lightsBuffer;
|
|
|
|
[shader("vertex")]
|
|
VSOutput vertMain(VSInput input) {
|
|
VSOutput output;
|
|
|
|
float4x4 modelMatrix = transform.model;
|
|
float4 worldPos = mul(modelMatrix, float4(input.inPosition, 1.0));
|
|
output.pos = mul(camera.projection, mul(camera.view, worldPos));
|
|
output.color = input.inColor;
|
|
output.uv = input.inUV;
|
|
|
|
// Pour une mise à l'échelle uniforme, on peut utiliser directement la matrice 3x3
|
|
float3x3 normalMatrix = (float3x3)modelMatrix;
|
|
// Si mises à l'échelle non-uniforme :
|
|
// float3x3 normalMatrix = transpose(inverse((float3x3)modelMatrix));
|
|
|
|
output.normal = normalize(mul(normalMatrix, input.inNormal));
|
|
output.fragPos = worldPos.xyz;
|
|
|
|
// Position de la caméra dans le monde
|
|
float3x3 R = (float3x3)camera.view;
|
|
output.viewPos = -mul(transpose(R), camera.view[3].xyz);
|
|
|
|
return output;
|
|
}
|
|
|
|
float3 computeDirectional(LightData light, VSOutput vertIn)
|
|
{
|
|
// Normaliser la normale (l'interpolation peut la dénormaliser)
|
|
float3 normal = normalize(vertIn.normal);
|
|
|
|
// Direction de la lumière (utiliser les données de la lumière)
|
|
float3 lightDir = normalize(-light.direction.xyz);
|
|
|
|
// Direction de la vue
|
|
float3 viewDir = normalize(vertIn.viewPos - vertIn.fragPos);
|
|
|
|
// Diffuse (Lambertian)
|
|
float diff = max(dot(normal, lightDir), 0.0);
|
|
float3 diffuse = diff * light.color.xyz * light.color.w;
|
|
|
|
// Specular (Blinn-Phong)
|
|
float3 halfVec = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(normal, halfVec), 0.0), 32.0);
|
|
float3 specular = spec * light.color.xyz * light.color.w * 0.5;
|
|
|
|
// Retourner la somme
|
|
return (diffuse + specular) * light.attenuation;
|
|
}
|
|
|
|
float3 computePoint(LightData light, VSOutput vertIn)
|
|
{
|
|
float3 normal = normalize(vertIn.normal);
|
|
float3 viewDir = normalize(vertIn.viewPos - vertIn.fragPos);
|
|
|
|
// Direction de la lumière (du point lumineux vers le fragment)
|
|
float3 lightDir = normalize(light.position.xyz - vertIn.fragPos);
|
|
|
|
// Distance pour l'atténuation
|
|
float distance = length(light.position.xyz - vertIn.fragPos);
|
|
float attenuation = 1.0 / (1.0 + light.attenuation * distance * distance);
|
|
|
|
// Diffuse
|
|
float diff = max(dot(normal, lightDir), 0.0);
|
|
float3 diffuse = diff * light.color.xyz * light.color.w;
|
|
|
|
// Specular
|
|
float3 halfVec = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(normal, halfVec), 0.0), 32.0);
|
|
float3 specular = spec * light.color.xyz * light.color.w * 0.5;
|
|
|
|
return (diffuse + specular) * attenuation;
|
|
}
|
|
|
|
float3 computeSpot(LightData light, VSOutput vertIn)
|
|
{
|
|
float3 normal = normalize(vertIn.normal);
|
|
float3 viewDir = normalize(vertIn.viewPos - vertIn.fragPos);
|
|
|
|
// Direction du fragment vers la lumière
|
|
float3 lightDir = normalize(light.position.xyz - vertIn.fragPos);
|
|
|
|
// Distance et atténuation
|
|
float distance = length(light.position.xyz - vertIn.fragPos);
|
|
float attenuation = 1.0 / (1.0 + light.attenuation * distance * distance);
|
|
|
|
// Spot light (cosinus de l'angle entre la direction du spot et la direction vers le fragment)
|
|
float cosAngle = dot(-light.direction.xyz, lightDir);
|
|
float spotFactor = smoothstep(light.outerCosAngle, light.innerCosAngle, cosAngle);
|
|
|
|
// Diffuse
|
|
float diff = max(dot(normal, lightDir), 0.0);
|
|
float3 diffuse = diff * light.color.xyz * light.color.w;
|
|
|
|
// Specular
|
|
float3 halfVec = normalize(lightDir + viewDir);
|
|
float spec = pow(max(dot(normal, halfVec), 0.0), 32.0);
|
|
float3 specular = spec * light.color.xyz * light.color.w * 0.5;
|
|
|
|
return (diffuse + specular) * attenuation * spotFactor;
|
|
}
|
|
|
|
[shader("fragment")]
|
|
float4 fragMain(VSOutput vertIn) : SV_Target {
|
|
// Sample textures
|
|
float3 albedo = albedoTexture.Sample(vertIn.uv).rgb;
|
|
|
|
// Ambient
|
|
float3 ambient = 0.03 * albedo;
|
|
|
|
// Lighting accumulé
|
|
float3 lighting = float3(0.0, 0.0, 0.0);
|
|
|
|
// Récupérer les lumières
|
|
LightsBuffer lb = lightsBuffer[0];
|
|
|
|
for (int i = 0; i < lb.lightCount; i++) {
|
|
LightData light = lb.lights[i];
|
|
int lightType = (int)light.position.w;
|
|
|
|
if (lightType == 0)
|
|
lighting += computeDirectional(light, vertIn);
|
|
else if (lightType == 1)
|
|
lighting += computePoint(light, vertIn);
|
|
else if (lightType == 2)
|
|
lighting += computeSpot(light, vertIn);
|
|
}
|
|
|
|
// Résultat final
|
|
float3 finalColor = (ambient + lighting) * albedo;
|
|
|
|
// Tone mapping simple (optionnel)
|
|
// finalColor = finalColor / (finalColor + 1.0);
|
|
|
|
return float4(finalColor, 1.0);
|
|
} |