Cycles / Sky Texture:

* Added a new sky model by Hosek and Wilkie: "An Analytic Model for Full Spectral Sky-Dome Radiance" http://cgg.mff.cuni.cz/projects/SkylightModelling/ 

Example render:
http://archive.dingto.org/2013/blender/code/new_sky_model.png
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Textures#Sky_Texture

Details:
* User can choose between the older Preetham and the new Hosek / Wilkie model via a dropdown. For older files, backwards compatibility is preserved. When we add a new Sky texture, it defaults to the new model though. 
* For the new model, you can specify the ground albedo (see documentation for details). 
* Turbidity now has a UI soft range between 1 and 10, higher values (up to 30) are still possible, but can result in weird colors or black. 
* Removed the limitation of 1 sky texture per SVM stack. (Patch by Lukas Tönne, thanks!)

Thanks to Brecht for code review and some help! 

This is part of my GSoC 2013 project, SVN merge of r59214, r59220, r59251 and r59601.
This commit is contained in:
Thomas Dinges
2013-08-28 14:11:28 +00:00
18 changed files with 5056 additions and 129 deletions

View File

@@ -18,6 +18,7 @@
#include "nodes.h"
#include "svm.h"
#include "osl.h"
#include "sky_model.h"
#include "util_transform.h"
@@ -384,19 +385,35 @@ static float2 sky_spherical_coordinates(float3 dir)
return make_float2(acosf(dir.z), atan2f(dir.x, dir.y));
}
typedef struct SunSky {
/* sun direction in spherical and cartesian */
float theta, phi;
/* Parameter */
float radiance_x, radiance_y, radiance_z;
float config_x[9], config_y[9], config_z[9];
} SunSky;
/* Preetham model */
static float sky_perez_function(float lam[6], float theta, float gamma)
{
return (1.0f + lam[0]*expf(lam[1]/cosf(theta))) * (1.0f + lam[2]*expf(lam[3]*gamma) + lam[4]*cosf(gamma)*cosf(gamma));
}
static void sky_texture_precompute(KernelSunSky *ksunsky, float3 dir, float turbidity)
static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
{
/*
* We re-use the SunSky struct of the new model, to avoid extra variables
* zenith_Y/x/y is now radiance_x/y/z
* perez_Y/x/y is now config_x/y/z
*/
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
float phi = spherical.y;
ksunsky->theta = theta;
ksunsky->phi = phi;
sunsky->theta = theta;
sunsky->phi = phi;
float theta2 = theta*theta;
float theta3 = theta2*theta;
@@ -404,47 +421,93 @@ static void sky_texture_precompute(KernelSunSky *ksunsky, float3 dir, float turb
float T2 = T * T;
float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
ksunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
ksunsky->zenith_Y *= 0.06f;
sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
sunsky->radiance_x *= 0.06f;
ksunsky->zenith_x =
sunsky->radiance_y =
(0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
(-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T +
(0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
ksunsky->zenith_y =
sunsky->radiance_z =
(0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
(-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T +
(0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
ksunsky->perez_Y[0] = (0.1787f * T - 1.4630f);
ksunsky->perez_Y[1] = (-0.3554f * T + 0.4275f);
ksunsky->perez_Y[2] = (-0.0227f * T + 5.3251f);
ksunsky->perez_Y[3] = (0.1206f * T - 2.5771f);
ksunsky->perez_Y[4] = (-0.0670f * T + 0.3703f);
sunsky->config_x[0] = (0.1787f * T - 1.4630f);
sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
sunsky->config_x[3] = (0.1206f * T - 2.5771f);
sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
ksunsky->perez_x[0] = (-0.0193f * T - 0.2592f);
ksunsky->perez_x[1] = (-0.0665f * T + 0.0008f);
ksunsky->perez_x[2] = (-0.0004f * T + 0.2125f);
ksunsky->perez_x[3] = (-0.0641f * T - 0.8989f);
ksunsky->perez_x[4] = (-0.0033f * T + 0.0452f);
sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
ksunsky->perez_y[0] = (-0.0167f * T - 0.2608f);
ksunsky->perez_y[1] = (-0.0950f * T + 0.0092f);
ksunsky->perez_y[2] = (-0.0079f * T + 0.2102f);
ksunsky->perez_y[3] = (-0.0441f * T - 1.6537f);
ksunsky->perez_y[4] = (-0.0109f * T + 0.0529f);
sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
ksunsky->zenith_Y /= sky_perez_function(ksunsky->perez_Y, 0, theta);
ksunsky->zenith_x /= sky_perez_function(ksunsky->perez_x, 0, theta);
ksunsky->zenith_y /= sky_perez_function(ksunsky->perez_y, 0, theta);
sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
}
/* Hosek / Wilkie */
static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidity, float ground_albedo)
{
/* Calculate Sun Direction and save coordinates */
float2 spherical = sky_spherical_coordinates(dir);
float theta = spherical.x;
float phi = spherical.y;
sunsky->theta = theta;
sunsky->phi = phi;
double solarElevation = M_PI_2_F - theta;
/* Initialize Sky Model */
ArHosekSkyModelState *sky_state;
sky_state = arhosek_xyz_skymodelstate_alloc_init(turbidity, ground_albedo, solarElevation);
/* Copy values from sky_state to SunSky */
for (int i = 0; i < 9; ++i) {
sunsky->config_x[i] = sky_state->configs[0][i];
sunsky->config_y[i] = sky_state->configs[1][i];
sunsky->config_z[i] = sky_state->configs[2][i];
}
sunsky->radiance_x = sky_state->radiances[0];
sunsky->radiance_y = sky_state->radiances[1];
sunsky->radiance_z = sky_state->radiances[2];
/* Free sky_state */
arhosekskymodelstate_free(sky_state);
}
static ShaderEnum sky_type_init()
{
ShaderEnum enm;
enm.insert("Preetham", NODE_SKY_OLD);
enm.insert("Hosek / Wilkie", NODE_SKY_NEW);
return enm;
}
ShaderEnum SkyTextureNode::type_enum = sky_type_init();
SkyTextureNode::SkyTextureNode()
: TextureNode("sky_texture")
{
type = ustring("Hosek / Wilkie");
sun_direction = make_float3(0.0f, 0.0f, 1.0f);
turbidity = 2.2f;
ground_albedo = 0.3f;
add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
add_output("Color", SHADER_SOCKET_COLOR);
@@ -455,15 +518,17 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
ShaderInput *vector_in = input("Vector");
ShaderOutput *color_out = output("Color");
if(compiler.sunsky) {
sky_texture_precompute(compiler.sunsky, sun_direction, turbidity);
compiler.sunsky = NULL;
}
SunSky sunsky;
if(type_enum[type] == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
else if(type_enum[type] == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
if(vector_in->link)
compiler.stack_assign(vector_in);
int vector_offset = vector_in->stack_offset;
int sky_model = type_enum[type];
if(!tex_mapping.skip()) {
vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
@@ -471,7 +536,15 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
}
compiler.stack_assign(color_out);
compiler.add_node(NODE_TEX_SKY, vector_offset, color_out->stack_offset);
compiler.add_node(NODE_TEX_SKY, vector_offset, color_out->stack_offset, sky_model);
compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y));
compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2]));
compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6]));
compiler.add_node(__float_as_uint(sunsky.config_x[7]), __float_as_uint(sunsky.config_x[8]), __float_as_uint(sunsky.config_y[0]), __float_as_uint(sunsky.config_y[1]));
compiler.add_node(__float_as_uint(sunsky.config_y[2]), __float_as_uint(sunsky.config_y[3]), __float_as_uint(sunsky.config_y[4]), __float_as_uint(sunsky.config_y[5]));
compiler.add_node(__float_as_uint(sunsky.config_y[6]), __float_as_uint(sunsky.config_y[7]), __float_as_uint(sunsky.config_y[8]), __float_as_uint(sunsky.config_z[0]));
compiler.add_node(__float_as_uint(sunsky.config_z[1]), __float_as_uint(sunsky.config_z[2]), __float_as_uint(sunsky.config_z[3]), __float_as_uint(sunsky.config_z[4]));
compiler.add_node(__float_as_uint(sunsky.config_z[5]), __float_as_uint(sunsky.config_z[6]), __float_as_uint(sunsky.config_z[7]), __float_as_uint(sunsky.config_z[8]));
if(vector_offset != vector_in->stack_offset)
compiler.stack_clear_offset(vector_in->type, vector_offset);
@@ -481,8 +554,19 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
compiler.parameter_vector("sun_direction", sun_direction);
compiler.parameter("turbidity", turbidity);
SunSky sunsky;
if(type_enum[type] == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
else if(type_enum[type] == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
compiler.parameter("sky_model", type);
compiler.parameter("theta", sunsky.theta);
compiler.parameter("phi", sunsky.phi);
compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
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.add(this, "node_sky_texture");
}