mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-15 00:05:06 +00:00
372 lines
9.3 KiB
Text
372 lines
9.3 KiB
Text
|
uniform float4x4 ViewProj<
|
||
|
bool automatic = true;
|
||
|
>;
|
||
|
uniform float4 ViewSize<
|
||
|
bool automatic = true;
|
||
|
>;
|
||
|
uniform float4 Time<
|
||
|
bool automatic = true;
|
||
|
>;
|
||
|
|
||
|
// Camera Parameters
|
||
|
uniform float3 CameraPosition<
|
||
|
string name = "Camera Position";
|
||
|
string field_type = "slider";
|
||
|
float3 minimum = {-10.0, -10.0, -10.0};
|
||
|
float3 maximum = {10.0, 10.0, 10.0};
|
||
|
> = {0., 0., 0.};
|
||
|
|
||
|
uniform float3 CameraRotation<
|
||
|
string name = "Camera Rotation";
|
||
|
string suffix = " °Deg";
|
||
|
string field_type = "slider";
|
||
|
float3 minimum = {-180.0, -90.0, -180.0};
|
||
|
float3 maximum = {180.0, 90.0, 180.0};
|
||
|
float3 scale = {0.01745329251994329576923690768489, 0.01745329251994329576923690768489, 0.01745329251994329576923690768489};
|
||
|
> = {0., 0., 0.};
|
||
|
|
||
|
uniform float CameraFieldOfView<
|
||
|
string name = "Camera Field Of View";
|
||
|
string suffix = " °Deg";
|
||
|
string field_type = "slider";
|
||
|
float minimum = 1.0;
|
||
|
float maximum = 180.0;
|
||
|
float scale = 0.00872664625997164788461845384244;
|
||
|
> = 90.0;
|
||
|
|
||
|
uniform float2 CameraRange<
|
||
|
string name = "Camera Range";
|
||
|
string field_type = "slider";
|
||
|
float2 minimum = {0.0, 1.00};
|
||
|
float2 maximum = {10000.0, 10000.0};
|
||
|
float2 scale = {0.01, 0.01};
|
||
|
> = {0.1, 256.0};
|
||
|
|
||
|
uniform int RayMarchAccuracy<
|
||
|
string name = "Ray March Steps";
|
||
|
string field_type = "slider";
|
||
|
int minimum = 32;
|
||
|
int maximum = 1024;
|
||
|
> = 256;
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
// Configuration
|
||
|
#define MAX_ACCURACY 1024
|
||
|
|
||
|
// Camera Type
|
||
|
//#define CAMERA_ORTHOGRAPHIC // Orthographic projection
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
#define INFINITY 1.#INF
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
float4x4 make_rotation_matrix(float3 axis, float angle)
|
||
|
{
|
||
|
axis = normalize(axis);
|
||
|
float s = sin(angle);
|
||
|
float c = cos(angle);
|
||
|
float oc = 1.0 - c;
|
||
|
|
||
|
float x_x = axis.x * axis.x;
|
||
|
float x_y = axis.x * axis.y;
|
||
|
float x_z = axis.x * axis.z;
|
||
|
float y_x = x_y;
|
||
|
float y_y = axis.y * axis.y;
|
||
|
float y_z = axis.y * axis.z;
|
||
|
float z_x = x_z;
|
||
|
float z_y = y_z;
|
||
|
float z_z = axis.z * axis.z;
|
||
|
|
||
|
return float4x4(oc * x_x + c, oc * x_y - axis.z * s, oc * z_x + axis.y * s, 0.0,
|
||
|
oc * x_y + axis.z * s, oc * y_y + c, oc * z_y - axis.x * s, 0.0,
|
||
|
oc * x_z - axis.y * s, oc * y_z + axis.x * s, oc * z_z + c, 0.0,
|
||
|
0.0, 0.0, 0.0, 1.0);
|
||
|
};
|
||
|
|
||
|
float3 rotate_float3(float3 v, float3 rotation)
|
||
|
{
|
||
|
float4x4 rz = make_rotation_matrix(float3(0., 0., 1.), rotation.z);
|
||
|
float4x4 ry = make_rotation_matrix(float3(0., 1., 0.), rotation.y);
|
||
|
float4x4 rx = make_rotation_matrix(float3(1., 0., 0.), rotation.x);
|
||
|
|
||
|
float4 p = float4(v, 1.);
|
||
|
float4 rtd = mul(mul(mul(p, rz), rx), ry);
|
||
|
|
||
|
return rtd.xyz;
|
||
|
};
|
||
|
|
||
|
bool solve_quadratic(float a, float b, float c, out float x0, out float x1)
|
||
|
{
|
||
|
float discr = b * b - 4. * a * c;
|
||
|
if (discr < 0.) {
|
||
|
return false;
|
||
|
} else if (discr == 0.) {
|
||
|
x0 = x1 = - 0.5 * b / a;
|
||
|
} else {
|
||
|
float q = (b > 0.) ?
|
||
|
-0.5 * (b + sqrt(discr)) :
|
||
|
-0.5 * (b - sqrt(discr));
|
||
|
x0 = q / a;
|
||
|
x1 = c / q;
|
||
|
}
|
||
|
|
||
|
if (x0 > x1) {
|
||
|
float tmp = x1;
|
||
|
x1 = x0;
|
||
|
x0 = tmp;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool collide_point_aabb(float3 pos, float3 aabb, float3 size) {
|
||
|
float3 aabb_min = aabb - size;
|
||
|
float3 aabb_max = aabb + size;
|
||
|
return (pos.x >= aabb_min.x)
|
||
|
&& (pos.y >= aabb_min.y)
|
||
|
&& (pos.z >= aabb_min.z)
|
||
|
&& (pos.x <= aabb_max.x)
|
||
|
&& (pos.y <= aabb_max.y)
|
||
|
&& (pos.z <= aabb_max.z);
|
||
|
}
|
||
|
|
||
|
bool collide_aabb_aabb(float3 pos1, float3 size1, float3 pos2, float3 size2) {
|
||
|
float3 min1 = pos1 - size1;
|
||
|
float3 max1 = pos1 + size1;
|
||
|
float3 min2 = pos2 - size2;
|
||
|
float3 max2 = pos2 + size2;
|
||
|
|
||
|
return (min1.x <= max2.x && max1.x >= min2.x) &&
|
||
|
(min1.y <= max2.y && max1.y >= min2.y) &&
|
||
|
(min1.z <= max2.z && max1.z >= min2.z);
|
||
|
}
|
||
|
|
||
|
bool intersect_box(float3 pos, float3 size, float3 ray_pos, float3 ray_dir, out float t) {
|
||
|
float3 aabb_size = float3(max(size.x, max(size.y, size.z)), 0., 0.);
|
||
|
if (!collide_aabb_aabb(ray_pos, ray_dir, pos, aabb_size.xxx))
|
||
|
return false;
|
||
|
|
||
|
t = 0.;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool intersect_sphere(float3 center, float radius, float3 orig, float3 dir, out float t)
|
||
|
{
|
||
|
if (!collide_aabb_aabb(orig, dir, center, float3(radius, radius, radius)))
|
||
|
return false;
|
||
|
|
||
|
float t0, t1; // solutions for t if the ray intersects
|
||
|
float radius2 = radius * radius;
|
||
|
|
||
|
// analytic solution
|
||
|
float3 L = orig - center;
|
||
|
float a = dot(dir, dir);
|
||
|
float b = 2. * dot(dir, L);
|
||
|
float c = dot(L, L) - radius2;
|
||
|
|
||
|
if (!solve_quadratic(a, b, c, t0, t1)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (t0 > t1) {
|
||
|
float tmp = t0;
|
||
|
t0 = t1;
|
||
|
t1 = tmp;
|
||
|
}
|
||
|
|
||
|
if (t0 < 0.) {
|
||
|
t0 = t1; // if t0 is negative, let's use t1 instead
|
||
|
if (t0 < 0.) {
|
||
|
return false; // both t0 and t1 are negative
|
||
|
}
|
||
|
}
|
||
|
|
||
|
t = t0;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
struct default_data {
|
||
|
float4 pos : POSITION;
|
||
|
float2 uv : TEXCOORD0;
|
||
|
};
|
||
|
|
||
|
default_data default_vs(default_data data) {
|
||
|
data.pos = mul(float4(data.pos.xyz, 1.0), ViewProj);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
struct material_data {
|
||
|
float4 color;
|
||
|
float metallic;
|
||
|
float specular;
|
||
|
float roughness;
|
||
|
float4 emissive_color;
|
||
|
float3 normal;
|
||
|
float index_of_refraction;
|
||
|
};
|
||
|
|
||
|
void material_data_constructor(out material_data material)
|
||
|
{
|
||
|
material.color = float4(0., 0., 0., 0.);
|
||
|
material.metallic = 0.;
|
||
|
material.specular = .5;
|
||
|
material.roughness = 1.;
|
||
|
material.emissive_color = float4(0., 0., 0., 0.);
|
||
|
material.normal = float3(0., 0., 0.);
|
||
|
material.index_of_refraction = 1.;
|
||
|
}
|
||
|
|
||
|
struct ray_data {
|
||
|
// Status
|
||
|
float3 position; // Current position.
|
||
|
float3 direction; // Direction of the ray.
|
||
|
int depth; // Ray Calculation Depth, limited by ACCURACY define.
|
||
|
|
||
|
// Hit
|
||
|
bool hit; // Did we hit anything?
|
||
|
float3 hit_position; // If so, where?
|
||
|
float4 hit_color; // What color does it have?
|
||
|
float3 hit_normal; // And what is the normal for that hit?
|
||
|
float hit_depth;
|
||
|
};
|
||
|
|
||
|
void ray_data_constructor(out ray_data ray)
|
||
|
{
|
||
|
ray.position = float3(0., 0., 0.);
|
||
|
ray.direction = float3(0., 0., 0.);
|
||
|
ray.depth = 0;
|
||
|
|
||
|
ray.hit = false;
|
||
|
ray.hit_position = float3(0., 0., 0.);
|
||
|
ray.hit_color = float4(0., 0., 0., 0.);
|
||
|
ray.hit_normal = float3(0., 0., 0.);
|
||
|
ray.hit_depth = 0.;
|
||
|
}
|
||
|
|
||
|
float get_view_aspect_ratio() {
|
||
|
return ViewSize.x / ViewSize.y;
|
||
|
}
|
||
|
|
||
|
float get_raymarch_step_length() {
|
||
|
return CameraRange.y / float(RayMarchAccuracy);
|
||
|
}
|
||
|
|
||
|
ray_data initialize_camera_ray(float2 uv) {
|
||
|
ray_data ray;
|
||
|
ray_data_constructor(ray);
|
||
|
|
||
|
uv -= .5;
|
||
|
//uv *= 2.;
|
||
|
|
||
|
float aspect = get_view_aspect_ratio();
|
||
|
|
||
|
#ifdef CAMERA_ORTHOGRAPHIC
|
||
|
ray.direction = rotate_float3(float3(0., 0., 1.), CameraRotation);
|
||
|
ray.position = CameraPosition + float3(uv.x * ViewSize.x, uv.y * ViewSize.y, CameraRange.x);
|
||
|
#else
|
||
|
ray.direction = rotate_float3(rotate_float3(float3(0., 0., 1.), CameraRotation), float3(
|
||
|
uv.y * CameraFieldOfView / aspect,
|
||
|
uv.x * CameraFieldOfView,
|
||
|
0.));
|
||
|
ray.position = CameraPosition + float3(-uv.x, uv.y / aspect, CameraRange.x);
|
||
|
#endif
|
||
|
ray.direction *= get_raymarch_step_length();
|
||
|
|
||
|
return ray;
|
||
|
}
|
||
|
|
||
|
bool raymarch_box(inout ray_data ray, float3 pos, float3 rotation, float3 size, material_data material) {
|
||
|
float step = 0.;
|
||
|
if (!intersect_box(pos, size, ray.position, ray.direction, step))
|
||
|
return false;
|
||
|
|
||
|
// if (step > 1.)
|
||
|
// return false;
|
||
|
|
||
|
float depth = (step + float(ray.depth));
|
||
|
// if (ray.hit && (ray.hit_depth <= depth))
|
||
|
// return false;
|
||
|
|
||
|
ray.hit = true;
|
||
|
ray.hit_position = ray.position + ray.direction * step;
|
||
|
ray.hit_depth = depth;
|
||
|
ray.hit_color = material.color;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool raymarch_sphere(inout ray_data ray, float3 pos, float3 rotation, float radius, material_data material) {
|
||
|
float step = 0.;
|
||
|
if (!intersect_sphere(pos, radius, ray.position, ray.direction, step))
|
||
|
return false;
|
||
|
|
||
|
if (step > 1.) // Ray start to end actually did not hit.
|
||
|
return false;
|
||
|
|
||
|
float depth = (step + float(ray.depth));
|
||
|
if (ray.hit && (ray.hit_depth <= depth))
|
||
|
return false;
|
||
|
|
||
|
ray.hit = true;
|
||
|
ray.hit_position = ray.position + ray.direction * step;
|
||
|
ray.hit_depth = depth;
|
||
|
ray.hit_color = material.color;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool scene(inout ray_data ray) {
|
||
|
material_data box1;
|
||
|
material_data_constructor(box1);
|
||
|
box1.color = float4(0., 0., 0., 1.);
|
||
|
raymarch_box(ray, float3(0., -1., 2.), float3(0., 0., 0.), float3(1., 1., 1.), box1);
|
||
|
|
||
|
material_data sphere1;
|
||
|
material_data_constructor(sphere1);
|
||
|
sphere1.color = float4(1., 0., 0., 1.);
|
||
|
raymarch_sphere(ray, float3(-1., 0., 1.), float3(0., 0., 0.), 0.5, sphere1);
|
||
|
|
||
|
material_data sphere2;
|
||
|
material_data_constructor(sphere2);
|
||
|
sphere2.color = float4(0., 0., 1., 1.);
|
||
|
raymarch_sphere(ray, float3(1., 0., 1.), float3(0., 0., 0.), 0.5, sphere2);
|
||
|
|
||
|
return ray.hit;
|
||
|
}
|
||
|
|
||
|
bool raymarch(inout ray_data ray) {
|
||
|
// Simulate hitting a sphere.
|
||
|
if (ray.depth >= RayMarchAccuracy) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
for (; (ray.depth < MAX_ACCURACY) && (ray.depth < RayMarchAccuracy); ray.depth++) {
|
||
|
if (scene(ray))
|
||
|
break;
|
||
|
|
||
|
ray.position = ray.position + ray.direction;
|
||
|
}
|
||
|
|
||
|
return ray.hit;
|
||
|
}
|
||
|
|
||
|
float4 pass1_ps(default_data data) : TARGET {
|
||
|
// Set up camera.
|
||
|
ray_data ray = initialize_camera_ray(data.uv);
|
||
|
// Raymarch
|
||
|
raymarch(ray);
|
||
|
// Finally just return the color
|
||
|
//return float4(ray.hit_depth / float(CameraRange.y), float(ray.depth) / float(RayMarchAccuracy), 0., 1.);
|
||
|
return ray.hit_color;
|
||
|
}
|
||
|
|
||
|
//----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
|
||
|
technique Draw {
|
||
|
pass
|
||
|
{
|
||
|
vertex_shader = default_vs(data);
|
||
|
pixel_shader = pass1_ps(data);
|
||
|
}
|
||
|
}
|