Ok, je le note... et je vais étudier ça en détails.
En attendant mieux, voici ma version actuelle du shader. J'ai essayé de piocher d'autres valeurs pour générer le bruit aléatoire en faisant un mix à partir de la worldposition du centre de chaque billboard (et non des vertices) ainsi que l'index de chaque billboard.
ça fourmille toujours, mais là je ne vois pas comment obtenir mieux avec cette méthode.
Code : Tout sélectionner
Shader "Custom/BillboardsWithShadows2"
{
Properties
{
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Alpha", 2D) = "white" {}
_Size ("Particle Size", Range(0.01,2)) = 1
_MaxCameraDistance ("Max Camera Distance", float) = 250
_Transition ("Transition", float) = 30
_RandomDithering("Random Dithering", Range(0,10)) = 1
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType"="Transparent" }
// base pass
Pass
{
Tags { "LightMode" = "ForwardBase"}
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Lighting Off
ZWrite Off
CGPROGRAM
#pragma vertex vertexShader
#pragma fragment fragmentShader
#pragma geometry geometryShader
#pragma multi_compile_fwdbase
#pragma multi_compile_fog
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc"
struct VS_INPUT
{
float4 position : POSITION;
float4 uv_Noise : TEXCOORD0;
fixed sizeFactor : TEXCOORD1;
float4 color: COLOR;
};
struct GS_INPUT
{
float4 worldPosition : TEXCOORD0;
float4 color: COLOR;
};
struct FS_INPUT
{
float4 pos : SV_POSITION; // has to be called this way because of unity MACRO for light
float2 uv_MainTexture : TEXCOORD0;
float4 tint : COLOR0;
LIGHTING_COORDS(1,2)
UNITY_FOG_COORDS(3)
};
uniform fixed4 _Color;
uniform sampler2D _MainTex;
// for billboard
uniform float _Size;
uniform float _MaxCameraDistance;
uniform float _Transition;
uniform float4 _LightColor0;
// Vertex Shader ------------------------------------------------
GS_INPUT vertexShader(VS_INPUT vIn)
{
GS_INPUT vOut;
// set output values
vOut.worldPosition = mul(_Object2World, vIn.position);
vOut.color = vIn.color;
return vOut;
}
// Geometry Shader -----------------------------------------------------
[maxvertexcount(4)]
void geometryShader(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream)
{
// cutout trough a transition area
float cameraDistance = length(_WorldSpaceCameraPos - p[0].worldPosition);
// discard billboards that are too far away
if (cameraDistance > _MaxCameraDistance)
return;
float t = (cameraDistance - (_MaxCameraDistance - _Transition)) / _Transition;
float alpha = clamp (1, 0, lerp (1.0, 0.0, t));
float3 viewDirection = UNITY_MATRIX_V[2].xyz;
float3 up = UNITY_MATRIX_V[1].xyz;
float3 right = cross(up, viewDirection);
// billboard's size and color
float halfSize = 0.5f * _Size;
float4 tint = p[0].color;
tint.a = alpha * p[0].color.a;
tint *= _Color;
// create billboard
float4 v[4];
v[0] = float4(p[0].worldPosition + halfSize * right - halfSize * up, 1.0f);
v[1] = float4(p[0].worldPosition + halfSize * right + halfSize * up, 1.0f);
v[2] = float4(p[0].worldPosition - halfSize * right - halfSize * up, 1.0f);
v[3] = float4(p[0].worldPosition - halfSize * right + halfSize * up, 1.0f);
// matrix to transfer vertices from world to screen space
float4x4 vpMatrix = mul(UNITY_MATRIX_MVP, _World2Object);
FS_INPUT fIn;
fIn.pos = mul(vpMatrix, v[0]);
fIn.uv_MainTexture = float2(1.0f, 0.0f);
fIn.tint = tint;
TRANSFER_VERTEX_TO_FRAGMENT(fIn);
UNITY_TRANSFER_FOG(fIn,fIn.pos);
triStream.Append(fIn);
fIn.pos = mul(vpMatrix, v[1]);
fIn.uv_MainTexture = float2(1.0f, 1.0f);
fIn.tint = tint;
TRANSFER_VERTEX_TO_FRAGMENT(fIn);
UNITY_TRANSFER_FOG(fIn,fIn.pos);
triStream.Append(fIn);
fIn.pos = mul(vpMatrix, v[2]);
fIn.uv_MainTexture = float2(0.0f, 0.0f);
fIn.tint = tint;
TRANSFER_VERTEX_TO_FRAGMENT(fIn);
UNITY_TRANSFER_FOG(fIn,fIn.pos);
triStream.Append(fIn);
fIn.pos = mul(vpMatrix, v[3]);
fIn.uv_MainTexture = float2(0.0f, 1.0f);
fIn.tint = tint;
TRANSFER_VERTEX_TO_FRAGMENT(fIn);
UNITY_TRANSFER_FOG(fIn,fIn.pos);
triStream.Append(fIn);
}
// Fragment Shader -----------------------------------------------
float4 fragmentShader(FS_INPUT fIn) : COLOR
{
fixed4 color = tex2D(_MainTex, fIn.uv_MainTexture) * fIn.tint;
if (color.a < 0.01) discard;
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float atten = LIGHT_ATTENUATION(fIn);
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 normal = float3(0,1,0);
float3 lambert = float(max(0.0,dot(normal,lightDirection)));
float3 lighting = (ambient + lambert * atten) * _LightColor0.rgb;
color = fixed4 (color.rgb * lighting, color.a);
UNITY_APPLY_FOG(fIn.fogCoord, color);
return color;
}
ENDCG
}
// shadow caster
Pass
{
//Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
Fog { Mode Off }
ZWrite On
ZTest LEqual
CGPROGRAM
#pragma vertex vertexShader
#pragma geometry geometryShader
#pragma fragment fragmentShader
#pragma multi_compile_shadowcaster
//#pragma only_renderers d3d11
#define SHADOW_CASTER_PASS
#include "UnityCG.cginc"
#include "HLSLSupport.cginc"
struct VS_INPUT
{
float4 position : POSITION;
float4 uv_Noise : TEXCOORD0;
fixed sizeFactor : TEXCOORD1;
uint vid : SV_VertexID;
};
struct SHADOW_VERTEX
{
float4 vertex : POSITION; // has to be called this way because of unity macro
};
struct GS_INPUT
{
float4 worldPosition : TEXCOORD0;
};
struct FS_INPUT
{
float4 uv_MainTexture : TEXCOORD0;
V2F_SHADOW_CASTER;
};
uniform fixed4 _Color;
uniform sampler2D _MainTex;
// for billboard
uniform float _Size;
uniform float _RandomDithering;
uniform float _Transition;
uniform float _MaxCameraDistance;
GS_INPUT vertexShader (VS_INPUT v)
{
GS_INPUT vOut;
// set output values
vOut.worldPosition = mul(_Object2World, v.position);
vOut.worldPosition.w = v.vid; // unique index of the vertex
return vOut;
}
// Geometry Shader
[maxvertexcount(4)]
void geometryShader(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream )
{
// cutout trough a transition area
float cameraDistance = length(_WorldSpaceCameraPos - p[0].worldPosition);
// discard billboards that are too far away
if (cameraDistance > _MaxCameraDistance)
return;
float t = (cameraDistance - (_MaxCameraDistance - _Transition)) / _Transition;
float alpha = clamp (1, 0, lerp (1.0, 0.0, t));
float3 viewDirection = UNITY_MATRIX_V[2].xyz;
float3 up = UNITY_MATRIX_V[1].xyz;
float3 right = cross(up, viewDirection);
// size of billboard
float halfSize = 0.5f * _Size;
// create billboard
float4 vertices[4];
vertices[0] = float4(p[0].worldPosition.xyz + halfSize * right - halfSize * up, 1.0f);
vertices[1] = float4(p[0].worldPosition.xyz + halfSize * right + halfSize * up, 1.0f);
vertices[2] = float4(p[0].worldPosition.xyz - halfSize * right - halfSize * up, 1.0f);
vertices[3] = float4(p[0].worldPosition.xyz - halfSize * right + halfSize * up, 1.0f);
FS_INPUT fIn;
SHADOW_VERTEX v;
v.vertex = mul (_World2Object, vertices[0]);
fIn.uv_MainTexture = float4(1.0f, 0.0f,p[0].worldPosition.xw*0.1);
TRANSFER_SHADOW_CASTER(fIn) // uses "v.vertex" for vertex position
triStream.Append(fIn);
v.vertex = mul (_World2Object, vertices[1]);
fIn.uv_MainTexture = float4(1.0f, 1.0f,p[0].worldPosition.yw*0.1);
TRANSFER_SHADOW_CASTER(fIn)
triStream.Append(fIn);
v.vertex = mul (_World2Object, vertices[2]);
fIn.uv_MainTexture = float4(0.0f, 0.0f,p[0].worldPosition.zw*0.1);
TRANSFER_SHADOW_CASTER(fIn)
triStream.Append(fIn);
v.vertex = mul (_World2Object, vertices[3]);
fIn.uv_MainTexture = float4(0.0f, 1.0f,p[0].worldPosition.w*0.3,p[0].worldPosition.w*0.1);
TRANSFER_SHADOW_CASTER(fIn)
triStream.Append(fIn);
}
float rand(float3 co){
return frac(sin(dot(co.xyz,float3(12.9898,78.233,45.5432)))*43758.5453);
}
fixed4 fragmentShader (FS_INPUT fIn) : COLOR
{
fixed clipme = tex2D(_MainTex, fIn.uv_MainTexture.xy).a * _Color.a - 0.005;
// random dithering
clipme -= rand(fIn.uv_MainTexture.xzw)*_RandomDithering*_RandomDithering;
clip(clipme);
// better stability with QualitySettings/Shadow Projection = Close fit
fIn.pos.xy = floor(fIn.pos.xy) * 0.25;
clipme -= frac(fIn.pos.xy.x + fIn.pos.xy.y);
clip(clipme);
SHADOW_CASTER_FRAGMENT(fIn);
}
ENDCG
}
}
FallBack "Diffuse"
}
Prochaine étape : réception des ombres sur les particules