Explorar el Código

Add shader file

luboslenco hace 6 años
padre
commit
ccdaab8e78
Se han modificado 3 ficheros con 287 adiciones y 4 borrados
  1. 0 4
      Assets/raytrace/build.md
  2. 287 0
      Assets/raytrace/raytrace.hlsl
  3. BIN
      Bundled/raytrace/raytrace.cso

+ 0 - 4
Assets/raytrace/build.md

@@ -1,5 +1 @@
-Build:
-`node Kinc/make -g direct3d12 --raytrace dxr`
-
-Compile shader:
 `.\dxc.exe -Zpr -Fo ..\..\Bundled\raytrace\raytrace.cso -T lib_6_3 .\raytrace.hlsl`

+ 287 - 0
Assets/raytrace/raytrace.hlsl

@@ -0,0 +1,287 @@
+
+struct Vertex {
+	float3 position;
+	float3 normal;
+	float2 tex;
+};
+
+struct RayGenConstantBuffer {
+	float4 eye; // xyz, frame
+	float4x4 inv_vp;
+};
+
+struct RayPayload {
+	float4 color;
+	float3 ray_origin;
+	float3 ray_dir;
+};
+
+RWTexture2D<float4> render_target : register(u0);
+RaytracingAccelerationStructure scene : register(t0);
+ByteAddressBuffer indices : register(t1);
+StructuredBuffer<Vertex> vertices : register(t2);
+ConstantBuffer<RayGenConstantBuffer> constant_buffer : register(b0);
+
+Texture2D<float4> mytexture0 : register(t3);
+Texture2D<float4> mytexture1 : register(t4);
+Texture2D<float4> mytexture2 : register(t5);
+Texture2D<float4> mytexture_env : register(t6);
+
+static uint seed;
+static const float PI = 3.1415926535f;
+
+void create_basis(float3 normal, out float3 tangent, out float3 binormal) {
+	tangent = abs(normal.x) > abs(normal.y) ?
+		normalize(float3(0., normal.z, -normal.y)) :
+		normalize(float3(-normal.z, 0., normal.x));
+	binormal = cross(normal, tangent);
+}
+
+uint wang_hash(uint seed) {
+	seed = (seed ^ 61) ^ (seed >> 16);
+	seed *= 9;
+	seed = seed ^ (seed >> 4);
+	seed *= 0x27d4eb2d;
+	seed = seed ^ (seed >> 15);
+	return seed;
+}
+
+void compute_seed(uint index, uint iteration, uint depth) {
+	seed = uint(wang_hash((1 << 31) | (depth << 22) | iteration) ^ wang_hash(index));
+}
+
+float rand() {
+	static const float png_01_convert = (1.0f / 4294967296.0f);
+	seed ^= uint(seed << 13);
+	seed ^= uint(seed >> 17);
+	seed ^= uint(seed << 5);
+	return float(seed * png_01_convert);
+}
+
+float schlick(float cosine, float ri) {
+	float r0 = (1 - ri) / (1 + ri);
+	r0 = r0 * r0;
+	return r0 + (1 - r0) * pow(saturate(1 - cosine), 5);
+}
+
+float schlick_weight(float cosTheta) {
+	float m = clamp(1. - cosTheta, 0., 1.);
+	float m2 = m * m;
+	return m2 * m2 * m;
+}
+
+float2 calculate_concentric_sample_disk(float u, float v) {
+	// Maps a (u,v) in [0, 1)^2 to a 2D unit disk centered at (0,0). Based on PBRT.
+	float2 u_offset = 2.0f * float2(u, v) - float2(1, 1);
+	if (u_offset.x == 0 && u_offset.y == 0) {
+		return float2(0.0f, 0.0f);
+	}
+	float theta, r;
+	if (abs(u_offset.x) > abs(u_offset.y)) {
+		r = u_offset.x;
+		theta = PI / 4 * (u_offset.y / u_offset.x);
+	}
+	else {
+		r = u_offset.y;
+		theta = (PI / 2) - (PI / 4 * (u_offset.x / u_offset.y));
+	}
+	return r * float2(cos(theta), sin(theta));
+}
+
+void generate_camera_ray(float2 screen_pos, out float3 ray_origin, out float3 ray_dir) {
+	screen_pos.y = -screen_pos.y;
+	float4 world = mul(float4(screen_pos, 0, 1), constant_buffer.inv_vp);
+	world.xyz /= world.w;
+	ray_origin = constant_buffer.eye.xyz;
+	ray_dir = normalize(world.xyz - ray_origin);
+
+	// Depth of Field
+	// float lens_rad = 0.005f;
+	// float focal_dist = 0.4f;
+	// float3 plens = float3(lens_rad * calculate_concentric_sample_disk(rand(), rand()), 0.0f);
+	// float ft = focal_dist / abs(ray_dir.z);
+	// float3 pfocus = ray_dir * ft;
+	// ray_origin += plens;
+	// ray_dir = normalize(pfocus - plens);
+}
+
+[shader("raygeneration")]
+void raygeneration() {
+	uint2 sample_point = DispatchRaysIndex().xy;
+	uint2 sample_dim = DispatchRaysDimensions().xy;
+	uint id = sample_point.x + sample_dim.x * sample_point.y;
+	const int depth = 5;
+	compute_seed(id, constant_buffer.eye.w, depth);
+
+	float2 xy = DispatchRaysIndex().xy + 0.5f;
+	xy.x += rand(); // AA
+	xy.y += rand();
+	float2 screen_pos = xy / DispatchRaysDimensions().xy * 2.0 - 1.0;
+
+	RayPayload payload;
+	payload.color = float4(1, 1, 1, -1);
+	generate_camera_ray(screen_pos, payload.ray_origin, payload.ray_dir);
+
+	RayDesc ray;
+	ray.TMin = 0.01;
+	ray.TMax = 10.0;
+	ray.Origin = payload.ray_origin;
+	ray.Direction = payload.ray_dir;
+	
+	for (int i = 0; i < depth; ++i) {
+		TraceRay(scene, RAY_FLAG_FORCE_OPAQUE, ~0, 0, 1, 0, ray, payload);
+		compute_seed(id, constant_buffer.eye.w, i);
+
+		if (payload.color.a != 0) break;
+		ray.Origin = payload.ray_origin;
+		ray.Direction = payload.ray_dir;
+	}
+
+	float3 color = float3(render_target[DispatchRaysIndex().xy].xyz);
+	if (constant_buffer.eye.w == 1.0) color = float3(0, 0, 0);
+	float a = 1.0 / constant_buffer.eye.w;
+	float b = 1.0 - a;
+
+	color = color * b + payload.color.xyz * a;
+	render_target[DispatchRaysIndex().xy] = float4(color.xyz, 0.0f);
+}
+
+float3 hit_world_position() {
+	return WorldRayOrigin() + RayTCurrent() * WorldRayDirection();
+}
+
+float3 hit_attribute(float3 vertexAttribute[3], BuiltInTriangleIntersectionAttributes attr) {
+	return vertexAttribute[0] +
+		attr.barycentrics.x * (vertexAttribute[1] - vertexAttribute[0]) +
+		attr.barycentrics.y * (vertexAttribute[2] - vertexAttribute[0]);
+}
+
+float2 hit_attribute2d(float2 vertexAttribute[3], BuiltInTriangleIntersectionAttributes attr) {
+	return vertexAttribute[0] +
+		attr.barycentrics.x * (vertexAttribute[1] - vertexAttribute[0]) +
+		attr.barycentrics.y * (vertexAttribute[2] - vertexAttribute[0]);
+}
+
+float3 cos_weighted_random_hemisphere_direction(float3 n) {
+	float2 r = float2(rand(), rand());
+	float3 uu = normalize(cross(n, float3(0.0, 1.0, 1.0)));
+	float3 vv = cross(uu, n);
+	float ra = sqrt(r.y);
+	float rx = ra * cos(6.2831 * r.x); 
+	float ry = ra * sin(6.2831 * r.x);
+	float rz = sqrt(1.0 - r.y);
+	float3 rr = float3(rx * uu + ry * vv + rz * n);
+	return normalize(rr);
+}
+
+[shader("closesthit")]
+void closesthit(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) {
+	uint2 sample_point = DispatchRaysIndex().xy;
+	uint2 sample_dim = DispatchRaysDimensions().xy;
+	uint id = sample_point.x + sample_dim.x * sample_point.y;
+	compute_seed(id, constant_buffer.eye.w, 0);
+
+	float3 hit_position = hit_world_position();
+
+	const uint triangleIndexStride = 12; // 3 * 4
+	uint base_index = PrimitiveIndex() * triangleIndexStride;
+	uint3 indices_sample = indices.Load3(base_index);
+
+	float3 vertex_normals[3] = { 
+		float3(vertices[indices_sample[0]].normal),
+		float3(vertices[indices_sample[1]].normal),
+		float3(vertices[indices_sample[2]].normal)
+	};
+	float3 n = normalize(hit_attribute(vertex_normals, attr));
+
+	float2 vertex_uvs[3] = { 
+		float2(vertices[indices_sample[0]].tex),
+		float2(vertices[indices_sample[1]].tex),
+		float2(vertices[indices_sample[2]].tex)
+	};
+	float2 tex_coord = hit_attribute2d(vertex_uvs, attr);
+
+	float emittance = 0.0;
+	float3 texpaint0 = mytexture0.Load(uint3(tex_coord * 2048, 0)).rgb;
+	float3 texpaint1 = mytexture1.Load(uint3(tex_coord * 2048, 0)).rgb;
+	float3 texpaint2 = mytexture2.Load(uint3(tex_coord * 2048, 0)).rgb;
+	if (hit_position.z > 0.99) {
+		emittance = 1.0;
+		texpaint0 = float3(5, 5, 5); // temp
+	}
+	float3 color = payload.color.rgb * texpaint0.rgb;
+	
+	if (emittance == 0.0f) {
+		if (texpaint2.b >= 0.99) {
+			payload.ray_dir = lerp(reflect(WorldRayDirection(), n), cos_weighted_random_hemisphere_direction(n), texpaint2.g);
+		}
+		// else if (texpaint2.matid == glass) {
+		// 	float indexOfRefraction = 1.0f;
+		// 	// adjust eta & normal according to direction of ray (inside or outside mat)
+		// 	bool inside = dot(WorldRayDirection(), n) > 0.f;
+		// 	float3 tempNormal = n * (inside ? -1.0f : 1.0f);
+		// 	float eta = inside ? indexOfRefraction : (1.0f / indexOfRefraction);
+		// 	// normal refraction
+		// 	float3 newDir = refract(WorldRayDirection(), tempNormal, eta);
+		// 	// internal total reflection
+		// 	if (length(newDir) < 0.01f) {
+		// 		color *= 0;
+		// 		newDir = reflect(WorldRayDirection(), n);
+		// 	}
+		// 	// use schlick's approx
+		// 	float schlick_0 = pow((inside ? indexOfRefraction - 1.0f : 1.0f - indexOfRefraction) /
+		// 		(1.0f + indexOfRefraction), 2.0f);
+		// 	float schlick_coef = schlick_0 +
+		// 		(1 - schlick_0) * pow(1 - max(0.0f, dot(WorldRayDirection(), n)), 5);
+		// 	// based on coef, pick either a refraction or reflection
+		// 	newDir = schlick_coef < rand() ? reflect(WorldRayDirection(), n) : newDir;
+		// 	payload.ray_dir = newDir;
+		// }
+		else {
+			// TEMP
+			float fresnel = schlick(dot(n, payload.ray_dir), 1.35) * (1.0 - texpaint2.g);
+			if (rand() > fresnel) {
+				payload.ray_dir = cos_weighted_random_hemisphere_direction(n);
+
+				// float3 wo = -payload.ray_dir;
+				// payload.ray_dir = cos_weighted_random_hemisphere_direction(n);
+				// float3 tangent = float3(0, 0, 0);
+				// float3 binormal = float3(0, 0, 0);
+				// create_basis(n, tangent, binormal);
+				// float3 wi = payload.ray_dir.x * tangent + payload.ray_dir.y * binormal + payload.ray_dir.z * n;
+				// float dotNL = dot(n, wo);
+				// float dotNV = dot(n, wi);
+				// float3 H = normalize(wo + wi);
+				// float dotLH = dot(wo, H);
+				// float FL = schlick_weight(dotNL);
+				// float FV = schlick_weight(dotNV);
+				// float Fss90 = dotLH * dotLH * texpaint2.g;
+				// float Fss = lerp(1.0, Fss90, FL) * lerp(1.0, Fss90, FV);
+				// float ss = 1.25 * (Fss * (1.0 / (dotNL + dotNV) - 0.5) + 0.5);
+				// color = (1 / PI) * ss * color;
+				// if (dotNL < 0.0 || dotNV < 0.0) color = float3(0, 0, 0);
+			}
+			else {
+				payload.ray_dir = reflect(WorldRayDirection(), n);
+			}
+		}
+		payload.ray_origin = hit_position + payload.ray_dir * 0.0001f;
+	}
+
+	payload.color = float4(color.xyz, emittance);
+}
+
+float2 equirect(float3 normal) {
+	const float PI = 3.1415926535;
+	const float PI2 = PI * 2.0;
+	float phi = acos(normal.z);
+	float theta = atan2(-normal.y, normal.x) + PI;
+	return float2(theta / PI2, phi / PI);
+}
+
+[shader("miss")]
+void miss(inout RayPayload payload) {
+	float2 tex_coord = equirect(normalize(payload.ray_dir));
+	float3 texenv = mytexture_env.Load(uint3(tex_coord.x * 1024, tex_coord.y * 512, 0)).rgb * 3;
+	payload.color = float4(payload.color.rgb * texenv.rgb, -1);
+}

BIN
Bundled/raytrace/raytrace.cso