(
name: "StandardParticleSystemShader",
resources: [
(
name: "diffuseTexture",
kind: Texture(kind: Sampler2D, fallback: White),
binding: 0
),
(
name: "fyrox_sceneDepth",
kind: Texture(kind: Sampler2D, fallback: White),
binding: 1
),
(
name: "properties",
kind: PropertyGroup([
(
name: "softBoundarySharpnessFactor",
kind: Float(100.0),
),
(
name: "useLighting",
kind: Bool(false),
),
]),
binding: 0
),
(
name: "fyrox_instanceData",
kind: PropertyGroup([
// Autogenerated
]),
binding: 1
),
(
name: "fyrox_cameraData",
kind: PropertyGroup([
// Autogenerated
]),
binding: 2
),
(
name: "fyrox_lightsBlock",
kind: PropertyGroup([
// Autogenerated
]),
binding: 3
),
(
name: "fyrox_lightData",
kind: PropertyGroup([
// Autogenerated
]),
binding: 4
),
],
passes: [
(
name: "Forward",
draw_parameters: DrawParameters(
cull_face: None,
color_write: ColorMask(
red: true,
green: true,
blue: true,
alpha: true,
),
depth_write: false,
stencil_test: None,
depth_test: Some(Less),
blend: Some(BlendParameters(
func: BlendFunc(
sfactor: SrcAlpha,
dfactor: OneMinusSrcAlpha,
alpha_sfactor: SrcAlpha,
alpha_dfactor: OneMinusSrcAlpha,
),
equation: BlendEquation(
rgb: Add,
alpha: Add
)
)),
stencil_op: StencilOp(
fail: Keep,
zfail: Keep,
zpass: Keep,
write_mask: 0xFFFF_FFFF,
),
scissor_box: None
),
vertex_shader:
r#"
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 2) in float particleSize;
layout(location = 3) in float particleRotation;
layout(location = 4) in vec4 vertexColor;
out vec2 texCoord;
out vec4 color;
out vec3 fragmentPosition;
void main()
{
color = S_SRGBToLinear(vertexColor);
texCoord = vertexTexCoord;
vec2 vertexOffset = S_RotateVec2(vertexTexCoord * 2.0 - 1.0, particleRotation);
vec4 worldPosition = fyrox_instanceData.worldMatrix * vec4(vertexPosition, 1.0);
vec3 offset = (vertexOffset.x * fyrox_cameraData.sideVector + vertexOffset.y * fyrox_cameraData.upVector) * particleSize;
vec4 finalPosition = worldPosition + vec4(offset.x, offset.y, offset.z, 0.0);
fragmentPosition = finalPosition.xyz;
gl_Position = fyrox_cameraData.viewProjectionMatrix * finalPosition;
}
"#,
fragment_shader:
r#"
out vec4 FragColor;
in vec2 texCoord;
in vec4 color;
in vec3 fragmentPosition;
float toProjSpace(float z)
{
return (fyrox_cameraData.zFar * fyrox_cameraData.zNear) / (fyrox_cameraData.zFar - z * fyrox_cameraData.zRange);
}
void main()
{
ivec2 depthTextureSize = textureSize(fyrox_sceneDepth, 0);
vec2 pixelSize = vec2(1.0 / float(depthTextureSize.x), 1.0 / float(depthTextureSize.y));
float sceneDepth = toProjSpace(texture(fyrox_sceneDepth, gl_FragCoord.xy * pixelSize).r);
float fragmentDepth = toProjSpace(gl_FragCoord.z);
float depthOpacity = smoothstep((sceneDepth - fragmentDepth) * properties.softBoundarySharpnessFactor, 0.0, 1.0);
vec3 lighting;
if (properties.useLighting) {
lighting = fyrox_lightData.ambientLightColor.xyz;
for(int i = 0; i < min(fyrox_lightsBlock.lightCount, 16); ++i) {
// "Unpack" light parameters.
float halfHotspotAngleCos = fyrox_lightsBlock.lightsParameters[i].x;
float halfConeAngleCos = fyrox_lightsBlock.lightsParameters[i].y;
vec3 lightColor = fyrox_lightsBlock.lightsColorRadius[i].xyz;
float radius = fyrox_lightsBlock.lightsColorRadius[i].w;
vec3 lightPosition = fyrox_lightsBlock.lightsPosition[i];
vec3 direction = fyrox_lightsBlock.lightsDirection[i];
// Calculate lighting.
vec3 toFragment = fragmentPosition - lightPosition;
float distance = length(toFragment);
vec3 toFragmentNormalized = toFragment / distance;
float distanceAttenuation = S_LightDistanceAttenuation(distance, radius);
float spotAngleCos = dot(toFragmentNormalized, direction);
float directionalAttenuation = smoothstep(halfConeAngleCos, halfHotspotAngleCos, spotAngleCos);
lighting += lightColor * (distanceAttenuation * directionalAttenuation);
}
} else {
lighting = vec3(1.0);
}
FragColor = vec4(lighting, 1.0) * color * S_SRGBToLinear(texture(diffuseTexture, texCoord)).r;
FragColor.a *= depthOpacity;
}
"#,
)
],
)