Skip to content

Instantly share code, notes, and snippets.

@Piratkopia13
Last active April 16, 2024 10:59
Show Gist options
  • Save Piratkopia13/46c5dda51ed59cfe69b242deb0cf40ce to your computer and use it in GitHub Desktop.
Save Piratkopia13/46c5dda51ed59cfe69b242deb0cf40ce to your computer and use it in GitHub Desktop.
useful hlsl math functions
// Barycentric interpolation
float2 barrypolation(float3 barry, float2 in1, float2 in2, float2 in3) {
return barry.x * in1 + barry.y * in2 + barry.z * in3;
}
float3 barrypolation(float3 barry, float3 in1, float3 in2, float3 in3) {
return barry.x * in1 + barry.y * in2 + barry.z * in3;
}
// Generates a seed for a random number generator from 2 inputs plus a backoff
uint initRand(uint val0, uint val1, uint backoff = 16) {
uint v0 = val0, v1 = val1, s0 = 0;
[unroll]
for (uint n = 0; n < backoff; n++)
{
s0 += 0x9e3779b9;
v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
}
return v0;
}
// Takes our seed, updates it, and returns a pseudorandom float in [0..1]
float nextRand(inout uint s) {
s = (1664525u * s + 1013904223u);
return float(s & 0x00FFFFFF) / float(0x01000000);
}
// Utility function to get a vector perpendicular to an input vector
// (from "Efficient Construction of Perpendicular Vectors Without Branching")
float3 getPerpendicularVector(float3 u) {
float3 a = abs(u);
uint xm = ((a.x - a.y)<0 && (a.x - a.z)<0) ? 1 : 0;
uint ym = (a.y - a.z)<0 ? (1 ^ xm) : 0;
uint zm = 1 ^ (xm | ym);
return cross(u, float3(xm, ym, zm));
}
// Get a cosine-weighted random vector centered around a specified normal direction.
float3 getCosHemisphereSample(inout uint randSeed, float3 hitNorm) {
// Get 2 random numbers to select our sample with
float2 randVal = float2(nextRand(randSeed), nextRand(randSeed));
// Cosine weighted hemisphere sample from RNG
float3 bitangent = getPerpendicularVector(hitNorm);
float3 tangent = cross(bitangent, hitNorm);
float r = sqrt(randVal.x);
float phi = 2.0f * 3.14159265f * randVal.y;
// Get our cosine-weighted hemisphere lobe sample direction
return tangent * (r * cos(phi).x) + bitangent * (r * sin(phi)) + hitNorm.xyz * sqrt(1 - randVal.x);
}
int to1D(int3 ind, int xMax, int yMax) {
return ind.x + xMax * (ind.y + yMax * ind.z);
}
int3 to3D(int ind, int xMax, int yMax) {
int3 ind3d;
ind3d.z = ind / (xMax * yMax);
ind -= (ind3d.z * xMax * yMax);
ind3d.y = ind / xMax;
ind3d.x = ind % xMax;
return ind3d;
}
uint unpackQuarterFloat(uint input, uint index) {
uint output = (input >> ((3-index) * 8)) & 255;
// output = max(1, output);
return output;
}
// Rotation with angle (in radians) and axis
float3x3 angleAxis3x3(float angle, float3 axis) {
float c, s;
sincos(angle, s, c);
float t = 1 - c;
float x = axis.x;
float y = axis.y;
float z = axis.z;
return float3x3(
t * x * x + c, t * x * y - s * z, t * x * z + s * y,
t * x * y + s * z, t * y * y + c, t * y * z - s * x,
t * x * z - s * y, t * y * z + s * x, t * z * z + c
);
}
// Returns a random direction vector inside a cone
// Angle defined in radians
// Example: direction=(0,1,0) and angle=pi returns ([-1,1],[0,1],[-1,1])
float3 getConeSample(inout uint randSeed, float3 direction, float coneAngle) {
float cosAngle = cos(coneAngle);
// Generate points on the spherical cap around the north pole [1].
// [1] See https://math.stackexchange.com/a/205589/81266
float z = nextRand(randSeed) * (1.0f - cosAngle) + cosAngle;
float phi = nextRand(randSeed) * 2.0f * PI;
float x = sqrt(1.0f - z * z) * cos(phi);
float y = sqrt(1.0f - z * z) * sin(phi);
float3 north = float3(0.f, 0.f, 1.f);
// Find the rotation axis `u` and rotation angle `rot` [1]
float3 axis = normalize(cross(north, normalize(direction)));
float angle = acos(dot(normalize(direction), north));
// Convert rotation axis and angle to 3x3 rotation matrix [2]
float3x3 R = angleAxis3x3(angle, axis);
return mul(R, float3(x, y, z));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment