Files
UnrealEngine/Engine/Shaders/Private/PhysicsFieldEval.ush
2025-05-18 13:04:45 +08:00

1037 lines
38 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PhysicsFieldEval.ush
=============================================================================*/
#pragma once
#include "Common.ush"
/* -----------------------------------------------------------------
* Field System constants and context
* -----------------------------------------------------------------
*/
Buffer<float> NodesParams;
Buffer<int> NodesOffsets;
Buffer<int> TargetsOffsets;
float TimeSeconds;
/* -----------------------------------------------------------------
* Shared datas to store field evaluation
* -----------------------------------------------------------------
*/
#define MAX_DATAS 16
groupshared float SharedDatas[64][MAX_DATAS];
static int GFieldGroupThreadId;
/* -----------------------------------------------------------------
* Reandom Vector + Perlin Noise
* -----------------------------------------------------------------
*/
static const int p[512] =
{
151, 160, 137, 91, 90, 15,
131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23,
190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,
77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244,
102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123,
5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,
223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228,
251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107,
49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,
138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
151, 160, 137, 91, 90, 15,
131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23,
190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,
77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244,
102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123,
5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,
223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228,
251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107,
49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,
138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
};
float FadeValue(float t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
float LerpValue(float t, float a, float b)
{
return a + t * (b - a);
}
float GradientDirection(int hash, float x, float y, float z)
{
// CONVERT LO 4 BITS OF HASH CODE INTO 12 GRADIENT DIRECTIONS.
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
float PerlinNoise(float3 pos)
{
// FIND UNIT CUBE THAT CONTAINS POINT.
int X = (int) floor(pos.x) & 255;
int Y = (int) floor(pos.y) & 255;
int Z = (int) floor(pos.z) & 255;
// FIND RELATIVE X,Y,Z OF POINT IN CUBE.
float x = pos.x - floor(pos.x);
float y = pos.y - floor(pos.y);
float z = pos.z - floor(pos.z);
// COMPUTE FADE CURVES FOR EACH OF X,Y,Z.
float u = FadeValue(x);
float v = FadeValue(y);
float w = FadeValue(z);
// HASH COORDINATES OF THE 8 CUBE CORNERS
int A = p[X] + Y;
int AA = p[A] + Z;
int AB = p[A + 1] + Z;
int B = p[X + 1] + Y;
int BA = p[B] + Z;
int BB = p[B + 1] + Z;
// AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE
return clamp(0.97 * LerpValue(w, LerpValue(v, LerpValue(u, GradientDirection(p[AA], x, y, z), // CORNER 0
GradientDirection(p[BA], x - 1, y, z)), // CORNER 1
LerpValue(u, GradientDirection(p[AB], x, y - 1, z), // CORNER 2
GradientDirection(p[BB], x - 1, y - 1, z))), // CORNER 3
LerpValue(v, LerpValue(u, GradientDirection(p[AA + 1], x, y, z - 1), // CORNER 4
GradientDirection(p[BA + 1], x - 1, y, z - 1)), // CORNER 5
LerpValue(u, GradientDirection(p[AB + 1], x, y - 1, z - 1), // CORNER 6
GradientDirection(p[BB + 1], x - 1, y - 1, z - 1)))), -1.0, 1.0); // CORNER 7
}
uint3 RandomVector(int3 p)
{
// taking a signed int then reinterpreting as unsigned gives good behavior for negatives
uint3 v = uint3(p);
// Linear congruential step. These LCG constants are from Numerical Recipies
// For additional #'s, PCG would do multiple LCG steps and scramble each on output
// So v here is the RNG state
v = v * 1664525u + 1013904223u;
// PCG uses xorshift for the final shuffle, but it is expensive (and cheap
// versions of xorshift have visible artifacts). Instead, use simple MAD Feistel steps
//
// Feistel ciphers divide the state into separate parts (usually by bits)
// then apply a series of permutation steps one part at a time. The permutations
// use a reversible operation (usually ^) to part being updated with the result of
// a permutation function on the other parts and the key.
//
// In this case, I'm using v.x, v.y and v.z as the parts, using + instead of ^ for
// the combination function, and just multiplying the other two parts (no key) for
// the permutation function.
//
// That gives a simple mad per round.
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
// only top 16 bits are well shuffled
return v >> 16u;
}
/* -----------------------------------------------------------------
* Field System defines
* -----------------------------------------------------------------
*/
#define NONE_TYPE 0
#define RESULTS_TYPE 1
#define INTEGER_TYPE 2
#define SCALAR_TYPE 3
#define VECTOR_TYPE 4
#define NONE_TARGET 0
#define DYNAMIC_STATE 1
#define LINEAR_FORCE 2
#define EXTERNAL_STRAIN 3
#define KILL_PARTICLES 4
#define LINEAR_VELOCITY 5
#define ANGULAR_VELOCITY 6
#define ANGULAR_TORQUE 7
#define INTERNAL_STRAIN 8
#define DISABLED_THRESHOLD 9
#define SLEEPING_THRESHOLD 10
#define POSITION_STATIC 11
#define POSITION_ANIMATED 12
#define POSITION_TARGET 13
#define DYNAMIC_CONSTRAINT 14
#define COLLISION_GROUP 15
#define ACTIVATE_DISABLED 16
#define NONE_NODE 0
#define UNIFORM_INTEGER 1
#define RADIAL_MASK_INTEGER 2
#define UNIFORM_SCALAR 3
#define RADIAL_FALLOFF_SCALAR 4
#define PLANE_FALLOFF_SCALAR 5
#define BOX_FALLOFF_SCALAR 6
#define NOISE_SCALAR 7
#define UNIFORM_VECTOR 8
#define RADIAL_VECTOR 9
#define RANDOM_VECTOR 10
#define SUM_SCALAR 11
#define SUM_VECTOR 12
#define CONVERSION_FIELD 13
#define CULLING_FIELD 14
#define WAVE_SCALAR 15
#define SET_ALWAYS 0
#define SET_IFF_NOT_INTERIOR 1
#define SET_IFF_NOT_EXTERIOR 2
#define NONE_FALLOFF 0
#define FALLOFF_LINEAR 1
#define FALLOFF_INVERSE 2
#define FALLOFF_SQUARED 3
#define FALLOFF_LOGARITHMIC 4
#define MULTIPLY_OP 0
#define DIVIDE_OP 1
#define ADD_OP 2
#define SUBTRACT_OP 3
#define CULLING_INSIDE 0
#define CULLING_OUTSIDE 1
#define WAVE_COSINE 0
#define WAVE_GAUSSIAN 1
#define WAVE_FALLOFF 2
#define WAVE_DECAY 3
/* -----------------------------------------------------------------
* Quat utils
* -----------------------------------------------------------------
*/
float3 FieldRotateVectorByQuat(in float3 Vector, in float4 Quat)
{
float3 T = 2.0 * cross(Quat.xyz, Vector);
return Vector + Quat.w * T + cross(Quat.xyz, T);
}
float3 FieldUnRotateVectorByQuat(in float3 Vector, in float4 Quat)
{
float3 T = 2.0 * cross(Quat.xyz, Vector);
return Vector - Quat.w * T + cross(Quat.xyz, T);
}
/* -----------------------------------------------------------------
* Uniform Integer Field
* -----------------------------------------------------------------
*/
#define UNIFORM_INTEGER_MAGNITUDE 0
void EvaluateUniformInteger(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
SharedDatas[GFieldGroupThreadId][LocalIndex++] = NodesParams[NodeOffset + UNIFORM_INTEGER_MAGNITUDE];
}
/* -----------------------------------------------------------------
* Radial Int Mask Field
* -----------------------------------------------------------------
*/
#define RADIAL_MASK_INTEGER_RADIUS 0
#define RADIAL_MASK_INTEGER_POSITIONX 1
#define RADIAL_MASK_INTEGER_POSITIONY 2
#define RADIAL_MASK_INTEGER_POSITIONZ 3
#define RADIAL_MASK_INTEGER_INTERIOR_VALUE 4
#define RADIAL_MASK_INTEGER_EXTERIOR_VALUE 5
#define RADIAL_MASK_INTEGER_SET_MASK_CONDITION 6
void EvaluateRadialMaskInteger(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const float3 DeltaPosition = float3(NodesParams[NodeOffset + RADIAL_MASK_INTEGER_POSITIONX],
NodesParams[NodeOffset + RADIAL_MASK_INTEGER_POSITIONY],
NodesParams[NodeOffset + RADIAL_MASK_INTEGER_POSITIONZ]) - SamplePosition;
const float DistanceSquared = dot(DeltaPosition, DeltaPosition);
const int DeltaResult = (DistanceSquared < NodesParams[NodeOffset + RADIAL_MASK_INTEGER_RADIUS] *
NodesParams[NodeOffset + RADIAL_MASK_INTEGER_RADIUS]) ?
(int)NodesParams[NodeOffset + RADIAL_MASK_INTEGER_INTERIOR_VALUE]:
(int)NodesParams[NodeOffset + RADIAL_MASK_INTEGER_EXTERIOR_VALUE];
const int MaskCondition = (int)NodesParams[NodeOffset + RADIAL_MASK_INTEGER_SET_MASK_CONDITION];
SharedDatas[GFieldGroupThreadId][LocalIndex++] = (MaskCondition == SET_ALWAYS) ? DeltaResult :
((MaskCondition == SET_IFF_NOT_INTERIOR) && (SharedDatas[GFieldGroupThreadId][LocalIndex] != NodesParams[NodeOffset + RADIAL_MASK_INTEGER_INTERIOR_VALUE])) ? DeltaResult :
((MaskCondition == SET_IFF_NOT_EXTERIOR) && (SharedDatas[GFieldGroupThreadId][LocalIndex] != NodesParams[NodeOffset + RADIAL_MASK_INTEGER_EXTERIOR_VALUE])) ? DeltaResult : SharedDatas[GFieldGroupThreadId][LocalIndex];
}
/* -----------------------------------------------------------------
* Uniform Scalar Field
* -----------------------------------------------------------------
*/
#define UNIFORM_SCALAR_MAGNITUDE 0
void EvaluateUniformScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
SharedDatas[GFieldGroupThreadId][LocalIndex++] = NodesParams[NodeOffset + UNIFORM_SCALAR_MAGNITUDE];
}
/* -----------------------------------------------------------------
* Common Falloff functions
* -----------------------------------------------------------------
*/
void SetFalloffValue(in int FieldFalloff, in float FieldMagnitude, in float DeltaDistance, out float OutNodeResult)
{
if (FieldFalloff == NONE_FALLOFF)
{
OutNodeResult = FieldMagnitude;
}
else if (FieldFalloff == FALLOFF_LINEAR)
{
OutNodeResult = FieldMagnitude * DeltaDistance;
}
else if (FieldFalloff == FALLOFF_SQUARED)
{
OutNodeResult = FieldMagnitude * DeltaDistance * DeltaDistance;
}
else if (FieldFalloff == FALLOFF_INVERSE)
{
OutNodeResult = FieldMagnitude * 2.0 * (1.0 - 1.0 / (DeltaDistance+1.0));
}
else if (FieldFalloff == FALLOFF_LOGARITHMIC)
{
OutNodeResult = FieldMagnitude * log(DeltaDistance + 1.0) / log(2.0);
}
else
{
OutNodeResult = 0.0;
}
}
/* -----------------------------------------------------------------
* Wave Scalar Field
* -----------------------------------------------------------------
*/
#define WAVE_SCALAR_MAGNITUDE 0
#define WAVE_SCALAR_POSITIONX 1
#define WAVE_SCALAR_POSITIONY 2
#define WAVE_SCALAR_POSITIONZ 3
#define WAVE_SCALAR_WAVELENGTH 4
#define WAVE_SCALAR_PERIOD 5
#define WAVE_SCALAR_TIME 6
#define WAVE_SCALAR_FUNCTION 7
#define WAVE_SCALAR_FALLOFF 8
static const float WAVE_PI = 3.14159265f;
void EvaluateWaveScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex, in float MinLength)
{
const float Distance = length(float3(NodesParams[NodeOffset + WAVE_SCALAR_POSITIONX],
NodesParams[NodeOffset + WAVE_SCALAR_POSITIONY],
NodesParams[NodeOffset + WAVE_SCALAR_POSITIONZ]) - SamplePosition);
const float Wavelength = NodesParams[NodeOffset + WAVE_SCALAR_WAVELENGTH];
const float Velocity = Wavelength / NodesParams[NodeOffset + WAVE_SCALAR_PERIOD];
const float Wavenumber = 2.0 * WAVE_PI / max(Wavelength, MinLength);
const float DeltaTime = max(TimeSeconds - NodesParams[NodeOffset + WAVE_SCALAR_TIME], 0.0);
const float Radius = Velocity * DeltaTime;
const float Phase = Wavenumber * (Distance - Radius);
float Result = 0.0;
const int Function = (int) NodesParams[NodeOffset + WAVE_SCALAR_FUNCTION];
const float Magnitude = NodesParams[NodeOffset + WAVE_SCALAR_MAGNITUDE];
[branch]
if (Function == WAVE_GAUSSIAN)
{
Result = Magnitude * exp(-Phase * Phase);
}
else if (Function == WAVE_COSINE)
{
Result = Magnitude * cos(Phase);
}
else if (Function == WAVE_FALLOFF)
{
const int Falloff = (int) NodesParams[NodeOffset + WAVE_SCALAR_FALLOFF];
if ((Distance < Radius) && (Radius > 0.0))
{
const float Fraction = (1.0 - Distance / Radius);
SetFalloffValue(Falloff, Magnitude, Fraction, Result);
}
}
else if (Function == WAVE_DECAY)
{
const float Decay = DeltaTime / NodesParams[NodeOffset + WAVE_SCALAR_PERIOD];
Result = Magnitude * exp(-Decay * Decay);
}
SharedDatas[GFieldGroupThreadId][LocalIndex++] = Result;
}
/* -----------------------------------------------------------------
* Radial Falloff Field
* -----------------------------------------------------------------
*/
#define RADIAL_FALLOFF_MAGNITUDE 0
#define RADIAL_FALLOFF_MIN_RANGE 1
#define RADIAL_FALLOFF_MAX_RANGE 2
#define RADIAL_FALLOFF_DEFAULT 3
#define RADIAL_FALLOFF_RADIUS 4
#define RADIAL_FALLOFF_POSITIONX 5
#define RADIAL_FALLOFF_POSITIONY 6
#define RADIAL_FALLOFF_POSITIONZ 7
#define RADIAL_FALLOFF_FALLOFF 8
void EvaluateRadialFalloffScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
float ScalarDatas = NodesParams[NodeOffset + RADIAL_FALLOFF_DEFAULT];
const float DeltaRange = NodesParams[NodeOffset + RADIAL_FALLOFF_MAX_RANGE] - NodesParams[NodeOffset + RADIAL_FALLOFF_MIN_RANGE];
const float3 DeltaPosition = float3(NodesParams[NodeOffset + RADIAL_FALLOFF_POSITIONX],
NodesParams[NodeOffset + RADIAL_FALLOFF_POSITIONY],
NodesParams[NodeOffset + RADIAL_FALLOFF_POSITIONZ]) - SamplePosition;
const float LocalDistance = length(DeltaPosition);
const float FieldRadius = NodesParams[NodeOffset + RADIAL_FALLOFF_RADIUS];
if (FieldRadius > 0.0 && LocalDistance < FieldRadius)
{
const float DeltaDistance = 1.0 - LocalDistance / FieldRadius;
SetFalloffValue((int)NodesParams[NodeOffset + RADIAL_FALLOFF_FALLOFF],
1.0, DeltaDistance, ScalarDatas);
ScalarDatas = NodesParams[NodeOffset + RADIAL_FALLOFF_MAGNITUDE] * (NodesParams[NodeOffset + RADIAL_FALLOFF_MIN_RANGE] + ScalarDatas * DeltaRange);
}
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ScalarDatas;
}
/* -----------------------------------------------------------------
* Plane Falloff Field
* -----------------------------------------------------------------
*/
#define PLANE_FALLOFF_MAGNITUDE 0
#define PLANE_FALLOFF_MIN_RANGE 1
#define PLANE_FALLOFF_MAX_RANGE 2
#define PLANE_FALLOFF_DEFAULT 3
#define PLANE_FALLOFF_DISTANCE 4
#define PLANE_FALLOFF_POSITIONX 5
#define PLANE_FALLOFF_POSITIONY 6
#define PLANE_FALLOFF_POSITIONZ 7
#define PLANE_FALLOFF_NORMALX 8
#define PLANE_FALLOFF_NORMALY 9
#define PLANE_FALLOFF_NORMALZ 10
#define PLANE_FALLOFF_FALLOFF 11
void EvaluatePlaneFalloffScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
float ScalarDatas = NodesParams[NodeOffset + PLANE_FALLOFF_DEFAULT];
const float DeltaRange = NodesParams[NodeOffset + PLANE_FALLOFF_MAX_RANGE] - NodesParams[NodeOffset + PLANE_FALLOFF_MIN_RANGE];
const float3 PlaneBase = float3(NodesParams[NodeOffset + PLANE_FALLOFF_POSITIONX],
NodesParams[NodeOffset + PLANE_FALLOFF_POSITIONY],
NodesParams[NodeOffset + PLANE_FALLOFF_POSITIONZ]);
const float3 PlaneNormal = float3(NodesParams[NodeOffset + PLANE_FALLOFF_NORMALX],
NodesParams[NodeOffset + PLANE_FALLOFF_NORMALY],
NodesParams[NodeOffset + PLANE_FALLOFF_NORMALZ]);
const float PlaneOffset = dot(PlaneBase, PlaneNormal);
const float LocalDistance = dot(PlaneNormal, SamplePosition) - PlaneOffset;
const float PlaneDistance = NodesParams[NodeOffset + PLANE_FALLOFF_DISTANCE];
if (PlaneDistance > 0.0 && LocalDistance > -PlaneDistance && LocalDistance < 0.0)
{
const float DeltaDistance = 1.0 + LocalDistance / PlaneDistance;
SetFalloffValue((int)NodesParams[NodeOffset + PLANE_FALLOFF_FALLOFF],
1.0, DeltaDistance, ScalarDatas);
ScalarDatas = NodesParams[NodeOffset + PLANE_FALLOFF_MAGNITUDE] * (NodesParams[NodeOffset + PLANE_FALLOFF_MIN_RANGE] + ScalarDatas * DeltaRange);
}
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ScalarDatas;
}
/* -----------------------------------------------------------------
* Box Falloff Field
* -----------------------------------------------------------------
*/
#define BOX_FALLOFF_MAGNITUDE 0
#define BOX_FALLOFF_MIN_RANGE 1
#define BOX_FALLOFF_MAX_RANGE 2
#define BOX_FALLOFF_DEFAULT 3
#define BOX_FALLOFF_ROTATIONX 4
#define BOX_FALLOFF_ROTATIONY 5
#define BOX_FALLOFF_ROTATIONZ 6
#define BOX_FALLOFF_ROTATIONW 7
#define BOX_FALLOFF_TRANSLATIONX 8
#define BOX_FALLOFF_TRANSLATIONY 9
#define BOX_FALLOFF_TRANSLATIONZ 10
#define BOX_FALLOFF_SCALEX 11
#define BOX_FALLOFF_SCALEY 12
#define BOX_FALLOFF_SCALEZ 13
#define BOX_FALLOFF_FALLOFF 14
void EvaluateBoxFalloffScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
float ScalarDatas = NodesParams[NodeOffset + BOX_FALLOFF_DEFAULT];
const float HalfBox = 50.0;
const float DeltaRange = NodesParams[NodeOffset + BOX_FALLOFF_MAX_RANGE] - NodesParams[NodeOffset + BOX_FALLOFF_MIN_RANGE];
const float4 BoxRotation = float4(NodesParams[NodeOffset + BOX_FALLOFF_ROTATIONX],
NodesParams[NodeOffset + BOX_FALLOFF_ROTATIONY],
NodesParams[NodeOffset + BOX_FALLOFF_ROTATIONZ],
NodesParams[NodeOffset + BOX_FALLOFF_ROTATIONW]);
const float3 BoxTranslation = float3(NodesParams[NodeOffset + BOX_FALLOFF_TRANSLATIONX],
NodesParams[NodeOffset + BOX_FALLOFF_TRANSLATIONY],
NodesParams[NodeOffset + BOX_FALLOFF_TRANSLATIONZ]);
const float3 BoxScale = float3(NodesParams[NodeOffset + BOX_FALLOFF_SCALEX],
NodesParams[NodeOffset + BOX_FALLOFF_SCALEY],
NodesParams[NodeOffset + BOX_FALLOFF_SCALEZ]);
const float3 InverseScale = float3(BoxScale.x != 0.0 ? 1.0 / BoxScale.x : 0.0,
BoxScale.y != 0.0 ? 1.0 / BoxScale.y : 0.0,
BoxScale.z != 0.0 ? 1.0 / BoxScale.z : 0.0);
const float3 LocalPosition = FieldUnRotateVectorByQuat(SamplePosition - BoxTranslation, BoxRotation) * InverseScale;
const float3 DeltaPosition = abs(LocalPosition) - float3(HalfBox, HalfBox, HalfBox);
const int ClosestAxis = ((DeltaPosition.x > DeltaPosition.y) && (DeltaPosition.x > DeltaPosition.z)) ? 0 : (DeltaPosition.y > DeltaPosition.z) ? 1 : 2;
const float OutsideDistance = length(max(DeltaPosition, 0.0));
const float LocalDistance = OutsideDistance + min(DeltaPosition[ClosestAxis], 0.0);
if (LocalDistance < 0.0)
{
const float DeltaDistance = -LocalDistance / HalfBox;
SetFalloffValue((int)NodesParams[NodeOffset + BOX_FALLOFF_FALLOFF],
1.0,DeltaDistance, ScalarDatas);
ScalarDatas = NodesParams[NodeOffset + BOX_FALLOFF_MAGNITUDE] * (NodesParams[NodeOffset + BOX_FALLOFF_MIN_RANGE] + ScalarDatas * DeltaRange);
}
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ScalarDatas;
}
/* -----------------------------------------------------------------
* Noise Field
* -----------------------------------------------------------------
*/
#define NOISE_MIN_RANGE 0
#define NOISE_MAX_RANGE 1
#define NOISE_ROTATIONX 2
#define NOISE_ROTATIONY 3
#define NOISE_ROTATIONZ 4
#define NOISE_ROTATIONW 5
#define NOISE_TRANSLATIONX 6
#define NOISE_TRANSLATIONY 7
#define NOISE_TRANSLATIONZ 8
#define NOISE_SCALEX 9
#define NOISE_SCALEY 10
#define NOISE_SCALEZ 11
void EvaluateNoiseScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex, in float MinScale)
{
const float4 NoiseRotation = float4(NodesParams[NodeOffset + NOISE_ROTATIONX],
NodesParams[NodeOffset + NOISE_ROTATIONY],
NodesParams[NodeOffset + NOISE_ROTATIONZ],
NodesParams[NodeOffset + NOISE_ROTATIONW]);
const float3 NoiseTranslation = float3(NodesParams[NodeOffset + NOISE_TRANSLATIONX],
NodesParams[NodeOffset + NOISE_TRANSLATIONY],
NodesParams[NodeOffset + NOISE_TRANSLATIONZ]);
float3 NoiseScale = float3(NodesParams[NodeOffset + NOISE_SCALEX],
NodesParams[NodeOffset + NOISE_SCALEY],
NodesParams[NodeOffset + NOISE_SCALEZ]);
NoiseScale = 0.5 * max(NoiseScale, float3(MinScale, MinScale, MinScale));
const float3 InverseScale = float3(NoiseScale.x != 0.0 ? 1.0 / NoiseScale.x : 0.0,
NoiseScale.y != 0.0 ? 1.0 / NoiseScale.y : 0.0,
NoiseScale.z != 0.0 ? 1.0 / NoiseScale.z : 0.0);
float3 LocalPosition = fmod(FieldUnRotateVectorByQuat(SamplePosition - NoiseTranslation, NoiseRotation), NoiseScale) * InverseScale;
LocalPosition = (clamp(LocalPosition, float3(-1.0,-1.0,-1.0), float3(1.0,1.0,1.0)) * 0.5 + float3(0.5,0.5,0.5)) * 255;
const float NoiseValue = PerlinNoise(LocalPosition) * 0.5 + 0.5;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = NoiseValue * (NodesParams[NodeOffset + NOISE_MAX_RANGE] -
NodesParams[NodeOffset + NOISE_MIN_RANGE])
+ NodesParams[NodeOffset + NOISE_MIN_RANGE];
}
/* -----------------------------------------------------------------
* Uniform Vector Field
* -----------------------------------------------------------------
*/
#define UNIFORM_VECTOR_MAGNITUDE 0
#define UNIFORM_VECTOR_DIRECTIONX 1
#define UNIFORM_VECTOR_DIRECTIONY 2
#define UNIFORM_VECTOR_DIRECTIONZ 3
void EvaluateUniformVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const float3 VectorDatas = NodesParams[NodeOffset + UNIFORM_VECTOR_MAGNITUDE] * float3(
NodesParams[NodeOffset + UNIFORM_VECTOR_DIRECTIONX],
NodesParams[NodeOffset + UNIFORM_VECTOR_DIRECTIONY],
NodesParams[NodeOffset + UNIFORM_VECTOR_DIRECTIONZ]);
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.x;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.y;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.z;
}
/* -----------------------------------------------------------------
* Radial Vector Field
* -----------------------------------------------------------------
*/
#define RADIAL_VECTOR_MAGNITUDE 0
#define RADIAL_VECTOR_POSITIONX 1
#define RADIAL_VECTOR_POSITIONY 2
#define RADIAL_VECTOR_POSITIONZ 3
void EvaluateRadialVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const float3 RadialDirection = SamplePosition - float3(
NodesParams[NodeOffset + RADIAL_VECTOR_POSITIONX],
NodesParams[NodeOffset + RADIAL_VECTOR_POSITIONY],
NodesParams[NodeOffset + RADIAL_VECTOR_POSITIONZ]);
const float DirectionLength = length(RadialDirection);
const float3 VectorDatas = (DirectionLength != 0.0) ? NodesParams[NodeOffset + RADIAL_VECTOR_MAGNITUDE] *
RadialDirection / DirectionLength : float3(0, 0, 0);
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.x;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.y;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.z;
}
/* -----------------------------------------------------------------
* Random Vector Field
* -----------------------------------------------------------------
*/
#define RANDOM_VECTOR_MAGNITUDE 0
void EvaluateRandomVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const float3 RadialDirection = float3(RandomVector(int3(SamplePosition))) / 0xffff - 0.5;//float3(Rand3DPCG16(int3(SamplePosition))) / 0xffff - 0.5;
const float DirectionLength = length(RadialDirection);
const float3 VectorDatas = (DirectionLength != 0.0) ? NodesParams[NodeOffset + RANDOM_VECTOR_MAGNITUDE] *
RadialDirection / DirectionLength : float3(0, 0, 0);
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.x;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.y;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.z;
}
/* -----------------------------------------------------------------
* Sum Scalar Field
* -----------------------------------------------------------------
*/
#define SUM_SCALAR_MAGNITUDE 0
#define SUM_SCALAR_RIGHT 1
#define SUM_SCALAR_LEFT 2
#define SUM_SCALAR_OPERATION 3
void EvaluateSumScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int HasRight = (int)NodesParams[NodeOffset + SUM_SCALAR_RIGHT];
const int HasLeft = (int)NodesParams[NodeOffset + SUM_SCALAR_LEFT];
LocalIndex -= HasRight + HasLeft;
const int FieldOperation = (int)NodesParams[NodeOffset + SUM_SCALAR_OPERATION];
const bool UnitOperation = (FieldOperation == MULTIPLY_OP) || (FieldOperation == DIVIDE_OP);
int OffsetIndex = LocalIndex;
const float ScalarRight = HasRight ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : UnitOperation ? 1.0 : 0.0;
OffsetIndex += HasRight;
const float ScalarLeft = HasLeft ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : UnitOperation ? 1.0 : 0.0;
float ScalarDatas = 0.0;
if (FieldOperation == MULTIPLY_OP)
{
ScalarDatas = ScalarRight * ScalarLeft;
}
else if (FieldOperation == DIVIDE_OP)
{
ScalarDatas = ScalarLeft / ScalarRight;
}
else if (FieldOperation == ADD_OP)
{
ScalarDatas = ScalarRight + ScalarLeft;
}
else if (FieldOperation == SUBTRACT_OP)
{
ScalarDatas = ScalarLeft - ScalarRight;
}
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ScalarDatas * NodesParams[NodeOffset + SUM_SCALAR_MAGNITUDE];
}
/* -----------------------------------------------------------------
* Sum Vector Field
* -----------------------------------------------------------------
*/
#define SUM_VECTOR_MAGNITUDE 0
#define SUM_VECTOR_SCALAR 1
#define SUM_VECTOR_RIGHT 2
#define SUM_VECTOR_LEFT 3
#define SUM_VECTOR_OPERATION 4
void EvaluateSumVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int HasScalar = (int)NodesParams[NodeOffset + SUM_VECTOR_SCALAR];
const int HasRight = (int)NodesParams[NodeOffset + SUM_VECTOR_RIGHT];
const int HasLeft = (int)NodesParams[NodeOffset + SUM_VECTOR_LEFT];
LocalIndex -= HasScalar + HasRight * 3 + HasLeft * 3;
const int FieldOperation = (int)NodesParams[NodeOffset + SUM_VECTOR_OPERATION];
const bool UnitOperation = (FieldOperation == MULTIPLY_OP) || (FieldOperation == DIVIDE_OP);
int OffsetIndex = LocalIndex;
const float ScalarMagnitude = HasScalar ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : 1.0;
OffsetIndex += HasScalar;
const float3 VectorRight = HasRight ? float3(SharedDatas[GFieldGroupThreadId][OffsetIndex], SharedDatas[GFieldGroupThreadId][OffsetIndex + 1], SharedDatas[GFieldGroupThreadId][OffsetIndex + 2]) : UnitOperation ? float3(1, 1, 1) : float3(0, 0, 0);
OffsetIndex += HasRight * 3;
const float3 VectorLeft = HasLeft ? float3(SharedDatas[GFieldGroupThreadId][OffsetIndex], SharedDatas[GFieldGroupThreadId][OffsetIndex + 1], SharedDatas[GFieldGroupThreadId][OffsetIndex + 2]) : UnitOperation ? float3(1, 1, 1) : float3(0, 0, 0);
float3 VectorDatas = float3(0.0, 0.0, 0.0);
if (FieldOperation == MULTIPLY_OP)
{
VectorDatas = VectorRight * VectorLeft;
}
else if (FieldOperation == DIVIDE_OP)
{
VectorDatas = VectorLeft / VectorRight;
}
else if (FieldOperation == ADD_OP)
{
VectorDatas = VectorRight + VectorLeft;
}
else if (FieldOperation == SUBTRACT_OP)
{
VectorDatas = VectorLeft - VectorRight;
}
VectorDatas *= ScalarMagnitude * NodesParams[NodeOffset + SUM_VECTOR_MAGNITUDE];
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.x;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.y;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = VectorDatas.z;
}
/* -----------------------------------------------------------------
* Conversion Scalar
* -----------------------------------------------------------------
*/
#define CONVERSION_INPUT 0
void EvaluateConversionScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
// conversion in the same LocalIndex
}
/* -----------------------------------------------------------------
* Conversion Integer
* -----------------------------------------------------------------
*/
void EvaluateConversionInteger(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
// conversion in the same LocalIndex
}
/* -----------------------------------------------------------------
* Culling Integer
* -----------------------------------------------------------------
*/
#define CULLING_SCALAR 0
#define CULLING_INPUT 1
#define CULLING_OPERATION 2
void EvaluateCullingInteger(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int HasScalar = (int)NodesParams[NodeOffset + CULLING_SCALAR];
const int HasInput = (int)NodesParams[NodeOffset + CULLING_INPUT];
LocalIndex -= HasScalar + HasInput;
int OffsetIndex = LocalIndex;
const float CullingScalar = HasScalar ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : 0.0;
OffsetIndex += (int)CullingScalar;
const int InputInteger = HasInput ? (int) SharedDatas[GFieldGroupThreadId][OffsetIndex] : 0;
const int CullingOperation = (int)NodesParams[NodeOffset + CULLING_OPERATION];
const bool ValidSample = ((CullingOperation == CULLING_OUTSIDE) && (CullingScalar != 0.0)) ||
((CullingOperation == CULLING_INSIDE) && (CullingScalar == 0.0));
SharedDatas[GFieldGroupThreadId][LocalIndex++] = (float) (ValidSample ? InputInteger : 0);
}
/* -----------------------------------------------------------------
* Culling Scalar
* -----------------------------------------------------------------
*/
void EvaluateCullingScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int HasScalar = (int)NodesParams[NodeOffset + CULLING_SCALAR];
const int HasInput = (int) NodesParams[NodeOffset + CULLING_INPUT];
LocalIndex -= HasScalar + HasInput;
int OffsetIndex = LocalIndex;
const float CullingScalar = HasScalar ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : 0.0;
OffsetIndex += (int)CullingScalar;
const float InputScalar = HasInput ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : 0.0;
const int CullingOperation = (int)NodesParams[NodeOffset + CULLING_OPERATION];
const bool ValidSample = ((CullingOperation == CULLING_OUTSIDE) && (CullingScalar != 0.0)) ||
((CullingOperation == CULLING_INSIDE) && (CullingScalar == 0.0));
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ValidSample ? InputScalar : 0.0;
}
/* -----------------------------------------------------------------
* Culling Vector
* -----------------------------------------------------------------
*/
void EvaluateCullingVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int HasScalar = (int)NodesParams[NodeOffset + CULLING_SCALAR];
const int HasInput = (int)NodesParams[NodeOffset + CULLING_INPUT];
LocalIndex -= HasScalar + HasInput * 3;
int OffsetIndex = LocalIndex;
const float CullingScalar = HasScalar ? SharedDatas[GFieldGroupThreadId][OffsetIndex] : 0.0;
OffsetIndex += (int)CullingScalar;
const float3 InputVector = HasInput ? float3(SharedDatas[GFieldGroupThreadId][OffsetIndex], SharedDatas[GFieldGroupThreadId][OffsetIndex + 1], SharedDatas[GFieldGroupThreadId][OffsetIndex + 2]) : float3(0, 0, 0);
const int CullingOperation = (int)NodesParams[NodeOffset + CULLING_OPERATION];
const bool ValidSample = ((CullingOperation == CULLING_OUTSIDE) && (CullingScalar != 0.0)) ||
((CullingOperation == CULLING_INSIDE) && (CullingScalar == 0.0));
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ValidSample ? InputVector.x : 0.0;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ValidSample ? InputVector.y : 0.0;
SharedDatas[GFieldGroupThreadId][LocalIndex++] = ValidSample ? InputVector.z : 0.0;
}
/* -----------------------------------------------------------------
* Nodes evaluation
* -----------------------------------------------------------------
*/
void EvaluateFieldNodeInteger(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int NodeType = (int)NodesParams[NodeOffset];
[branch]
if (NodeType == UNIFORM_INTEGER)
{
EvaluateUniformInteger(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == RADIAL_MASK_INTEGER)
{
EvaluateRadialMaskInteger(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == CONVERSION_FIELD)
{
EvaluateConversionInteger(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == CULLING_FIELD)
{
EvaluateCullingInteger(SamplePosition, NodeOffset + 1, LocalIndex);
}
}
void EvaluateFieldNodeScalar(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex, in float MinScale, in float MinLength)
{
const int NodeType = (int)NodesParams[NodeOffset];
[branch]
if (NodeType == UNIFORM_SCALAR)
{
EvaluateUniformScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == WAVE_SCALAR)
{
EvaluateWaveScalar(SamplePosition, NodeOffset + 1, LocalIndex, MinLength);
}
else if (NodeType == RADIAL_FALLOFF_SCALAR)
{
EvaluateRadialFalloffScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == PLANE_FALLOFF_SCALAR)
{
EvaluatePlaneFalloffScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == BOX_FALLOFF_SCALAR)
{
EvaluateBoxFalloffScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == NOISE_SCALAR)
{
EvaluateNoiseScalar(SamplePosition, NodeOffset + 1, LocalIndex, MinScale);
}
else if (NodeType == SUM_SCALAR)
{
EvaluateSumScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == CONVERSION_FIELD)
{
EvaluateConversionScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == CULLING_FIELD)
{
EvaluateCullingScalar(SamplePosition, NodeOffset + 1, LocalIndex);
}
}
void EvaluateFieldNodeVector(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex)
{
const int NodeType = (int)NodesParams[NodeOffset];
[branch]
if (NodeType == UNIFORM_VECTOR)
{
EvaluateUniformVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == RADIAL_VECTOR)
{
EvaluateRadialVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == RANDOM_VECTOR)
{
EvaluateRandomVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == SUM_VECTOR)
{
EvaluateSumVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (NodeType == CULLING_FIELD)
{
EvaluateCullingVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
}
void EvaluateFieldNodeDatas(in float3 SamplePosition, in int NodeOffset, inout int LocalIndex, in float MinScale, in float MinLength)
{
const int DatasType = (int)NodesParams[NodeOffset];
[branch]
if (DatasType == SCALAR_TYPE)
{
EvaluateFieldNodeScalar(SamplePosition, NodeOffset + 1, LocalIndex, MinScale, MinLength);
}
else if (DatasType == INTEGER_TYPE)
{
EvaluateFieldNodeInteger(SamplePosition, NodeOffset + 1, LocalIndex);
}
else if (DatasType == VECTOR_TYPE)
{
EvaluateFieldNodeVector(SamplePosition, NodeOffset + 1, LocalIndex);
}
}
void SampleFieldDatas(in float3 SamplePosition, inout int LocalIndex, in int TargetType, in float MinScale, in float MinLength)
{
const int NodesBegin = TargetsOffsets[TargetType];
const int NodesEnd = TargetsOffsets[TargetType + 1];
const int NumNodes = NodesBegin - NodesEnd;
[unroll]
for (int DatasIndex = 0; DatasIndex < MAX_DATAS; ++DatasIndex)
{
SharedDatas[GFieldGroupThreadId][DatasIndex] = 0.0;
}
[branch]
if (NumNodes != 0)
{
for (int NodeIndex = NodesBegin; NodeIndex < NodesEnd; ++NodeIndex)
{
const int NodeOffset = NodesOffsets[NodeIndex];
EvaluateFieldNodeDatas(SamplePosition, NodeOffset, LocalIndex, MinScale, MinLength);
}
}
}
float3 PhysicsField_EvalPhysicsVectorField(in float3 SamplePosition, in int TargetIndex)
{
float3 VectorField = float3(0,0,0);
int LocalIndex = 0;
SampleFieldDatas(SamplePosition, LocalIndex, TargetIndex, 0.0, 0.0);
if(LocalIndex == 3)
{
VectorField.x = SharedDatas[GFieldGroupThreadId][0];
VectorField.y = SharedDatas[GFieldGroupThreadId][1];
VectorField.z = SharedDatas[GFieldGroupThreadId][2];
}
return VectorField;
}
float PhysicsField_EvalPhysicsScalarField(in float3 SamplePosition, in int TargetIndex)
{
float ScalarField = 0.0;
int LocalIndex = 0;
SampleFieldDatas(SamplePosition, LocalIndex, TargetIndex, 0.0, 0.0);
if(LocalIndex == 1)
{
ScalarField = SharedDatas[GFieldGroupThreadId][0];
}
return ScalarField;
}
int PhysicsField_EvalPhysicsIntegerField(in float3 SamplePosition, in int TargetIndex)
{
int IntegerField = 0;
int LocalIndex = 0;
SampleFieldDatas(SamplePosition, LocalIndex, TargetIndex, 0.0, 0.0);
if(LocalIndex == 1)
{
IntegerField = SharedDatas[GFieldGroupThreadId][0];
}
return IntegerField;
}