Files
CosmicEngine/assets/shaders/slang/triangle.slang
T

188 lines
5.8 KiB
Plaintext
Raw Normal View History

2026-08-30 17:17:11 +02:00
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;
};
2026-08-30 17:17:11 +02:00
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")]
2026-08-30 17:17:11 +02:00
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;
}
2026-08-30 17:17:11 +02:00
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)
{
2026-08-30 17:17:11 +02:00
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);
}