372 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			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); 
 | |
| 	}
 | |
| } |