2021-03-27 10:03:24 +00:00
|
|
|
#include "SlimeVertex.cginc"
|
|
|
|
|
#include "UnityCG.cginc"
|
|
|
|
|
#define NUM_THREAD_X 64
|
|
|
|
|
|
|
|
|
|
// Each #kernel tells which function to compile; you can have many kernels
|
|
|
|
|
#pragma kernel UpdateAgents
|
|
|
|
|
#pragma kernel Diffuse
|
|
|
|
|
#pragma kernel CreateAgentParticles
|
2021-05-25 22:01:59 +01:00
|
|
|
#pragma kernel UpdateTrailPoints
|
|
|
|
|
#pragma kernel CreateTrailGeometry
|
|
|
|
|
// #pragma kernel CreateParticleGeometry
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Struct for storing the current state of each simulated slime agent
|
|
|
|
|
struct Agent
|
|
|
|
|
{
|
|
|
|
|
float2 position;
|
|
|
|
|
float angle;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Particle
|
|
|
|
|
{
|
|
|
|
|
float3 start;
|
2021-03-28 03:17:55 +01:00
|
|
|
float intensity;
|
2021-03-27 10:03:24 +00:00
|
|
|
};
|
|
|
|
|
|
2021-03-28 03:17:55 +01:00
|
|
|
struct SlimeParameter
|
|
|
|
|
{
|
|
|
|
|
float SlopeThreshold;
|
|
|
|
|
float SlopeBlend;
|
|
|
|
|
float HighValue;
|
|
|
|
|
float LowValue;
|
2021-03-30 01:17:58 +01:00
|
|
|
float Exponent;
|
2021-03-28 03:17:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct SlimeSettings
|
|
|
|
|
{
|
|
|
|
|
SlimeParameter Deposition;
|
|
|
|
|
SlimeParameter Diffusion;
|
|
|
|
|
SlimeParameter Decay;
|
|
|
|
|
SlimeParameter TurnSpeed;
|
|
|
|
|
SlimeParameter Speed;
|
|
|
|
|
SlimeParameter Drive;
|
|
|
|
|
SlimeParameter SensorDistance;
|
|
|
|
|
SlimeParameter SensorSpread;
|
|
|
|
|
SlimeParameter TrailDamping;
|
|
|
|
|
SlimeParameter Intensity;
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
float evaluate(SlimeParameter param, float slope)
|
2021-03-28 03:17:55 +01:00
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
return lerp(param.LowValue, param.HighValue, pow(smoothstep(param.SlopeThreshold - param.SlopeBlend, param.SlopeThreshold + param.SlopeBlend, slope), param.Exponent));
|
2021-03-28 03:17:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parameter buffer
|
|
|
|
|
RWStructuredBuffer<SlimeSettings> parameters;
|
|
|
|
|
|
2021-03-27 10:03:24 +00:00
|
|
|
// Accumulation Buffer
|
|
|
|
|
RWTexture2D<float> accumulation;
|
|
|
|
|
|
|
|
|
|
// Output of the diffusion kernel
|
|
|
|
|
RWTexture2D<float> diffusedAccumulation;
|
|
|
|
|
|
|
|
|
|
// Agent data buffer
|
|
|
|
|
RWStructuredBuffer<Agent> agents;
|
|
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
RWStructuredBuffer<float2> spawnPositions;
|
|
|
|
|
|
2021-03-27 10:03:24 +00:00
|
|
|
// Use this texture to sample level terrain shape for shenanigans
|
|
|
|
|
Texture2D Heightmap;
|
|
|
|
|
SamplerState samplerHeightmap;
|
|
|
|
|
|
|
|
|
|
int randomOffset;
|
|
|
|
|
int numAgents;
|
2021-03-28 03:17:55 +01:00
|
|
|
float deltaTime;
|
2021-03-30 01:17:58 +01:00
|
|
|
int textureSize;
|
|
|
|
|
int gravityTextureSize;
|
2021-03-27 10:03:24 +00:00
|
|
|
float zoneRadius;
|
2021-03-30 01:17:58 +01:00
|
|
|
int spawnPositionCount;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-05-25 22:01:59 +01:00
|
|
|
// Buffer containing the leading position of the agent particle
|
|
|
|
|
RWStructuredBuffer<Particle> particles;
|
|
|
|
|
|
|
|
|
|
// Output buffer for particle trail geometry
|
|
|
|
|
RWStructuredBuffer<Vertex> vertexBuffer;
|
|
|
|
|
|
|
|
|
|
// Perlin noise parameters
|
|
|
|
|
float noiseAmplitude;
|
|
|
|
|
float time;
|
|
|
|
|
float heightRange;
|
|
|
|
|
float heightOffset;
|
|
|
|
|
int particleCount;
|
|
|
|
|
|
|
|
|
|
RWStructuredBuffer<float3> previousTrailBuffer;
|
|
|
|
|
RWStructuredBuffer<float3> trailBuffer;
|
|
|
|
|
|
|
|
|
|
int trailPoints;
|
|
|
|
|
float trailStartWidth;
|
|
|
|
|
float trailEndWidth;
|
|
|
|
|
float3 cameraPos;
|
|
|
|
|
|
2021-03-27 10:03:24 +00:00
|
|
|
// Hash function from H. Schechter & R. Bridson, goo.gl/RXiKaH
|
|
|
|
|
inline uint hash(uint s)
|
|
|
|
|
{
|
|
|
|
|
s ^= 2747636419u;
|
|
|
|
|
s *= 2654435769u;
|
|
|
|
|
s ^= s >> 16;
|
|
|
|
|
s *= 2654435769u;
|
|
|
|
|
s ^= s >> 16;
|
|
|
|
|
s *= 2654435769u;
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float random(uint seed)
|
|
|
|
|
{
|
|
|
|
|
return float(hash(seed)) / 4294967295.0; // 2^32-1
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
// inline float2 uvToPos(float2 uv)
|
|
|
|
|
// {
|
|
|
|
|
// return (uv - float2(.5, .5)) * (zoneRadius * 2);
|
|
|
|
|
// }
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
inline float2 posToUv(float2 pos)
|
|
|
|
|
{
|
|
|
|
|
return pos / (zoneRadius * 2) + float2(.5, .5);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-28 03:17:55 +01:00
|
|
|
float sense(int2 position, float angle, float directionSign, float spread, float distance)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
const float sensorAngle = angle + directionSign * spread;
|
|
|
|
|
const float2 sensorDir = float2(cos(sensorAngle), sin(sensorAngle));
|
|
|
|
|
const int2 sensorCenter = position + sensorDir * distance;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
float sum = 0;
|
2021-03-28 03:17:55 +01:00
|
|
|
for(int x = -1; x <= 1; x++)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
2021-03-28 03:17:55 +01:00
|
|
|
for(int y = -1; y <= 1; y++)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
const int2 sample = sensorCenter + int2(x, y);
|
|
|
|
|
if(sample.x >= 0 && sample.x < textureSize && sample.y >= 0 && sample.y < textureSize)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
|
|
|
|
sum += accumulation[sample];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return sum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float unlerp(float x, float min, float max)
|
|
|
|
|
{
|
|
|
|
|
return (x - min) / (max - min);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-28 03:17:55 +01:00
|
|
|
// Z-up normal of the heightmap
|
|
|
|
|
float3 GetNormal(int2 pos)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
if(pos.x >= gravityTextureSize || pos.y >= gravityTextureSize) return float3(0, 0, 1);
|
|
|
|
|
|
|
|
|
|
const float e = -Heightmap[pos + int2(1, 0)];
|
|
|
|
|
const float n = -Heightmap[pos + int2(0, 1)];
|
|
|
|
|
const float me = -Heightmap[pos];
|
2021-03-28 03:17:55 +01:00
|
|
|
|
|
|
|
|
// Deduce terrain normal
|
2021-03-30 01:17:58 +01:00
|
|
|
const float3 normal = float3(e - me, n - me, 1.0 / gravityTextureSize * zoneRadius * 2);
|
2021-03-28 03:17:55 +01:00
|
|
|
return normalize(normal);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-27 10:03:24 +00:00
|
|
|
[numthreads(NUM_THREAD_X,1,1)]
|
|
|
|
|
void UpdateAgents (uint3 id : SV_DispatchThreadID)
|
|
|
|
|
{
|
|
|
|
|
if (id.x >= numAgents) return;
|
|
|
|
|
|
|
|
|
|
Agent agent = agents[id.x];
|
2021-03-30 01:17:58 +01:00
|
|
|
const SlimeSettings settings = parameters[0];
|
2021-03-28 03:17:55 +01:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const float2 uv = posToUv(agent.position);
|
|
|
|
|
const int2 texPos = int2(uv * textureSize);
|
|
|
|
|
const int2 gravTexPos = int2(uv * gravityTextureSize);
|
|
|
|
|
const float3 normal = GetNormal(gravTexPos);
|
|
|
|
|
const float slope = acos(dot(normal, float3(0,0,1))) / UNITY_HALF_PI;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Move Agents based on direction and speed
|
2021-03-30 01:17:58 +01:00
|
|
|
const float2 direction = float2(cos(agent.angle), sin(agent.angle));
|
|
|
|
|
agent.position += direction * evaluate(settings.Speed, slope) * deltaTime;
|
|
|
|
|
|
|
|
|
|
const float r = random(id.x + randomOffset);
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Clamp position within bounds and randomize direction
|
2021-05-25 22:01:59 +01:00
|
|
|
if(dot(agent.position, agent.position) > zoneRadius * zoneRadius || isnan(agent.position.x) || slope > .8)
|
2021-03-28 03:17:55 +01:00
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
agent.position = spawnPositions[id.x%spawnPositionCount];
|
2021-03-28 03:17:55 +01:00
|
|
|
agent.angle = r * UNITY_TWO_PI;
|
|
|
|
|
}
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const float spread = evaluate(settings.SensorSpread, slope);
|
|
|
|
|
const float distance = evaluate(settings.SensorDistance, slope);
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Acquire sensory data
|
2021-03-30 01:17:58 +01:00
|
|
|
const float forwardSensor = sense(texPos, agent.angle, 0, spread, distance);
|
2021-03-28 03:17:55 +01:00
|
|
|
float leftSensor = sense(texPos, agent.angle, -1, spread, distance);
|
|
|
|
|
float rightSensor = sense(texPos, agent.angle, 1, spread, distance);
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Determine the range of the sensor inputs
|
2021-03-30 01:17:58 +01:00
|
|
|
const float minSensor = min(min(leftSensor, rightSensor), forwardSensor);
|
|
|
|
|
const float maxSensor = max(max(max(leftSensor, rightSensor), forwardSensor), .01);
|
|
|
|
|
const float range = min(maxSensor - minSensor, .01);
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Normalize sensor inputs
|
2021-03-28 03:17:55 +01:00
|
|
|
//forwardSensor = unlerp(forwardSensor, minSensor, maxSensor);
|
2021-03-27 10:03:24 +00:00
|
|
|
leftSensor = unlerp(leftSensor, minSensor, maxSensor);
|
|
|
|
|
rightSensor = unlerp(rightSensor, minSensor, maxSensor);
|
|
|
|
|
|
|
|
|
|
// Which direction it wants to turn in
|
2021-03-30 01:17:58 +01:00
|
|
|
const float desire = leftSensor - rightSensor;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// Strength of its directional preference
|
2021-03-30 01:17:58 +01:00
|
|
|
const float motivation = pow(range / maxSensor, 1 / max(evaluate(settings.Drive, slope),.001));
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
agent.angle += evaluate(settings.TurnSpeed, slope) * lerp(r * 2 - 1, desire, motivation) * deltaTime;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
agents[id.x] = agent;
|
2021-03-30 01:17:58 +01:00
|
|
|
accumulation[texPos] += evaluate(settings.Deposition, slope) * deltaTime;
|
2021-03-27 10:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[numthreads(8,8,1)]
|
|
|
|
|
void Diffuse (uint3 id : SV_DispatchThreadID)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
if(id.x >= textureSize || id.y >= textureSize) return;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const float previous = accumulation[id.xy];
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const SlimeSettings settings = parameters[0];
|
|
|
|
|
const float3 normal = GetNormal(id.xy * (gravityTextureSize / textureSize));
|
|
|
|
|
const float slope = acos(dot(normal, float3(0,0,1))) / UNITY_HALF_PI;
|
2021-03-28 03:17:55 +01:00
|
|
|
|
2021-03-27 10:03:24 +00:00
|
|
|
float sum = 0;
|
|
|
|
|
for(int x = -1; x <= 1; x++)
|
|
|
|
|
{
|
|
|
|
|
for(int y=-1; y <= 1; y++)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
const int2 sample = int2(id.x+x, id.y+y);
|
|
|
|
|
if(sample.x >= 0 && sample.x < textureSize && sample.y >= 0 && sample.y < textureSize)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
|
|
|
|
sum += accumulation[sample];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-30 01:17:58 +01:00
|
|
|
const float average = sum / 9;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
diffusedAccumulation[id.xy] = lerp(previous, average, saturate(evaluate(settings.Diffusion, slope) * deltaTime)) * saturate(1-evaluate(settings.Decay, slope) * deltaTime);
|
2021-03-27 10:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define HASHSCALE 0.1031
|
|
|
|
|
float hashp(float p)
|
|
|
|
|
{
|
|
|
|
|
float3 p3 = frac(p.xxx * HASHSCALE);
|
|
|
|
|
p3 += dot(p3, p3.yzx + 19.19);
|
|
|
|
|
return frac((p3.x + p3.y) * p3.z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float fade(float t) { return t*t*t*(t*(6.*t-15.)+10.); }
|
|
|
|
|
|
|
|
|
|
float grad(float hash, float p)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
return (int(1e4*hash) & 1) == 0 ? p : -p;
|
2021-03-27 10:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float perlinNoise1D(float p)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
const float pi = floor(p), pf = p - pi;
|
2021-05-25 22:01:59 +01:00
|
|
|
return lerp(grad(hashp(pi), pf), grad(hashp(pi + 1.0), pf - 1.0), fade(pf)) * 2.0 - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fractal sum, range -1.0 - 1.0
|
|
|
|
|
float fBm(float p, int octaves)
|
|
|
|
|
{
|
|
|
|
|
float freq = 1, amp = .5;
|
|
|
|
|
float sum = 0;
|
|
|
|
|
for(int i = 0; i < octaves; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i<4)
|
|
|
|
|
sum += (1-abs(perlinNoise1D(p * freq))) * amp;
|
|
|
|
|
else sum += abs(perlinNoise1D(p * freq)) * amp;
|
|
|
|
|
freq *= 2;
|
|
|
|
|
amp *= .75;
|
|
|
|
|
}
|
|
|
|
|
return (sum + 0)*noiseAmplitude;
|
2021-03-27 10:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[numthreads(NUM_THREAD_X,1,1)]
|
|
|
|
|
void CreateAgentParticles (uint3 id : SV_DispatchThreadID)
|
|
|
|
|
{
|
2021-03-30 01:17:58 +01:00
|
|
|
const Agent agent = agents[id.x];
|
2021-03-28 03:17:55 +01:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const float2 uv = posToUv(agent.position);
|
|
|
|
|
const int2 gravTexPos = int2(uv * gravityTextureSize);
|
|
|
|
|
const float3 normal = GetNormal(gravTexPos);
|
|
|
|
|
const float height = -Heightmap[gravTexPos];
|
|
|
|
|
const float slope = acos(dot(normal, float3(0,0,1))) / UNITY_HALF_PI;
|
|
|
|
|
|
|
|
|
|
const SlimeSettings settings = parameters[0];
|
|
|
|
|
|
|
|
|
|
const float sequence = (float)id.x/particleCount;
|
2021-03-28 03:17:55 +01:00
|
|
|
//float height = -Heightmap.SampleLevel(samplerHeightmap, posToUv(agent.position), 0);
|
2021-03-30 01:17:58 +01:00
|
|
|
const float particleHeight = height + pow(random(id.x)-.5, 3) * heightRange + heightOffset;
|
2021-03-27 10:03:24 +00:00
|
|
|
Particle particle = particles[id.x];
|
2021-03-30 01:17:58 +01:00
|
|
|
const float damping = evaluate(settings.TrailDamping, slope);
|
|
|
|
|
const float3 targetPosition = float3(
|
2021-05-25 22:01:59 +01:00
|
|
|
agent.position.x + fBm(id.x*3 + time + sequence, 4),
|
|
|
|
|
particleHeight + fBm(id.x*3 + 1 + time + sequence, 4),
|
|
|
|
|
agent.position.y + fBm(id.x*3 + 2 + time + sequence, 4));
|
|
|
|
|
if(length(particle.start-targetPosition) > 32)
|
2021-03-28 03:17:55 +01:00
|
|
|
{
|
|
|
|
|
particle.start = targetPosition;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
particle.start = lerp(particle.start, targetPosition, damping);
|
|
|
|
|
}
|
2021-03-30 01:17:58 +01:00
|
|
|
particle.intensity = evaluate(settings.Intensity, slope);
|
2021-03-27 10:03:24 +00:00
|
|
|
particles[id.x] = particle;
|
|
|
|
|
}
|
2021-05-25 22:01:59 +01:00
|
|
|
|
|
|
|
|
[numthreads(NUM_THREAD_X,1,1)]
|
|
|
|
|
void UpdateTrailPoints (uint3 id : SV_DispatchThreadID)
|
|
|
|
|
{
|
|
|
|
|
// give every trail position its own particle
|
|
|
|
|
const int idx = id.x;
|
|
|
|
|
const int particleIndex = idx / trailPoints;
|
|
|
|
|
const int trailIndex = idx % trailPoints;
|
|
|
|
|
|
|
|
|
|
const Particle particle = particles[particleIndex];
|
|
|
|
|
|
|
|
|
|
if(trailIndex==trailPoints-1)
|
|
|
|
|
{
|
|
|
|
|
trailBuffer[idx] = particle.start;
|
|
|
|
|
}
|
|
|
|
|
else trailBuffer[idx] = previousTrailBuffer[idx+1];
|
|
|
|
|
}
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
// https://catlikecoding.com/unity/tutorials/curves-and-splines/
|
|
|
|
|
inline float3 QuadraticSplinePosition(float3 p0, float3 p1, float3 p2, float t)
|
|
|
|
|
{
|
|
|
|
|
//return lerp(lerp(p0,p1,t),lerp(p1,p2,t),t);
|
2021-03-30 01:17:58 +01:00
|
|
|
const float oneMinusT = 1 - t;
|
2021-03-27 10:03:24 +00:00
|
|
|
return
|
|
|
|
|
oneMinusT * oneMinusT * p0 +
|
|
|
|
|
2 * oneMinusT * t * p1 +
|
|
|
|
|
t * t * p2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float3 QuadraticSplineDerivative (float3 p0, float3 p1, float3 p2, float t) {
|
|
|
|
|
return
|
|
|
|
|
2 * (1 - t) * (p1 - p0) +
|
|
|
|
|
2 * t * (p2 - p1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float3 calcToCameraDir(float3 pos)
|
|
|
|
|
{
|
|
|
|
|
return normalize(cameraPos - pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[numthreads(NUM_THREAD_X,1,1)]
|
2021-05-25 22:01:59 +01:00
|
|
|
void CreateTrailGeometry (uint3 id : SV_DispatchThreadID)
|
2021-03-27 10:03:24 +00:00
|
|
|
{
|
|
|
|
|
Vertex v0 = GetDefaultVertex();
|
|
|
|
|
Vertex v1 = GetDefaultVertex();
|
2021-03-30 01:17:58 +01:00
|
|
|
|
2021-05-25 22:01:59 +01:00
|
|
|
// give every trail position its own particle
|
2021-03-30 01:17:58 +01:00
|
|
|
const int idx = id.x;
|
|
|
|
|
const int particleIndex = id.x / trailPoints;
|
|
|
|
|
const int trailIndex = id.x % trailPoints;
|
2021-03-27 10:03:24 +00:00
|
|
|
float trailLerp = (float) trailIndex / trailPoints;
|
|
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const Particle particle = particles[particleIndex];
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-05-25 22:01:59 +01:00
|
|
|
float3 dirPrev = float3(0,0,0);
|
|
|
|
|
float3 dirNext = float3(0,0,0);
|
|
|
|
|
|
|
|
|
|
float3 pos = trailBuffer[idx];
|
|
|
|
|
|
|
|
|
|
if ( trailIndex!=0 )
|
|
|
|
|
dirPrev = normalize(pos - trailBuffer[idx-1]);
|
|
|
|
|
|
|
|
|
|
if( trailIndex < trailPoints-1 )
|
|
|
|
|
dirNext = normalize(trailBuffer[idx+1] - pos);
|
|
|
|
|
|
|
|
|
|
const float3 dir = normalize(dirPrev + dirNext);
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const float width = lerp(trailStartWidth, trailEndWidth, trailLerp);
|
|
|
|
|
|
|
|
|
|
const float3 toCameraDir = calcToCameraDir(pos);
|
|
|
|
|
const float3 right = normalize(cross(dir, toCameraDir)) * width * 0.5f / particle.intensity;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
v0.pos = pos - right;
|
|
|
|
|
v0.uv = float2(trailLerp, 0);
|
2021-03-28 03:17:55 +01:00
|
|
|
v0.intensity = particle.intensity;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
|
|
|
|
v1.pos = pos + right;
|
|
|
|
|
v1.uv = float2(trailLerp, 1);
|
2021-03-28 03:17:55 +01:00
|
|
|
v1.intensity = particle.intensity;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
2021-03-30 01:17:58 +01:00
|
|
|
const uint vId = idx * 2;
|
2021-03-27 10:03:24 +00:00
|
|
|
vertexBuffer[vId] = v0;
|
|
|
|
|
vertexBuffer[vId+1] = v1;
|
2021-05-25 22:01:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// [numthreads(NUM_THREAD_X,1,1)]
|
|
|
|
|
// void CreateParticleGeometry (uint3 id : SV_DispatchThreadID)
|
|
|
|
|
// {
|
|
|
|
|
// Vertex v0 = GetDefaultVertex();
|
|
|
|
|
// Vertex v1 = GetDefaultVertex();
|
|
|
|
|
//
|
|
|
|
|
// // give every trail position its own particle
|
|
|
|
|
// const int idx = id.x;
|
|
|
|
|
// const int particleIndex = id.x / trailPoints;
|
|
|
|
|
// const int trailIndex = id.x % trailPoints;
|
|
|
|
|
// float trailLerp = (float) trailIndex / trailPoints;
|
|
|
|
|
//
|
|
|
|
|
// const Particle particle = particles[particleIndex];
|
|
|
|
|
//
|
|
|
|
|
// const float3 pos = QuadraticSplinePosition(particle.start, particle.middle, particle.end, trailLerp);
|
|
|
|
|
// const float3 dir = QuadraticSplineDerivative(particle.start, particle.middle, particle.end, trailLerp);
|
|
|
|
|
//
|
|
|
|
|
// const float width = lerp(trailStartWidth, trailEndWidth, trailLerp);
|
|
|
|
|
//
|
|
|
|
|
// const float3 toCameraDir = calcToCameraDir(pos);
|
|
|
|
|
// const float3 right = normalize(cross(dir, toCameraDir)) * width * 0.5f / particle.intensity;
|
|
|
|
|
//
|
|
|
|
|
// v0.pos = pos - right;
|
|
|
|
|
// v0.uv = float2(trailLerp, 0);
|
|
|
|
|
// v0.intensity = particle.intensity;
|
|
|
|
|
//
|
|
|
|
|
// v1.pos = pos + right;
|
|
|
|
|
// v1.uv = float2(trailLerp, 1);
|
|
|
|
|
// v1.intensity = particle.intensity;
|
|
|
|
|
//
|
|
|
|
|
// const uint vId = idx * 2;
|
|
|
|
|
// vertexBuffer[vId] = v0;
|
|
|
|
|
// vertexBuffer[vId+1] = v1;
|
|
|
|
|
// }
|