Commit df9f43a3 authored by Johannes Braun's avatar Johannes Braun
Browse files

Removed PT color storage texture and made just about everything dispatch-local.

parent 89cbb3b2
......@@ -20,10 +20,6 @@ uniform struct
bool u_random_subpixel; //defaults to false.
} settings;
void generate(int id, ivec2 pixels);
void trace(int id);
void resetImportance(int id);
void main()
{
ivec2 target_size = u_render_target.imageSize();
......@@ -31,26 +27,9 @@ void main()
return;
int id = target_size.x * int(gl_GlobalInvocationID.y) + int(gl_GlobalInvocationID.x);
generate(id, target_size);
trace(id);
resetImportance(id);
}
void generate(int id, ivec2 pixels)
{
traces_data[id].ray = u_camera.getRayFromPixel(vec2(gl_GlobalInvocationID.xy), settings.u_random_subpixel ? vec2(0, 0) : rand2D(random_seed + id, pixels.x*pixels.y), vec2(pixels));
}
void trace(int id)
{
vec2 random = settings.u_random_subpixel ? vec2(0, 0) : rand2D(random_seed + id, target_size.x*target_size.y);
traces_data[id].ray = u_camera.getRayFromPixel(vec2(gl_GlobalInvocationID.xy), random, vec2(target_size));
traces_data[id].hit.invalidate();
bool intersects = nearestIntersection(traces_data[id].ray, traces_data[id].hit, true);
}
void resetImportance(int id)
{
traces_data[id].properties.accuracy_importance = 1.f;
traces_data[id].properties.shadow_importance = 1.f;
traces_data[id].properties.bounce_amount = 0;
traces_data[id].properties.travelled_distance = 0;
bool intersects = traces_data[id].ray.nearestIntersection(traces_data[id].hit, true);
}
......@@ -43,24 +43,43 @@ uniform struct
float distance_threshold;
} u_linespace_properties;
uint getBounceAmount(const in Trace trace, uint id)
struct LightData
{
return (trace.properties.bounce_amount >> (8*id)) & 0xFF;
}
bool sample_succeeded;
Ray shadow_test;
vec3 point_on_light;
vec3 light_color;
float testing_distance;
};
void addBounceAmount(inout Trace trace, uint id, uint amount)
struct Bounce
{
trace.properties.bounce_amount += (amount & 0xFF) << (8*id);
}
Hit hit;
Ray ray;
vec3 color;
vec3 radiance;
//Threshold properties
float path_distance;
float accuracy_importance;
float shadow_importance;
uint getLSBounceThreshold(uint id)
uint bounce_amount;
int count;
int bsdf_id;
};
uint getPart(uint base, uint index)
{
return (u_linespace_properties.bounce_thresholds >> (8*id)) & 0xFF;
return (base >> (8 * index)) & 0xFF;
}
uint getBounceThreshold(uint id)
void addToPart(inout uint base, uint index, uint amount)
{
return (u_render_config.bounce_thresholds >> (8*id)) & 0xFF;
base += (amount & 0xFF) << (8 * index);
}
//////////////////////////////////////////////////////////////////////////
......@@ -69,26 +88,21 @@ uint getBounceThreshold(uint id)
////
//////////////////////////////////////////////////////////////////////////
void writeRenderTarget(int id, vec4 color)
LightData sampleLight(const in Light light, const in Vertex vertex, const in vec2 random_sample)
{
Trace trace = traces_data[id];
u_render_target.imageStore(ivec2(trace.ray.px, trace.ray.py), vec4(color.rgb, 1));
LightData result;
result.sample_succeeded = u_light_sample[light.type % 4](light, vertex.position.xyz, result.point_on_light, result.light_color, random_sample);
vec3 non_normal_direction = result.point_on_light - vertex.position.xyz;
result.shadow_test.direction = normalize(non_normal_direction);
result.shadow_test.origin = vertex.position.xyz + 1e-2f * vertex.normal.xyz;
return result;
}
void writeColorStore(const in Ray ray, const in vec3 rgb_color, float clamp_color)
bool shouldUseBvh(const in Bounce bounce)
{
u_color_store.imageAdd(ivec2(ray.px, ray.py), vec4(rgb_color.clamp(0, clamp_color), 1));
}
vec4 loadColorStore(int id)
{
Trace trace = traces_data[id];
return u_color_store.imageLoad(ivec2(trace.ray.px, trace.ray.py));
}
bool sampleLight(const in Light light, const in vec3 position, out vec3 point_on_light, out vec3 color, const in vec2 random_sample)
{
return u_light_sample[light.type % 4](light, position, point_on_light, color, random_sample);
return (bounce.shadow_importance > (1-u_linespace_properties.shadow_quality))
&& (bounce.bounce_amount.getPart(bounce.bsdf_id) < u_linespace_properties.bounce_thresholds.getPart(bounce.bsdf_id))
&& bounce.path_distance < u_linespace_properties.distance_threshold;
}
//////////////////////////////////////////////////////////////////////////
......@@ -97,96 +111,77 @@ bool sampleLight(const in Light light, const in vec3 position, out vec3 point_on
////
//////////////////////////////////////////////////////////////////////////
bool shade(int id, inout vec3 radiance, uint bounce, out uint bsdf_id)
bool shade(inout Bounce bounce)
{
Trace trace = traces_data[id];
Hit hit = trace.hit;
Ray ray = trace.ray;
float clamp_color_max = mix(u_render_config.clamp_direct, u_render_config.clamp_indirect, bounce.clamp(0.f, 1.f));
float clamp_color_max = mix(u_render_config.clamp_direct, u_render_config.clamp_indirect, bounce.count.clamp(0.f, 1.f));
//Sample environment when not hitting anything.
if(!hit.valid())
if(!bounce.hit.valid())
{
writeColorStore(ray, radiance * u_environment.sampleColor(ray.direction.xyz).rgb, clamp_color_max);
vec3 environment = bounce.radiance * u_environment.sampleColor(bounce.ray.direction.xyz).rgb;
bounce.color += clamp(environment, 0, clamp_color_max);
return false;
}
//Get Hit data
Mesh mesh = meshes_data[hit.mesh];
Vertex vertex = mesh.getVertex(hit);
Mesh mesh = meshes_data[bounce.hit.mesh];
Vertex vertex = mesh.getVertex(bounce.hit);
Material material = materials_data[mesh.material];
traces_data[id].properties.travelled_distance += traces_data[id].hit.valid() ? (distance(traces_data[id].ray.origin, vertex.position.xyz)) : FLT_MAX;
bounce.path_distance += distance(bounce.ray.origin, vertex.position.xyz);
// generate a random sample on each bounce so there won't be any notifiable patterns
const vec2 base_random = vec2(ray.px, ray.py) - ivec2(floor(ray.px), floor(ray.py));
const vec2 base_random = vec2(bounce.ray.px, bounce.ray.py) - ivec2(floor(bounce.ray.px), floor(bounce.ray.py));
const ivec2 img_size = u_render_target.imageSize();
const int img_dimen = img_size.x * img_size.y;
vec2 random_sample = rand2D((random_seed + int(id))%img_dimen, img_size.x * img_size.y);
vec2 random_sample = rand2D((random_seed + int(gl_GlobalInvocationID.y * uint(img_size.x) + gl_GlobalInvocationID.x))%img_dimen, img_size.x * img_size.y);
BSDFResult bsdf_result = material.computeBSDF(random_sample, vertex, ray);
BSDFResult bsdf_result = material.computeBSDF(random_sample, vertex, bounce.ray);
traces_data[id].addBounceAmount(bsdf_result.bsdf_id, 1);
if(traces_data[id].getBounceAmount(bsdf_result.bsdf_id) > getBounceThreshold(bsdf_result.bsdf_id))
bounce.bsdf_id = int(bsdf_result.bsdf_id);
bounce.bounce_amount.addToPart(bsdf_result.bsdf_id, 1);
if(bounce.bounce_amount.getPart(bsdf_result.bsdf_id) > u_render_config.bounce_thresholds.getPart(bsdf_result.bsdf_id))
{
traces_data[id].hit.invalidate();
return false;
return bounce.hit.invalidate();
}
if(bsdf_result.bsdf_id == eEmit)
{
writeColorStore(ray, radiance * bsdf_result.radiance, clamp_color_max);
traces_data[id].hit.invalidate();
return false;
bounce.color += clamp(bounce.radiance * bsdf_result.radiance, 0, clamp_color_max);
return bounce.hit.invalidate();
}
bool use_bvh = (trace.properties.shadow_importance > (1-u_linespace_properties.shadow_quality))
&& (traces_data[id].getBounceAmount(bsdf_result.bsdf_id) < getLSBounceThreshold(bsdf_result.bsdf_id))
&& traces_data[id].properties.travelled_distance < u_linespace_properties.distance_threshold;
if (lights_data.length() > 0) {
//Select random light.
Light light = lights_data[int(floor(random_sample.x * lights_data.length()))];
vec3 point_on_light;
vec3 light_color;
bool success = sampleLight(light, vertex.position.xyz, point_on_light, light_color, random_sample);
vec3 non_normal_direction = point_on_light - vertex.position.xyz;
Ray shadow_test;
shadow_test.direction = normalize(non_normal_direction);
shadow_test.origin = vertex.position.xyz + 1e-2f * vertex.normal.xyz;
if (success && !shadow_test.intersectsAny(length(non_normal_direction), use_bvh))
//And sample it.
LightData data = light.sampleLight(vertex, random_sample);
if (data.sample_succeeded && !data.shadow_test.intersectsAny(data.testing_distance, shouldUseBvh(bounce)))
{
writeColorStore(ray, light_color * bsdf_result.evaluation * radiance * max(dot(vertex.normal.xyz, normalize(shadow_test.direction)), 0.f), clamp_color_max);
vec3 lighting = data.light_color * bsdf_result.evaluation * bounce.radiance * max(dot(vertex.normal.xyz, normalize(data.shadow_test.direction)), 0.f);
bounce.color += clamp(lighting, 0, clamp_color_max);
}
}
//Quit if bounces won't be of any use due to low contributions
if (bsdf_result.radiance == vec3(0) || bsdf_result.probability_density <= 1e-5f)
{
traces_data[id].hit.invalidate();
return false;
return bounce.hit.invalidate();
}
traces_data[id].properties.accuracy_importance *= bsdf_result.probability_density;
traces_data[id].properties.shadow_importance *= bsdf_result.probability_density;
traces_data[id].ray = bsdf_result.generated_ray;
radiance *= clamp(bsdf_result.radiance * angle(bsdf_result.generated_ray, vertex) / bsdf_result.probability_density, 0, 1);//
bounce.accuracy_importance *= bsdf_result.probability_density;
bounce.shadow_importance *= bsdf_result.probability_density;
bounce.ray = bsdf_result.generated_ray;
bounce.radiance *= clamp(bsdf_result.radiance * angle(bsdf_result.generated_ray, vertex) / bsdf_result.probability_density, 0, 1);
return true;
}
bool trace(int id, uint last_bsdf_id)
void trace(inout Bounce bounce)
{
//Invalidate before intersection test so that we don't have to conditionally invalidate afterwards
traces_data[id].hit.invalidate();
//Use a BVH if accuracy is important
bool use_bvh = (traces_data[id].properties.accuracy_importance > (1-u_linespace_properties.accuracy_quality))
&& (traces_data[id].getBounceAmount(last_bsdf_id) < getLSBounceThreshold(last_bsdf_id))
&& traces_data[id].properties.travelled_distance < u_linespace_properties.distance_threshold;
bool intersects = traces_data[id].ray.nearestIntersection(traces_data[id].hit, use_bvh);
return intersects;
bounce.hit.invalidate();
bounce.ray.nearestIntersection(bounce.hit, shouldUseBvh(bounce));
}
void main()
......@@ -198,19 +193,33 @@ void main()
if (!(int(gl_GlobalInvocationID.x) < target_size.x && int(gl_GlobalInvocationID.y) < target_size.y))
return;
//Initial radiance weight.
vec3 radiance = vec3(1);
//Shade the primary ray hit which was generated by the RayGenerator before the render dispatch call.
uint last_bsdf_id;
bool success = shade(id, radiance, 0, last_bsdf_id);
//Then shade all valid hits as long as they bounce around happily in the scene.
for (int bounce = 0; bounce < u_render_config.num_bounces && success; ++bounce) {
success = trace(id, last_bsdf_id);
success = bool(uint(success) & uint(shade(id, radiance, bounce + 1, last_bsdf_id)));
// Get the trace generated by the external primary-ray-generator and initialize the Bounce struct.
Trace current = traces_data[id];
Bounce bounce;
bounce.hit = current.hit;
bounce.ray = current.ray;
//Threshold properties
bounce.path_distance = 0;
bounce.accuracy_importance = 1.f;
bounce.shadow_importance = 1.f;
bounce.bounce_amount = 0;
bounce.color = vec3(0);
bounce.radiance = vec3(1);
// Nifty for-loop trick. :P
// Will execute the bounce.shade() method at the very beginning (to shade the primary ray) and then
// continue with first-trace-then-shade until either shade returns false (not hitting something or constribution too low)
// or we exceed the global bounce limit.
for (bounce.count = 1; bounce.shade() && bounce.count <= u_render_config.num_bounces; ++bounce.count) {
bounce.trace();
}
//Divide color storage by sample count to retrieve the final color.
writeRenderTarget(id, loadColorStore(id) / (u_render_config.current_sample + 1));
ivec2 pixel = ivec2(bounce.ray.px, bounce.ray.py);
vec4 color = u_render_target.imageLoad(pixel);
// Divide color storage by sample count to retrieve the final color.
// A float type render target should provide enough precision to not need a secondary color storage.
color = mix(color, vec4(bounce.color, 1), 1 / float(u_render_config.current_sample + 1));
u_render_target.imageStore(pixel, color);
}
......@@ -35,14 +35,14 @@ struct Hit
/*
@bytesize 16
*/
struct TraceProperties
{
float accuracy_importance;
float shadow_importance;
uint bounce_amount;
float travelled_distance;
};
// struct TraceProperties
// {
// float accuracy_importance;
// float shadow_importance;
//
// uint bounce_amount;
// float travelled_distance;
// };
/*
@bytesize 64
......@@ -53,7 +53,7 @@ struct Trace
Hit hit;
//Additional properties for BVH-LS-Hybrid
TraceProperties properties;
//TraceProperties properties;
};
......@@ -78,7 +78,7 @@ Ray makeRelative(const in Ray ray, const in Mesh mesh)
bool valid(const in Hit hit) { return hit.barycentric.x != -1; }
void invalidate(inout Hit hit) { hit.barycentric.x = -1; }
bool invalidate(inout Hit hit) { hit.barycentric.x = -1; return false; }
#define hit__getFromBarycentric(barycentric, triangle, param) (barycentric.x * v1.param + \
barycentric.y * v2.param + \
......
......@@ -25,7 +25,7 @@ namespace glare::core
gl::getProgramInfoLog(m_handle, log_length, &log_length, &log[0]);
Log_Error << log;
Log_Error << "Shader compiled successfully.";
Log_Error << "Error linking the program.";
for (const auto &shader : shaders)
gl::detachShader(m_handle, shader->id());
......
......@@ -25,7 +25,6 @@ namespace glare::raytrace
core::Context::current().messages()->addObserver(this, tags::scene);
m_render_target = std::make_unique<core::Texture>(core::Texture::Target::e2D, core::Texture::StoreFormat::eRGBA32Float);
m_color_storage = std::make_unique<core::Texture>(core::Texture::Target::e2D, core::Texture::StoreFormat::eRGBA32Float);
if (collector)
initialize(collector);
......@@ -98,10 +97,8 @@ namespace glare::raytrace
m_trace_buffer.reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
m_render_target = std::make_unique<core::Texture>(core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
m_color_storage = std::make_unique<core::Texture>(core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
m_render_shader->uniform("u_render_target", m_render_target->imageAddress(gl::Access::eReadWrite));
m_render_shader->uniform("u_color_store", m_color_storage->imageAddress(gl::Access::eReadWrite));
m_render_shader->storageBuffer("trace_buffer", m_trace_buffer);
m_samples_current = 0;
......@@ -110,7 +107,6 @@ namespace glare::raytrace
if (m_samples_current == 0)
{
m_collector->collect();
m_color_storage->clear(0);
}
for (unsigned sample = 0; sample < m_samples_per_frame; sample++) {
......
......@@ -120,7 +120,6 @@ namespace glare::raytrace
std::unique_ptr<core::Program> m_render_shader;
std::unique_ptr<core::Texture> m_render_target;
std::unique_ptr<core::Texture> m_color_storage;
core::Buffer m_trace_buffer;
std::shared_ptr<SceneCollector> m_collector;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment