obs-StreamFX/data/examples/shaders/source/3d-sphere.effect

372 lines
9.3 KiB
Plaintext

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);
}
}