Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/closure/volume.h
| /* | /* | ||||
| * Copyright 2011-2013 Blender Foundation | * Copyright 2011-2013 Blender Foundation | ||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| * You may obtain a copy of the License at | * You may obtain a copy of the License at | ||||
| * | * | ||||
| * http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * | * | ||||
| * Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
| * distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| #ifndef __VOLUME_H__ | #pragma once | ||||
| #define __VOLUME_H__ | |||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* VOLUME EXTINCTION */ | /* VOLUME EXTINCTION */ | ||||
| ccl_device void volume_extinction_setup(ShaderData *sd, float3 weight) | ccl_device void volume_extinction_setup(ShaderData *sd, float3 weight) | ||||
| { | { | ||||
| if (sd->flag & SD_EXTINCTION) { | if (sd->flag & SD_EXTINCTION) { | ||||
| Show All 30 Lines | ccl_device int volume_henyey_greenstein_setup(HenyeyGreensteinVolume *volume) | ||||
| volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; | volume->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; | ||||
| /* clamp anisotropy to avoid delta function */ | /* clamp anisotropy to avoid delta function */ | ||||
| volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f); | volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f); | ||||
| return SD_SCATTER; | return SD_SCATTER; | ||||
| } | } | ||||
| ccl_device bool volume_henyey_greenstein_merge(const ShaderClosure *a, const ShaderClosure *b) | ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderVolumeClosure *svc, | ||||
| { | |||||
| const HenyeyGreensteinVolume *volume_a = (const HenyeyGreensteinVolume *)a; | |||||
| const HenyeyGreensteinVolume *volume_b = (const HenyeyGreensteinVolume *)b; | |||||
| return (volume_a->g == volume_b->g); | |||||
| } | |||||
| ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, | |||||
| const float3 I, | const float3 I, | ||||
| float3 omega_in, | float3 omega_in, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume *)sc; | float g = svc->g; | ||||
| float g = volume->g; | |||||
| /* note that I points towards the viewer */ | /* note that I points towards the viewer */ | ||||
| if (fabsf(g) < 1e-3f) { | if (fabsf(g) < 1e-3f) { | ||||
| *pdf = M_1_PI_F * 0.25f; | *pdf = M_1_PI_F * 0.25f; | ||||
| } | } | ||||
| else { | else { | ||||
| float cos_theta = dot(-I, omega_in); | float cos_theta = dot(-I, omega_in); | ||||
| *pdf = single_peaked_henyey_greenstein(cos_theta, g); | *pdf = single_peaked_henyey_greenstein(cos_theta, g); | ||||
| Show All 29 Lines | henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pdf) | ||||
| float3 T, B; | float3 T, B; | ||||
| make_orthonormals(D, &T, &B); | make_orthonormals(D, &T, &B); | ||||
| dir = dir.x * T + dir.y * B + dir.z * D; | dir = dir.x * T + dir.y * B + dir.z * D; | ||||
| return dir; | return dir; | ||||
| } | } | ||||
| ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, | ccl_device int volume_henyey_greenstein_sample(const ShaderVolumeClosure *svc, | ||||
| float3 I, | float3 I, | ||||
| float3 dIdx, | float3 dIdx, | ||||
| float3 dIdy, | float3 dIdy, | ||||
| float randu, | float randu, | ||||
| float randv, | float randv, | ||||
| float3 *eval, | float3 *eval, | ||||
| float3 *omega_in, | float3 *omega_in, | ||||
| float3 *domega_in_dx, | float3 *domega_in_dx, | ||||
| float3 *domega_in_dy, | float3 *domega_in_dy, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| const HenyeyGreensteinVolume *volume = (const HenyeyGreensteinVolume *)sc; | float g = svc->g; | ||||
| float g = volume->g; | |||||
| /* note that I points towards the viewer and so is used negated */ | /* note that I points towards the viewer and so is used negated */ | ||||
| *omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf); | *omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf); | ||||
| *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */ | *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */ | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| /* todo: implement ray differential estimation */ | /* todo: implement ray differential estimation */ | ||||
| *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f); | *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f); | ||||
| *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f); | *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f); | ||||
| #endif | #endif | ||||
| return LABEL_VOLUME_SCATTER; | return LABEL_VOLUME_SCATTER; | ||||
| } | } | ||||
| /* VOLUME CLOSURE */ | /* VOLUME CLOSURE */ | ||||
| ccl_device float3 volume_phase_eval(const ShaderData *sd, | ccl_device float3 volume_phase_eval(const ShaderData *sd, | ||||
| const ShaderClosure *sc, | const ShaderVolumeClosure *svc, | ||||
| float3 omega_in, | float3 omega_in, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| kernel_assert(sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID); | return volume_henyey_greenstein_eval_phase(svc, sd->I, omega_in, pdf); | ||||
| return volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf); | |||||
| } | } | ||||
| ccl_device int volume_phase_sample(const ShaderData *sd, | ccl_device int volume_phase_sample(const ShaderData *sd, | ||||
| const ShaderClosure *sc, | const ShaderVolumeClosure *svc, | ||||
| float randu, | float randu, | ||||
| float randv, | float randv, | ||||
| float3 *eval, | float3 *eval, | ||||
| float3 *omega_in, | float3 *omega_in, | ||||
| differential3 *domega_in, | differential3 *domega_in, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| int label; | return volume_henyey_greenstein_sample(svc, | ||||
| switch (sc->type) { | |||||
| case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: | |||||
| label = volume_henyey_greenstein_sample(sc, | |||||
| sd->I, | sd->I, | ||||
| sd->dI.dx, | sd->dI.dx, | ||||
| sd->dI.dy, | sd->dI.dy, | ||||
| randu, | randu, | ||||
| randv, | randv, | ||||
| eval, | eval, | ||||
| omega_in, | omega_in, | ||||
| &domega_in->dx, | &domega_in->dx, | ||||
| &domega_in->dy, | &domega_in->dy, | ||||
| pdf); | pdf); | ||||
| break; | |||||
| default: | |||||
| *eval = make_float3(0.0f, 0.0f, 0.0f); | |||||
| label = LABEL_NONE; | |||||
| break; | |||||
| } | } | ||||
| return label; | /* Volume sampling utilities. */ | ||||
| /* todo: this value could be tweaked or turned into a probability to avoid | |||||
| * unnecessary work in volumes and subsurface scattering. */ | |||||
| #define VOLUME_THROUGHPUT_EPSILON 1e-6f | |||||
| ccl_device float3 volume_color_transmittance(float3 sigma, float t) | |||||
| { | |||||
| return exp3(-sigma * t); | |||||
| } | } | ||||
| CCL_NAMESPACE_END | ccl_device float volume_channel_get(float3 value, int channel) | ||||
| { | |||||
| return (channel == 0) ? value.x : ((channel == 1) ? value.y : value.z); | |||||
| } | |||||
| #endif | ccl_device int volume_sample_channel(float3 albedo, float3 throughput, float rand, float3 *pdf) | ||||
| { | |||||
| /* Sample color channel proportional to throughput and single scattering | |||||
| * albedo, to significantly reduce noise with many bounce, following: | |||||
| * | |||||
| * "Practical and Controllable Subsurface Scattering for Production Path | |||||
| * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */ | |||||
| float3 weights = fabs(throughput * albedo); | |||||
| float sum_weights = weights.x + weights.y + weights.z; | |||||
| float3 weights_pdf; | |||||
| if (sum_weights > 0.0f) { | |||||
| weights_pdf = weights / sum_weights; | |||||
| } | |||||
| else { | |||||
| weights_pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f); | |||||
| } | |||||
| *pdf = weights_pdf; | |||||
| /* OpenCL does not support -> on float3, so don't use pdf->x. */ | |||||
| if (rand < weights_pdf.x) { | |||||
| return 0; | |||||
| } | |||||
| else if (rand < weights_pdf.x + weights_pdf.y) { | |||||
| return 1; | |||||
| } | |||||
| else { | |||||
| return 2; | |||||
| } | |||||
| } | |||||
| CCL_NAMESPACE_END | |||||