diff options
Diffstat (limited to 'intern')
22 files changed, 302 insertions, 188 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 6d28c14e12a..45d25720aff 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -212,7 +212,7 @@ def enum_denoiser(self, context): items += enum_openimagedenoise_denoiser(self, context) return items -enum_denoising_optix_input_passes = ( +enum_denoising_input_passes = ( ('RGB', "Color", "Use only color as input", 1), ('RGB_ALBEDO', "Color + Albedo", "Use color and albedo data as input", 2), ('RGB_ALBEDO_NORMAL', "Color + Albedo + Normal", "Use color, albedo and normal data as input", 3), @@ -1451,11 +1451,18 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup): denoising_optix_input_passes: EnumProperty( name="Input Passes", - description="Passes handed over to the OptiX denoiser (this can have different effects on the denoised image)", - items=enum_denoising_optix_input_passes, + description="Passes used by the denoiser to distinguish noise from shader and geometry detail", + items=enum_denoising_input_passes, default='RGB_ALBEDO', ) + denoising_openimagedenoise_input_passes: EnumProperty( + name="Input Passes", + description="Passes used by the denoiser to distinguish noise from shader and geometry detail", + items=enum_denoising_input_passes, + default='RGB_ALBEDO_NORMAL', + ) + use_pass_crypto_object: BoolProperty( name="Cryptomatte Object", description="Render cryptomatte object pass, for isolating objects in compositing", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 3d0b2f721b4..03b1675c309 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1008,6 +1008,7 @@ class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel): col.prop(cycles_view_layer, "denoising_optix_input_passes") return elif denoiser == 'OPENIMAGEDENOISE': + col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes") return col.prop(cycles_view_layer, "denoising_radius", text="Radius") diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 19d2730dc93..33e73b5a4b9 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -815,9 +815,10 @@ static ShaderNode *add_node(Scene *scene, sky->ground_albedo = b_sky_node.ground_albedo(); sky->sun_disc = b_sky_node.sun_disc(); sky->sun_size = b_sky_node.sun_size(); + sky->sun_intensity = b_sky_node.sun_intensity(); sky->sun_elevation = b_sky_node.sun_elevation(); sky->sun_rotation = b_sky_node.sun_rotation(); - sky->altitude = b_sky_node.altitude(); + sky->altitude = 1000.0f * b_sky_node.altitude(); sky->air_density = b_sky_node.air_density(); sky->dust_density = b_sky_node.dust_density(); sky->ozone_density = b_sky_node.ozone_density(); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index ee2445e44c4..d509f2fc786 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -954,7 +954,13 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene, denoising.strength = get_float(clayer, "denoising_strength"); denoising.feature_strength = get_float(clayer, "denoising_feature_strength"); denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca"); - denoising.optix_input_passes = get_enum(clayer, "denoising_optix_input_passes"); + + denoising.input_passes = (DenoiserInput)get_enum( + clayer, + (denoising.type == DENOISER_OPTIX) ? "denoising_optix_input_passes" : + "denoising_openimagedenoise_input_passes", + DENOISER_INPUT_NUM, + DENOISER_INPUT_RGB_ALBEDO_NORMAL); denoising.store_passes = get_boolean(clayer, "denoising_store_passes"); } diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index af8db5b75b8..ee3a3ddea64 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -951,12 +951,13 @@ class CPUDevice : public Device { void denoise_openimagedenoise_buffer(DeviceTask &task, float *buffer, - size_t offset, - size_t stride, - size_t x, - size_t y, - size_t w, - size_t h) + const size_t offset, + const size_t stride, + const size_t x, + const size_t y, + const size_t w, + const size_t h, + const float scale) { #ifdef WITH_OPENIMAGEDENOISE assert(openimagedenoise_supported()); @@ -982,31 +983,65 @@ class CPUDevice : public Device { } /* Set images with appropriate stride for our interleaved pass storage. */ - const struct { + struct { const char *name; - int offset; - } passes[] = {{"color", task.pass_denoising_data + DENOISING_PASS_COLOR}, - {"normal", task.pass_denoising_data + DENOISING_PASS_NORMAL}, - {"albedo", task.pass_denoising_data + DENOISING_PASS_ALBEDO}, - {"output", 0}, + const int offset; + const bool scale; + const bool use; + array<float> scaled_buffer; + } passes[] = {{"color", task.pass_denoising_data + DENOISING_PASS_COLOR, false, true}, + {"albedo", + task.pass_denoising_data + DENOISING_PASS_ALBEDO, + true, + task.denoising.input_passes >= DENOISER_INPUT_RGB_ALBEDO}, + {"normal", + task.pass_denoising_data + DENOISING_PASS_NORMAL, + true, + task.denoising.input_passes >= DENOISER_INPUT_RGB_ALBEDO_NORMAL}, + {"output", 0, false, true}, { NULL, 0 }}; for (int i = 0; passes[i].name; i++) { + if (!passes[i].use) { + continue; + } + const int64_t pixel_offset = offset + x + y * stride; - const int64_t buffer_offset = (pixel_offset * task.pass_stride + passes[i].offset) * - sizeof(float); - const int64_t pixel_stride = task.pass_stride * sizeof(float); + const int64_t buffer_offset = (pixel_offset * task.pass_stride + passes[i].offset); + const int64_t pixel_stride = task.pass_stride; const int64_t row_stride = stride * pixel_stride; - oidn_filter.setImage(passes[i].name, - (char *)buffer + buffer_offset, - oidn::Format::Float3, - w, - h, - 0, - pixel_stride, - row_stride); + if (passes[i].scale && scale != 1.0f) { + /* Normalize albedo and normal passes as they are scaled by the number of samples. + * For the color passes OIDN will perform auto-exposure making it unnecessary. */ + array<float> &scaled_buffer = passes[i].scaled_buffer; + scaled_buffer.resize(w * h * 3); + + for (int y = 0; y < h; y++) { + const float *pass_row = buffer + buffer_offset + y * row_stride; + float *scaled_row = scaled_buffer.data() + y * w * 3; + + for (int x = 0; x < w; x++) { + scaled_row[x * 3 + 0] = pass_row[x * pixel_stride + 0] * scale; + scaled_row[x * 3 + 1] = pass_row[x * pixel_stride + 1] * scale; + scaled_row[x * 3 + 2] = pass_row[x * pixel_stride + 2] * scale; + } + } + + oidn_filter.setImage( + passes[i].name, scaled_buffer.data(), oidn::Format::Float3, w, h, 0, 0, 0); + } + else { + oidn_filter.setImage(passes[i].name, + buffer + buffer_offset, + oidn::Format::Float3, + w, + h, + 0, + pixel_stride * sizeof(float), + row_stride * sizeof(float)); + } } /* Execute filter. */ @@ -1021,6 +1056,7 @@ class CPUDevice : public Device { (void)y; (void)w; (void)h; + (void)scale; #endif } @@ -1037,7 +1073,8 @@ class CPUDevice : public Device { rtile.x, rtile.y, rtile.w, - rtile.h); + rtile.h, + 1.0f / rtile.sample); /* todo: it may be possible to avoid this copy, but we have to ensure that * when other code copies data from the device it doesn't overwrite the @@ -1047,6 +1084,9 @@ class CPUDevice : public Device { else { /* Per-tile denoising. */ rtile.sample = rtile.start_sample + rtile.num_samples; + const float scale = 1.0f / rtile.sample; + const float invscale = rtile.sample; + const size_t pass_stride = task.pass_stride; /* Map neighboring tiles into one buffer for denoising. */ RenderTileNeighbors neighbors(rtile); @@ -1075,22 +1115,24 @@ class CPUDevice : public Device { const int ymax = min(ntile.y + ntile.h, rect.w); const size_t tile_offset = ntile.offset + xmin + ymin * ntile.stride; - const float *tile_buffer = (float *)ntile.buffer + tile_offset * task.pass_stride; + const float *tile_buffer = (float *)ntile.buffer + tile_offset * pass_stride; const size_t merged_stride = rect_size.x; const size_t merged_offset = (xmin - rect.x) + (ymin - rect.y) * merged_stride; - float *merged_buffer = merged.data() + merged_offset * task.pass_stride; + float *merged_buffer = merged.data() + merged_offset * pass_stride; for (int y = ymin; y < ymax; y++) { - memcpy(merged_buffer, tile_buffer, sizeof(float) * task.pass_stride * (xmax - xmin)); - tile_buffer += ntile.stride * task.pass_stride; - merged_buffer += merged_stride * task.pass_stride; + for (int x = 0; x < pass_stride * (xmax - xmin); x++) { + merged_buffer[x] = tile_buffer[x] * scale; + } + tile_buffer += ntile.stride * pass_stride; + merged_buffer += merged_stride * pass_stride; } } /* Denoise */ denoise_openimagedenoise_buffer( - task, merged.data(), 0, rect_size.x, 0, 0, rect_size.x, rect_size.y); + task, merged.data(), 0, rect_size.x, 0, 0, rect_size.x, rect_size.y, 1.0f); /* Copy back result from merged buffer. */ RenderTile &ntile = neighbors.target; @@ -1101,16 +1143,20 @@ class CPUDevice : public Device { const int ymax = min(ntile.y + ntile.h, rect.w); const size_t tile_offset = ntile.offset + xmin + ymin * ntile.stride; - float *tile_buffer = (float *)ntile.buffer + tile_offset * task.pass_stride; + float *tile_buffer = (float *)ntile.buffer + tile_offset * pass_stride; const size_t merged_stride = rect_size.x; const size_t merged_offset = (xmin - rect.x) + (ymin - rect.y) * merged_stride; - const float *merged_buffer = merged.data() + merged_offset * task.pass_stride; + const float *merged_buffer = merged.data() + merged_offset * pass_stride; for (int y = ymin; y < ymax; y++) { - memcpy(tile_buffer, merged_buffer, sizeof(float) * task.pass_stride * (xmax - xmin)); - tile_buffer += ntile.stride * task.pass_stride; - merged_buffer += merged_stride * task.pass_stride; + for (int x = 0; x < pass_stride * (xmax - xmin); x += pass_stride) { + tile_buffer[x + 0] = merged_buffer[x + 0] * invscale; + tile_buffer[x + 1] = merged_buffer[x + 1] * invscale; + tile_buffer[x + 2] = merged_buffer[x + 2] * invscale; + } + tile_buffer += ntile.stride * pass_stride; + merged_buffer += merged_stride * pass_stride; } } diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index 35856f48213..1cc45983565 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -877,7 +877,7 @@ class OptiXDevice : public CUDADevice { # if OPTIX_DENOISER_NO_PIXEL_STRIDE device_only_memory<float> input_rgb(this, "denoiser input rgb"); - input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.optix_input_passes); + input_rgb.alloc_to_device(rect_size.x * rect_size.y * 3 * task.denoising.input_passes); void *input_args[] = {&input_rgb.device_pointer, &input_ptr, @@ -886,7 +886,7 @@ class OptiXDevice : public CUDADevice { &input_stride, &task.pass_stride, const_cast<int *>(pass_offset), - &task.denoising.optix_input_passes, + &task.denoising.input_passes, &rtile.sample}; launch_filter_kernel( "kernel_cuda_filter_convert_to_rgb", rect_size.x, rect_size.y, input_args); @@ -897,7 +897,7 @@ class OptiXDevice : public CUDADevice { # endif const bool recreate_denoiser = (denoiser == NULL) || - (task.denoising.optix_input_passes != denoiser_input_passes); + (task.denoising.input_passes != denoiser_input_passes); if (recreate_denoiser) { // Destroy existing handle before creating new one if (denoiser != NULL) { @@ -906,9 +906,9 @@ class OptiXDevice : public CUDADevice { // Create OptiX denoiser handle on demand when it is first used OptixDenoiserOptions denoiser_options; - assert(task.denoising.optix_input_passes >= 1 && task.denoising.optix_input_passes <= 3); + assert(task.denoising.input_passes >= 1 && task.denoising.input_passes <= 3); denoiser_options.inputKind = static_cast<OptixDenoiserInputKind>( - OPTIX_DENOISER_INPUT_RGB + (task.denoising.optix_input_passes - 1)); + OPTIX_DENOISER_INPUT_RGB + (task.denoising.input_passes - 1)); # if OPTIX_ABI_VERSION < 28 denoiser_options.pixelFormat = OPTIX_PIXEL_FORMAT_FLOAT3; # endif @@ -917,7 +917,7 @@ class OptiXDevice : public CUDADevice { optixDenoiserSetModel(denoiser, OPTIX_DENOISER_MODEL_KIND_HDR, NULL, 0)); // OptiX denoiser handle was created with the requested number of input passes - denoiser_input_passes = task.denoising.optix_input_passes; + denoiser_input_passes = task.denoising.input_passes; } OptixDenoiserSizes sizes = {}; @@ -992,7 +992,7 @@ class OptiXDevice : public CUDADevice { denoiser_state.device_pointer, scratch_offset, input_layers, - task.denoising.optix_input_passes, + task.denoising.input_passes, overlap_offset.x, overlap_offset.y, output_layers, diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index 21da55d50d4..fd380788282 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -42,6 +42,14 @@ enum DenoiserType { DENOISER_ALL = ~0, }; +enum DenoiserInput { + DENOISER_INPUT_RGB = 1, + DENOISER_INPUT_RGB_ALBEDO = 2, + DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3, + + DENOISER_INPUT_NUM, +}; + typedef int DenoiserTypeMask; class DenoiseParams { @@ -73,10 +81,10 @@ class DenoiseParams { /* Clamp the input to the range of +-1e8. Should be enough for any legitimate data. */ bool clamp_input; - /** Optix Denoiser **/ + /** OIDN/Optix Denoiser **/ - /* Passes handed over to the OptiX denoiser (default to color + albedo). */ - int optix_input_passes; + /* Passes handed over to the OIDN/OptiX denoiser (default to color + albedo). */ + DenoiserInput input_passes; DenoiseParams() { @@ -92,7 +100,7 @@ class DenoiseParams { neighbor_frames = 2; clamp_input = true; - optix_input_passes = 2; + input_passes = DENOISER_INPUT_RGB_ALBEDO_NORMAL; start_sample = 0; } diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl index 20d379939ab..acb198a9852 100644 --- a/intern/cycles/kernel/shaders/node_sky_texture.osl +++ b/intern/cycles/kernel/shaders/node_sky_texture.osl @@ -127,12 +127,13 @@ float precise_angle(vector a, vector b) return 2.0 * atan2(length(a - b), length(a + b)); } -color sky_radiance_nishita(vector dir, float nishita_data[9], string filename) +color sky_radiance_nishita(vector dir, float nishita_data[10], string filename) { /* definitions */ float sun_elevation = nishita_data[6]; float sun_rotation = nishita_data[7]; float angular_diameter = nishita_data[8]; + float sun_intensity = nishita_data[9]; int sun_disc = angular_diameter > 0; float alpha = 1.0; color xyz; @@ -149,7 +150,7 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename) /* if ray inside sun disc render it, otherwise render sky */ if (sun_dir_angle < half_angular && sun_disc == 1) { - /* get 3 pixels data */ + /* get 2 pixels data */ color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]); color pixel_top = color(nishita_data[3], nishita_data[4], nishita_data[5]); float y; @@ -158,13 +159,13 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename) if (sun_elevation - half_angular > 0.0) { if ((sun_elevation + half_angular) > 0.0) { y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5; - xyz = mix(pixel_bottom, pixel_top, y); + xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; } } else { if (sun_elevation + half_angular > 0.0) { y = dir_elevation / (sun_elevation + half_angular); - xyz = mix(pixel_bottom, pixel_top, y); + xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity; } } /* limb darkening, coefficient is 0.6f */ @@ -176,7 +177,8 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename) else { /* sky interpolation */ float x = (direction[1] + M_PI + sun_rotation) / M_2PI; - float y = 1.0 - (dir_elevation / M_PI_2); + /* more pixels toward horizon compensation */ + float y = 1.0 - sqrt(dir_elevation / M_PI_2); if (x > 1.0) { x = x - 1.0; } @@ -206,19 +208,20 @@ color sky_radiance_nishita(vector dir, float nishita_data[9], string filename) return xyz_to_rgb(xyz[0], xyz[1], xyz[2]) * 120000.0; } -shader node_sky_texture(int use_mapping = 0, - matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - vector Vector = P, - string type = "hosek_wilkie", - float theta = 0.0, - float phi = 0.0, - string filename = "", - color radiance = color(0.0, 0.0, 0.0), - float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - float nishita_data[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - output color Color = color(0.0, 0.0, 0.0)) +shader node_sky_texture( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + vector Vector = P, + string type = "hosek_wilkie", + float theta = 0.0, + float phi = 0.0, + string filename = "", + color radiance = color(0.0, 0.0, 0.0), + float config_x[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float config_y[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float config_z[9] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + float nishita_data[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + output color Color = color(0.0, 0.0, 0.0)) { vector p = Vector; diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h index 214c0cd1a9a..be2c8ccdacf 100644 --- a/intern/cycles/kernel/svm/svm_sky.h +++ b/intern/cycles/kernel/svm/svm_sky.h @@ -136,6 +136,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg, float sun_elevation = nishita_data[6]; float sun_rotation = nishita_data[7]; float angular_diameter = nishita_data[8]; + float sun_intensity = nishita_data[9]; bool sun_disc = (angular_diameter > 0.0f); float3 xyz; /* convert dir to spherical coordinates */ @@ -151,7 +152,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg, /* if ray inside sun disc render it, otherwise render sky */ if (sun_disc && sun_dir_angle < half_angular) { - /* get 3 pixels data */ + /* get 2 pixels data */ float3 pixel_bottom = make_float3(nishita_data[0], nishita_data[1], nishita_data[2]); float3 pixel_top = make_float3(nishita_data[3], nishita_data[4], nishita_data[5]); float y; @@ -160,13 +161,13 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg, if (sun_elevation - half_angular > 0.0f) { if (sun_elevation + half_angular > 0.0f) { y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f; - xyz = interp(pixel_bottom, pixel_top, y); + xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; } } else { if (sun_elevation + half_angular > 0.0f) { y = dir_elevation / (sun_elevation + half_angular); - xyz = interp(pixel_bottom, pixel_top, y); + xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity; } } /* limb darkening, coefficient is 0.6f */ @@ -178,7 +179,8 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg, else { /* sky interpolation */ float x = (direction.y + M_PI_F + sun_rotation) / M_2PI_F; - float y = dir_elevation / M_PI_2_F; + /* more pixels toward horizon compensation */ + float y = safe_sqrtf(dir_elevation / M_PI_2_F); if (x > 1.0f) { x -= 1.0f; } @@ -301,7 +303,7 @@ ccl_device void svm_node_tex_sky( /* Nishita */ else { /* Define variables */ - float nishita_data[9]; + float nishita_data[10]; float4 data = read_node_float(kg, offset); nishita_data[0] = data.x; @@ -317,7 +319,8 @@ ccl_device void svm_node_tex_sky( data = read_node_float(kg, offset); nishita_data[8] = data.x; - uint texture_id = __float_as_uint(data.y); + nishita_data[9] = data.y; + uint texture_id = __float_as_uint(data.z); /* Compute Sky */ f = sky_radiance_nishita(kg, dir, nishita_data, texture_id); diff --git a/intern/cycles/render/image_sky.cpp b/intern/cycles/render/image_sky.cpp index 24d4834c2fa..0560907c63e 100644 --- a/intern/cycles/render/image_sky.cpp +++ b/intern/cycles/render/image_sky.cpp @@ -25,8 +25,11 @@ CCL_NAMESPACE_BEGIN -SkyLoader::SkyLoader( - float sun_elevation, int altitude, float air_density, float dust_density, float ozone_density) +SkyLoader::SkyLoader(float sun_elevation, + float altitude, + float air_density, + float dust_density, + float ozone_density) : sun_elevation(sun_elevation), altitude(altitude), air_density(air_density), @@ -57,7 +60,6 @@ bool SkyLoader::load_pixels(const ImageMetaData &metadata, int width = metadata.width; int height = metadata.height; float *pixel_data = (float *)pixels; - float altitude_f = (float)altitude; /* precompute sky texture */ const int rows_per_task = divide_up(1024, width); @@ -70,7 +72,7 @@ bool SkyLoader::load_pixels(const ImageMetaData &metadata, width, height, sun_elevation, - altitude_f, + altitude, air_density, dust_density, ozone_density); diff --git a/intern/cycles/render/image_sky.h b/intern/cycles/render/image_sky.h index cf4a3e8942c..686f4e5b885 100644 --- a/intern/cycles/render/image_sky.h +++ b/intern/cycles/render/image_sky.h @@ -21,14 +21,14 @@ CCL_NAMESPACE_BEGIN class SkyLoader : public ImageLoader { private: float sun_elevation; - int altitude; + float altitude; float air_density; float dust_density; float ozone_density; public: SkyLoader(float sun_elevation, - int altitude, + float altitude, float air_density, float dust_density, float ozone_density); diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index c0615c6217b..183c02cb6b9 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -625,13 +625,19 @@ void LightManager::device_update_background(Device *device, } } + /* Determine sun direction from lat/long and texture mapping. */ float latitude = sky->sun_elevation; float longitude = M_2PI_F - sky->sun_rotation + M_PI_2_F; + float3 sun_direction = make_float3( + cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude)); + Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform()); + sun_direction = transform_direction(&sky_transform, sun_direction); + + /* Pack sun direction and size. */ float half_angle = sky->sun_size * 0.5f; - kbackground->sun = make_float4(cosf(latitude) * cosf(longitude), - cosf(latitude) * sinf(longitude), - sinf(latitude), - half_angle); + kbackground->sun = make_float4( + sun_direction.x, sun_direction.y, sun_direction.z, half_angle); + kbackground->sun_weight = 4.0f; environment_res.x = max(environment_res.x, 512); environment_res.y = max(environment_res.y, 256); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 1e09b71b340..1a29663ec5e 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -632,7 +632,7 @@ typedef struct SunSky { /* Parameter */ float radiance_x, radiance_y, radiance_z; - float config_x[9], config_y[9], config_z[9], nishita_data[9]; + float config_x[9], config_y[9], config_z[9], nishita_data[10]; } SunSky; /* Preetham model */ @@ -749,18 +749,24 @@ static void sky_texture_precompute_hosek(SunSky *sunsky, static void sky_texture_precompute_nishita(SunSky *sunsky, bool sun_disc, float sun_size, + float sun_intensity, float sun_elevation, float sun_rotation, - int altitude, + float altitude, float air_density, float dust_density) { /* sample 2 sun pixels */ float pixel_bottom[3]; float pixel_top[3]; - float altitude_f = (float)altitude; SKY_nishita_skymodel_precompute_sun( - sun_elevation, sun_size, altitude_f, air_density, dust_density, pixel_bottom, pixel_top); + sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top); + /* limit sun rotation between 0 and 360 degrees */ + sun_rotation = fmodf(sun_rotation, M_2PI_F); + if (sun_rotation < 0.0f) { + sun_rotation += M_2PI_F; + } + sun_rotation = M_2PI_F - sun_rotation; /* send data to svm_sky */ sunsky->nishita_data[0] = pixel_bottom[0]; sunsky->nishita_data[1] = pixel_bottom[1]; @@ -769,8 +775,9 @@ static void sky_texture_precompute_nishita(SunSky *sunsky, sunsky->nishita_data[4] = pixel_top[1]; sunsky->nishita_data[5] = pixel_top[2]; sunsky->nishita_data[6] = sun_elevation; - sunsky->nishita_data[7] = M_2PI_F - sun_rotation; + sunsky->nishita_data[7] = sun_rotation; sunsky->nishita_data[8] = sun_disc ? sun_size : 0.0f; + sunsky->nishita_data[9] = sun_intensity; } NODE_DEFINE(SkyTextureNode) @@ -790,9 +797,10 @@ NODE_DEFINE(SkyTextureNode) SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f); SOCKET_BOOLEAN(sun_disc, "Sun Disc", true); SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f); + SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f); SOCKET_FLOAT(sun_elevation, "Sun Elevation", M_PI_2_F); SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f); - SOCKET_INT(altitude, "Altitude", 0); + SOCKET_FLOAT(altitude, "Altitude", 1.0f); SOCKET_FLOAT(air_density, "Air", 1.0f); SOCKET_FLOAT(dust_density, "Dust", 1.0f); SOCKET_FLOAT(ozone_density, "Ozone", 1.0f); @@ -820,12 +828,17 @@ void SkyTextureNode::compile(SVMCompiler &compiler) else if (type == NODE_SKY_HOSEK) sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo); else if (type == NODE_SKY_NISHITA) { + /* Clamp altitude to reasonable values. + * Below 1m causes numerical issues and above 60km is space. */ + float clamped_altitude = clamp(altitude, 1.0f, 59999.0f); + sky_texture_precompute_nishita(&sunsky, sun_disc, sun_size, + sun_intensity, sun_elevation, sun_rotation, - altitude, + clamped_altitude, air_density, dust_density); /* precomputed texture image parameters */ @@ -837,7 +850,7 @@ void SkyTextureNode::compile(SVMCompiler &compiler) /* precompute sky texture */ if (handle.empty()) { SkyLoader *loader = new SkyLoader( - sun_elevation, altitude, air_density, dust_density, ozone_density); + sun_elevation, clamped_altitude, air_density, dust_density, ozone_density); handle = image_manager->add_image(loader, impar); } } @@ -892,7 +905,10 @@ void SkyTextureNode::compile(SVMCompiler &compiler) __float_as_uint(sunsky.nishita_data[5]), __float_as_uint(sunsky.nishita_data[6]), __float_as_uint(sunsky.nishita_data[7])); - compiler.add_node(__float_as_uint(sunsky.nishita_data[8]), handle.svm_slot(), 0, 0); + compiler.add_node(__float_as_uint(sunsky.nishita_data[8]), + __float_as_uint(sunsky.nishita_data[9]), + handle.svm_slot(), + 0); } tex_mapping.compile_end(compiler, vector_in, vector_offset); @@ -908,12 +924,17 @@ void SkyTextureNode::compile(OSLCompiler &compiler) else if (type == NODE_SKY_HOSEK) sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo); else if (type == NODE_SKY_NISHITA) { + /* Clamp altitude to reasonable values. + * Below 1m causes numerical issues and above 60km is space. */ + float clamped_altitude = clamp(altitude, 1.0f, 59999.0f); + sky_texture_precompute_nishita(&sunsky, sun_disc, sun_size, + sun_intensity, sun_elevation, sun_rotation, - altitude, + clamped_altitude, air_density, dust_density); /* precomputed texture image parameters */ @@ -925,7 +946,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler) /* precompute sky texture */ if (handle.empty()) { SkyLoader *loader = new SkyLoader( - sun_elevation, altitude, air_density, dust_density, ozone_density); + sun_elevation, clamped_altitude, air_density, dust_density, ozone_density); handle = image_manager->add_image(loader, impar); } } @@ -940,7 +961,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler) compiler.parameter_array("config_x", sunsky.config_x, 9); compiler.parameter_array("config_y", sunsky.config_y, 9); compiler.parameter_array("config_z", sunsky.config_z, 9); - compiler.parameter_array("nishita_data", sunsky.nishita_data, 9); + compiler.parameter_array("nishita_data", sunsky.nishita_data, 10); /* nishita texture */ if (type == NODE_SKY_NISHITA) { compiler.parameter_texture("filename", handle.svm_slot()); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 846ba7423e5..326f1d14168 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -170,9 +170,10 @@ class SkyTextureNode : public TextureNode { float ground_albedo; bool sun_disc; float sun_size; + float sun_intensity; float sun_elevation; float sun_rotation; - int altitude; + float altitude; float air_density; float dust_density; float ozone_density; diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index c7737392e7b..92061f55128 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -362,8 +362,8 @@ extern GHOST_TSuccess GHOST_HasCursorShape(GHOST_WindowHandle windowhandle, * \param mask The mask data for the cursor. * \param sizex The width of the cursor * \param sizey The height of the cursor - * \param hotX The X coordinate of the cursor hotspot. - * \param hotY The Y coordinate of the cursor hotspot. + * \param hotX The X coordinate of the cursor hot-spot. + * \param hotY The Y coordinate of the cursor hot-spot. * \param canInvertColor Let macOS invert cursor color to match platform convention. * \return Indication of success. */ diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 62290d20f1c..9c72b6f07f9 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -287,8 +287,8 @@ class GHOST_IWindow { * Set the shape of the cursor to a custom cursor. * \param bitmap The bitmap data for the cursor. * \param mask The mask data for the cursor. - * \param hotX The X coordinate of the cursor hotspot. - * \param hotY The Y coordinate of the cursor hotspot. + * \param hotX The X coordinate of the cursor hot-spot. + * \param hotY The Y coordinate of the cursor hot-spot. * \return Indication of success. */ virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 6738aa850ce..7cfea5110c5 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -124,8 +124,8 @@ class GHOST_Window : public GHOST_IWindow { * Set the shape of the cursor to a custom cursor. * \param bitmap The bitmap data for the cursor. * \param mask The mask data for the cursor. - * \param hotX The X coordinate of the cursor hotspot. - * \param hotY The Y coordinate of the cursor hotspot. + * \param hotX The X coordinate of the cursor hot-spot. + * \param hotY The Y coordinate of the cursor hot-spot. * \return Indication of success. */ GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 43121f08f2d..676a2fd785e 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -870,9 +870,9 @@ void MANTA::initializeRNAMap(FluidModifierData *fmd) mRNAMap["GUIDING_ALPHA"] = to_string(fds->guide_alpha); mRNAMap["GUIDING_BETA"] = to_string(fds->guide_beta); mRNAMap["GUIDING_FACTOR"] = to_string(fds->guide_vel_factor); - mRNAMap["GRAVITY_X"] = to_string(fds->gravity[0]); - mRNAMap["GRAVITY_Y"] = to_string(fds->gravity[1]); - mRNAMap["GRAVITY_Z"] = to_string(fds->gravity[2]); + mRNAMap["GRAVITY_X"] = to_string(fds->gravity_final[0]); + mRNAMap["GRAVITY_Y"] = to_string(fds->gravity_final[1]); + mRNAMap["GRAVITY_Z"] = to_string(fds->gravity_final[2]); mRNAMap["CACHE_DIR"] = cacheDirectory; mRNAMap["COMPRESSION_OPENVDB"] = vdbCompressionMethod; mRNAMap["PRECISION_OPENVDB"] = vdbPrecisionHalf; @@ -1256,6 +1256,7 @@ bool MANTA::readData(FluidModifierData *fmd, int framenr, bool resumable) << ", '" << volume_format << "', " << resumable_cache << ")"; pythonCommands.push_back(ss.str()); result &= runPythonString(pythonCommands); + return (mSmokeFromFile = result); } if (mUsingLiquid) { ss.str(""); @@ -1263,6 +1264,7 @@ bool MANTA::readData(FluidModifierData *fmd, int framenr, bool resumable) << ", '" << volume_format << "', " << resumable_cache << ")"; pythonCommands.push_back(ss.str()); result &= runPythonString(pythonCommands); + return (mFlipFromFile = result); } return result; } @@ -1296,7 +1298,7 @@ bool MANTA::readNoise(FluidModifierData *fmd, int framenr, bool resumable) << ", '" << volume_format << "', " << resumable_cache << ")"; pythonCommands.push_back(ss.str()); - return runPythonString(pythonCommands); + return (mNoiseFromFile = runPythonString(pythonCommands)); } bool MANTA::readMesh(FluidModifierData *fmd, int framenr) @@ -1331,7 +1333,7 @@ bool MANTA::readMesh(FluidModifierData *fmd, int framenr) pythonCommands.push_back(ss.str()); } - return runPythonString(pythonCommands); + return (mMeshFromFile = runPythonString(pythonCommands)); } bool MANTA::readParticles(FluidModifierData *fmd, int framenr, bool resumable) @@ -1365,7 +1367,7 @@ bool MANTA::readParticles(FluidModifierData *fmd, int framenr, bool resumable) << framenr << ", '" << volume_format << "', " << resumable_cache << ")"; pythonCommands.push_back(ss.str()); - return runPythonString(pythonCommands); + return (mParticlesFromFile = runPythonString(pythonCommands)); } bool MANTA::readGuiding(FluidModifierData *fmd, int framenr, bool sourceDomain) diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h index 977b99e7759..4ee3ae59957 100644 --- a/intern/mantaflow/intern/strings/fluid_script.h +++ b/intern/mantaflow/intern/strings/fluid_script.h @@ -146,19 +146,19 @@ mantaMsg('1 Mantaflow cell is ' + str(ratioMetersToRes_s$ID$) + ' Blender length ratioResToBLength_s$ID$ = float(res_s$ID$) / float(domainSize_s$ID$) # [cells / blength] (blength: cm, m, or km, ... )\n\ mantaMsg('1 Blender length unit is ' + str(ratioResToBLength_s$ID$) + ' Mantaflow cells long.')\n\ \n\ -ratioBTimeToTimstep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\ -mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimstep_s$ID$) + ' Mantaflow time units long.')\n\ +ratioBTimeToTimestep_s$ID$ = float(1) / float(frameLengthRaw_s$ID$) # the time within 1 blender time unit, see also fluid.c\n\ +mantaMsg('1 Blender time unit is ' + str(ratioBTimeToTimestep_s$ID$) + ' Mantaflow time units long.')\n\ \n\ ratioFrameToFramelength_s$ID$ = float(1) / float(frameLengthUnscaled_s$ID$ ) # the time within 1 frame\n\ mantaMsg('frame / frameLength is ' + str(ratioFrameToFramelength_s$ID$) + ' Mantaflow time units long.')\n\ \n\ -scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimstep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\ +scaleAcceleration_s$ID$ = ratioResToBLength_s$ID$ * (ratioBTimeToTimestep_s$ID$**2)# [meters/btime^2] to [cells/timestep^2] (btime: sec, min, or h, ...)\n\ mantaMsg('scaleAcceleration is ' + str(scaleAcceleration_s$ID$))\n\ \n\ scaleSpeedFrames_s$ID$ = ratioResToBLength_s$ID$ * ratioFrameToFramelength_s$ID$ # [blength/frame] to [cells/frameLength]\n\ mantaMsg('scaleSpeed is ' + str(scaleSpeedFrames_s$ID$))\n\ \n\ -scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimstep_s$ID$ # [blength/btime] to [cells/frameLength]\n\ +scaleSpeedTime_s$ID$ = ratioResToBLength_s$ID$ * ratioBTimeToTimestep_s$ID$ # [blength/btime] to [cells/frameLength]\n\ mantaMsg('scaleSpeedTime is ' + str(scaleSpeedTime_s$ID$))\n\ \n\ gravity_s$ID$ *= scaleAcceleration_s$ID$ # scale from world acceleration to cell based acceleration\n\ diff --git a/intern/sky/include/sky_model.h b/intern/sky/include/sky_model.h index 9e7700f3042..021086e1e02 100644 --- a/intern/sky/include/sky_model.h +++ b/intern/sky/include/sky_model.h @@ -356,8 +356,8 @@ typedef struct SKY_ArHosekSkyModelState { ---------------------------------------------------------------------------- */ SKY_ArHosekSkyModelState *SKY_arhosekskymodelstate_alloc_init(const double solar_elevation, - const double atmospheric_turbidity, - const double ground_albedo); + const double atmospheric_turbidity, + const double ground_albedo); /* ---------------------------------------------------------------------------- @@ -398,56 +398,55 @@ SKY_ArHosekSkyModelState *SKY_arhosekskymodelstate_alienworld_alloc_init( void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state); double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state, - double theta, - double gamma, - double wavelength); + double theta, + double gamma, + double wavelength); // CIE XYZ and RGB versions SKY_ArHosekSkyModelState *SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity, - const double albedo, - const double elevation); + const double albedo, + const double elevation); SKY_ArHosekSkyModelState *SKY_arhosek_rgb_skymodelstate_alloc_init(const double turbidity, - const double albedo, - const double elevation); + const double albedo, + const double elevation); double SKY_arhosek_tristim_skymodel_radiance(SKY_ArHosekSkyModelState *state, - double theta, - double gamma, - int channel); + double theta, + double gamma, + int channel); // Delivers the complete function: sky + sun, including limb darkening. // Please read the above description before using this - there are several // caveats! double SKY_arhosekskymodel_solar_radiance(SKY_ArHosekSkyModelState *state, - double theta, - double gamma, - double wavelength); - + double theta, + double gamma, + double wavelength); /* Nishita improved sky model */ void SKY_nishita_skymodel_precompute_texture(float *pixels, - int stride, - int start_y, - int end_y, - int width, - int height, - float sun_elevation, + int stride, + int start_y, + int end_y, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float dust_density, + float ozone_density); + +void SKY_nishita_skymodel_precompute_sun(float sun_elevation, + float angular_diameter, float altitude, float air_density, float dust_density, - float ozone_density); - -void SKY_nishita_skymodel_precompute_sun(float sun_elevation, - float angular_diameter, - float altitude, - float air_density, - float dust_density, - float *pixel_bottom, - float *pixel_top); + float *r_pixel_bottom, + float *r_pixel_top); #ifdef __cplusplus } diff --git a/intern/sky/source/sky_model.cpp b/intern/sky/source/sky_model.cpp index 3eca68e076c..64cf14ec030 100644 --- a/intern/sky/source/sky_model.cpp +++ b/intern/sky/source/sky_model.cpp @@ -292,9 +292,9 @@ void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state) } double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state, - double theta, - double gamma, - double wavelength) + double theta, + double gamma, + double wavelength) { int low_wl = (int)((wavelength - 320.0) / 40.0); @@ -323,8 +323,8 @@ double SKY_arhosekskymodel_radiance(SKY_ArHosekSkyModelState *state, // xyz and rgb versions SKY_ArHosekSkyModelState *SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity, - const double albedo, - const double elevation) + const double albedo, + const double elevation) { SKY_ArHosekSkyModelState *state = ALLOC(SKY_ArHosekSkyModelState); diff --git a/intern/sky/source/sky_nishita.cpp b/intern/sky/source/sky_nishita.cpp index 27286ddecac..eae95dc73fe 100644 --- a/intern/sky/source/sky_nishita.cpp +++ b/intern/sky/source/sky_nishita.cpp @@ -14,19 +14,23 @@ * limitations under the License. */ -#include "sky_model.h" #include "sky_float3.h" +#include "sky_model.h" /* Constants */ static const float rayleigh_scale = 8000.0f; // Rayleigh scale height (m) static const float mie_scale = 1200.0f; // Mie scale height (m) static const float mie_coeff = 2e-5f; // Mie scattering coefficient static const float mie_G = 0.76f; // aerosols anisotropy +static const float sqr_G = mie_G * mie_G; // squared aerosols anisotropy static const float earth_radius = 6360000.0f; // radius of Earth (m) static const float atmosphere_radius = 6420000.0f; // radius of atmosphere (m) static const int steps = 32; // segments per primary ray static const int steps_light = 16; // segments per sun connection ray static const int num_wavelengths = 21; // number of wavelengths +static const int max_luminous_efficacy = 683; // maximum luminous efficacy +static const float step_lambda = (num_wavelengths - 1) * + 1e-9f; // step between each sampled wavelength /* irradiance at top of atmosphere */ static const float irradiance[] = { 1.45756829855592995315f, 1.56596305559738380175f, 1.65148449067670455293f, @@ -90,7 +94,7 @@ static float3 spec_to_xyz(float *spectrum) xyz.y += cmf_xyz[i][1] * spectrum[i]; xyz.z += cmf_xyz[i][2] * spectrum[i]; } - return xyz * (20 * 683 * 1e-9f); + return xyz * step_lambda * max_luminous_efficacy; } /* Atmosphere volume models */ @@ -122,8 +126,6 @@ static float phase_rayleigh(float mu) static float phase_mie(float mu) { - static const float sqr_G = mie_G * mie_G; - return (3.0f * (1.0f - sqr_G) * (1.0f + sqr(mu))) / (8.0f * M_PI_F * (2.0f + sqr_G) * powf((1.0f + sqr_G - 2.0f * mie_G * mu), 1.5)); } @@ -167,6 +169,7 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir) /* The density of each segment is evaluated at its middle. */ float3 P = ray_origin + 0.5f * segment; + for (int i = 0; i < steps_light; i++) { /* Compute height above sea level. */ float height = len(P) - earth_radius; @@ -174,13 +177,13 @@ static float3 ray_optical_depth(float3 ray_origin, float3 ray_dir) /* Accumulate optical depth of this segment (density is assumed to be constant along it). */ float3 density = make_float3( density_rayleigh(height), density_mie(height), density_ozone(height)); - optical_depth += segment_length * density; + optical_depth += density; /* Advance along ray. */ P += segment; } - return optical_depth; + return optical_depth * segment_length; } /* Single Scattering implementation */ @@ -219,6 +222,7 @@ static void single_scattering(float3 ray_dir, /* The density and in-scattering of each segment is evaluated at its middle. */ float3 P = ray_origin + 0.5f * segment; + for (int i = 0; i < steps; i++) { /* Compute height above sea level. */ float height = len(P) - earth_radius; @@ -268,16 +272,16 @@ static void single_scattering(float3 ray_dir, /* calculate texture array */ void SKY_nishita_skymodel_precompute_texture(float *pixels, - int stride, - int start_y, - int end_y, - int width, - int height, - float sun_elevation, - float altitude, - float air_density, - float dust_density, - float ozone_density) + int stride, + int start_y, + int end_y, + int width, + int height, + float sun_elevation, + float altitude, + float air_density, + float dust_density, + float ozone_density) { /* calculate texture pixels */ float spectrum[num_wavelengths]; @@ -287,11 +291,13 @@ void SKY_nishita_skymodel_precompute_texture(float *pixels, float latitude_step = M_PI_2_F / height; float longitude_step = M_2PI_F / width; + float half_lat_step = latitude_step / 2.0f; for (int y = start_y; y < end_y; y++) { - float latitude = latitude_step * y; + /* sample more pixels toward the horizon */ + float latitude = (M_PI_2_F + half_lat_step) * sqr((float)y / height); - float *pixel_row = pixels + (y * width) * stride; + float *pixel_row = pixels + (y * width * stride); for (int x = 0; x < half_width; x++) { float longitude = longitude_step * x - M_PI_F; @@ -299,13 +305,15 @@ void SKY_nishita_skymodel_precompute_texture(float *pixels, single_scattering(dir, sun_dir, cam_pos, air_density, dust_density, ozone_density, spectrum); float3 xyz = spec_to_xyz(spectrum); - pixel_row[x * stride + 0] = xyz.x; - pixel_row[x * stride + 1] = xyz.y; - pixel_row[x * stride + 2] = xyz.z; - int mirror_x = width - x - 1; - pixel_row[mirror_x * stride + 0] = xyz.x; - pixel_row[mirror_x * stride + 1] = xyz.y; - pixel_row[mirror_x * stride + 2] = xyz.z; + int pos_x = x * stride; + pixel_row[pos_x] = xyz.x; + pixel_row[pos_x + 1] = xyz.y; + pixel_row[pos_x + 2] = xyz.z; + /* mirror sky */ + int mirror_x = (width - x - 1) * stride; + pixel_row[mirror_x] = xyz.x; + pixel_row[mirror_x + 1] = xyz.y; + pixel_row[mirror_x + 2] = xyz.z; } } } @@ -326,17 +334,17 @@ static void sun_radiation(float3 cam_dir, /* Combine spectra and the optical depth into transmittance. */ float transmittance = rayleigh_coeff[i] * optical_depth.x * air_density + 1.11f * mie_coeff * optical_depth.y * dust_density; - r_spectrum[i] = (irradiance[i] / solid_angle) * expf(-transmittance); + r_spectrum[i] = irradiance[i] * expf(-transmittance) / solid_angle; } } void SKY_nishita_skymodel_precompute_sun(float sun_elevation, - float angular_diameter, - float altitude, - float air_density, - float dust_density, - float *pixel_bottom, - float *pixel_top) + float angular_diameter, + float altitude, + float air_density, + float dust_density, + float *r_pixel_bottom, + float *r_pixel_top) { /* definitions */ float half_angular = angular_diameter / 2.0f; @@ -358,10 +366,10 @@ void SKY_nishita_skymodel_precompute_sun(float sun_elevation, pix_top = spec_to_xyz(spectrum); /* store pixels */ - pixel_bottom[0] = pix_bottom.x; - pixel_bottom[1] = pix_bottom.y; - pixel_bottom[2] = pix_bottom.z; - pixel_top[0] = pix_top.x; - pixel_top[1] = pix_top.y; - pixel_top[2] = pix_top.z; + r_pixel_bottom[0] = pix_bottom.x; + r_pixel_bottom[1] = pix_bottom.y; + r_pixel_bottom[2] = pix_bottom.z; + r_pixel_top[0] = pix_top.x; + r_pixel_top[1] = pix_top.y; + r_pixel_top[2] = pix_top.z; } |