Blender V5.0
node_shader_tex_sky.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "node_shader_util.hh"
6#include "node_util.hh"
7#include "sky_hosek.h"
8#include "sky_nishita.h"
9
10#include "BKE_context.hh"
11#include "BKE_scene.hh"
12#include "BKE_texture.h"
13
14#include "RNA_access.hh"
15
17#include "UI_resources.hh"
18
20
22
24{
25 b.add_input<decl::Vector>("Vector").hide_value();
26 b.add_output<decl::Color>("Color").no_muted_links();
27}
28
30{
31 layout->prop(ptr, "sky_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
32
33 if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
34 layout->prop(ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
35 layout->prop(ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
36 }
37 else if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
38 layout->prop(ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
39 layout->prop(ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
40 layout->prop(ptr, "ground_albedo", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
41 }
42 else {
43 Scene *scene = CTX_data_scene(C);
45 layout->label(RPT_("Sun disc not available in EEVEE"), ICON_ERROR);
46 }
47 layout->prop(ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
48
50 if (RNA_boolean_get(ptr, "sun_disc")) {
51 col = &layout->column(true);
52 col->prop(ptr, "sun_size", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
53 col->prop(ptr, "sun_intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
54 }
55
56 col = &layout->column(true);
57 col->prop(ptr, "sun_elevation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
58 col->prop(ptr, "sun_rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
59
60 layout->prop(ptr, "altitude", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
61
62 col = &layout->column(true);
63 col->prop(ptr, "air_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
64 col->prop(ptr, "aerosol_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
65 col->prop(ptr, "ozone_density", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
66 }
67}
68
69static void node_shader_init_tex_sky(bNodeTree * /*ntree*/, bNode *node)
70{
71 NodeTexSky *tex = MEM_callocN<NodeTexSky>("NodeTexSky");
74 tex->sun_direction[0] = 0.0f;
75 tex->sun_direction[1] = 0.0f;
76 tex->sun_direction[2] = 1.0f;
77 tex->turbidity = 2.2f;
78 tex->ground_albedo = 0.3f;
79 tex->sun_disc = true;
80 tex->sun_size = DEG2RADF(0.545f);
81 tex->sun_intensity = 1.0f;
82 tex->sun_elevation = DEG2RADF(15.0f);
83 tex->sun_rotation = 0.0f;
84 tex->altitude = 100.0f;
85 tex->air_density = 1.0f;
86 tex->aerosol_density = 1.0f;
87 tex->ozone_density = 1.0f;
89 node->storage = tex;
90}
91
93 float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */
94 float radiance[3];
95};
96
97static float sky_perez_function(const float *lam, float theta, float gamma)
98{
99 float ctheta = cosf(theta);
100 float cgamma = cosf(gamma);
101
102 return (1.0 + lam[0] * expf(lam[1] / ctheta)) *
103 (1.0 + lam[2] * expf(lam[3] * gamma) + lam[4] * cgamma * cgamma);
104}
105
106static void sky_precompute_old(SkyModelPreetham *sunsky, const float sun_angles[], float turbidity)
107{
108 float theta = sun_angles[0];
109 float theta2 = theta * theta;
110 float theta3 = theta2 * theta;
111 float T = turbidity;
112 float T2 = T * T;
113 float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI - 2.0f * theta);
114
115 sunsky->radiance[0] = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
116 sunsky->radiance[0] *= 0.06f;
117
118 sunsky->radiance[1] = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
119 (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) *
120 T +
121 (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
122
123 sunsky->radiance[2] = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
124 (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) *
125 T +
126 (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
127
128 sunsky->config_Y[0] = (0.1787f * T - 1.4630f);
129 sunsky->config_Y[1] = (-0.3554f * T + 0.4275f);
130 sunsky->config_Y[2] = (-0.0227f * T + 5.3251f);
131 sunsky->config_Y[3] = (0.1206f * T - 2.5771f);
132 sunsky->config_Y[4] = (-0.0670f * T + 0.3703f);
133
134 sunsky->config_x[0] = (-0.0193f * T - 0.2592f);
135 sunsky->config_x[1] = (-0.0665f * T + 0.0008f);
136 sunsky->config_x[2] = (-0.0004f * T + 0.2125f);
137 sunsky->config_x[3] = (-0.0641f * T - 0.8989f);
138 sunsky->config_x[4] = (-0.0033f * T + 0.0452f);
139
140 sunsky->config_y[0] = (-0.0167f * T - 0.2608f);
141 sunsky->config_y[1] = (-0.0950f * T + 0.0092f);
142 sunsky->config_y[2] = (-0.0079f * T + 0.2102f);
143 sunsky->config_y[3] = (-0.0441f * T - 1.6537f);
144 sunsky->config_y[4] = (-0.0109f * T + 0.0529f);
145
146 sunsky->radiance[0] /= sky_perez_function(sunsky->config_Y, 0, theta);
147 sunsky->radiance[1] /= sky_perez_function(sunsky->config_x, 0, theta);
148 sunsky->radiance[2] /= sky_perez_function(sunsky->config_y, 0, theta);
149}
150
151static void sky_simplify_multiscatter_elevation_rotation(float &sun_elevation, float &sun_rotation)
152{
153 /* Patch Sun position so users are able to animate the daylight cycle while keeping the shading
154 * code simple. */
155 float new_sun_elevation = sun_elevation;
156 float new_sun_rotation = sun_rotation;
157
158 /* Wrap `new_sun_elevation` into [-2PI..2PI] range. */
159 new_sun_elevation = fmodf(new_sun_elevation, 2.0f * M_PI);
160 /* Wrap `new_sun_elevation` into [-PI..PI] range. */
161 if (fabsf(new_sun_elevation) >= M_PI) {
162 new_sun_elevation -= copysignf(2.0f, new_sun_elevation) * M_PI;
163 }
164 /* Wrap `new_sun_elevation` into [-PI/2..PI/2] range while keeping the same absolute position.
165 */
166 if (new_sun_elevation >= M_PI / 2.0f || new_sun_elevation <= -M_PI / 2.0f) {
167 new_sun_elevation = copysignf(M_PI, new_sun_elevation) - new_sun_elevation;
168 new_sun_rotation += M_PI;
169 }
170
171 /* Wrap `new_sun_rotation` into [-2PI..2PI] range. */
172 new_sun_rotation = fmodf(new_sun_rotation, 2.0f * M_PI);
173 /* Wrap `new_sun_rotation` into [0..2PI] range. */
174 if (new_sun_rotation < 0.0f) {
175 new_sun_rotation += 2.0f * M_PI;
176 }
177 new_sun_rotation = 2.0f * M_PI - new_sun_rotation;
178
179 sun_elevation = new_sun_elevation;
180 sun_rotation = new_sun_rotation;
181}
182
184 bNode *node,
185 bNodeExecData * /*execdata*/,
188{
189 node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
191 NodeTexSky *tex = (NodeTexSky *)node->storage;
192 float sun_angles[2]; /* [0]=theta=zenith angle [1]=phi=azimuth */
193 sun_angles[0] = acosf(tex->sun_direction[2]);
194 sun_angles[1] = atan2f(tex->sun_direction[0], tex->sun_direction[1]);
195
196 if (tex->sky_model == SHD_SKY_PREETHAM) {
197 /* Preetham */
198 SkyModelPreetham sunsky;
199 sky_precompute_old(&sunsky, sun_angles, tex->turbidity);
202 return GPU_stack_link(mat,
203 node,
204 "node_tex_sky_preetham",
205 in,
206 out,
207 /* Pass config_Y/x/y as 3x(vec4+float) */
208 GPU_uniform(&sunsky.config_Y[0]),
209 GPU_uniform(&sunsky.config_Y[4]),
210 GPU_uniform(&sunsky.config_x[0]),
211 GPU_uniform(&sunsky.config_x[4]),
212 GPU_uniform(&sunsky.config_y[0]),
213 GPU_uniform(&sunsky.config_y[4]),
214 GPU_uniform(sun_angles),
215 GPU_uniform(sunsky.radiance),
219 }
220 if (tex->sky_model == SHD_SKY_HOSEK) {
221 /* Hosek / Wilkie */
222 sun_angles[0] = fmin(M_PI_2, sun_angles[0]); /* clamp to horizon */
224 tex->turbidity, tex->ground_albedo, fmax(0.0, M_PI_2 - sun_angles[0]));
225 /* Pass sky_state->configs[3][9] as 3*(vec4+vec4)+vec3 */
226 float config_x07[8], config_y07[8], config_z07[8], config_xyz8[3];
227 for (int i = 0; i < 8; ++i) {
228 config_x07[i] = float(sky_state->configs[0][i]);
229 config_y07[i] = float(sky_state->configs[1][i]);
230 config_z07[i] = float(sky_state->configs[2][i]);
231 }
232 for (int i = 0; i < 3; ++i) {
233 config_xyz8[i] = float(sky_state->configs[i][8]);
234 }
235 float radiance[3];
236 for (int i = 0; i < 3; i++) {
237 radiance[i] = sky_state->radiances[i] * (2 * M_PI / 683);
238 }
242 return GPU_stack_link(mat,
243 node,
244 "node_tex_sky_hosekwilkie",
245 in,
246 out,
247 GPU_uniform(&config_x07[0]),
248 GPU_uniform(&config_x07[4]),
249 GPU_uniform(&config_y07[0]),
250 GPU_uniform(&config_y07[4]),
251 GPU_uniform(&config_z07[0]),
252 GPU_uniform(&config_z07[4]),
253 GPU_uniform(config_xyz8),
254 GPU_uniform(sun_angles),
255 GPU_uniform(radiance),
259 }
260
261 /* Nishita */
263
264 float sun_rotation = tex->sun_rotation;
267 4,
270 tex->sun_elevation,
271 tex->altitude,
272 tex->air_density,
273 tex->aerosol_density,
274 tex->ozone_density);
275
276 /* The multi-scatter case takes care of rotation wrapping in the
277 * sky_simplify_multiscatter_elevation_rotation(). */
278 sun_rotation = fmodf(sun_rotation, 2.0f * M_PI);
279 if (sun_rotation < 0.0f) {
280 sun_rotation += 2.0f * M_PI;
281 }
282 sun_rotation = 2.0f * M_PI - sun_rotation;
283 }
284 else {
285 float sun_elevation = tex->sun_elevation;
286 sky_simplify_multiscatter_elevation_rotation(sun_elevation, sun_rotation);
288 4,
291 sun_elevation,
292 tex->altitude,
293 tex->air_density,
294 tex->aerosol_density,
295 tex->ozone_density);
296 }
297
300
301 /* To fix pole issue we clamp the v coordinate. */
305 float layer;
306 float sky_type = (tex->sky_model == SHD_SKY_SINGLE_SCATTERING) ? 0.0f : 1.0f;
307 GPUNodeLink *sky_texture = GPU_image_sky(
308 mat, GPU_SKY_WIDTH, GPU_SKY_HEIGHT, pixels.data(), &layer, sampler);
309 return GPU_stack_link(mat,
310 node,
311 "node_tex_sky_nishita",
312 in,
313 out,
314 GPU_constant(&sky_type),
315 GPU_constant(&sun_rotation),
319 sky_texture,
320 GPU_constant(&layer));
321}
322
323static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
324{
325 bNodeSocket *sockVector = bke::node_find_socket(*node, SOCK_IN, "Vector");
326
327 NodeTexSky *tex = (NodeTexSky *)node->storage;
329 *ntree,
330 *sockVector,
332 tex->sun_disc == 1));
333}
334
336{
337 const NodeDeclaration &declaration = *params.node_type().static_declaration;
338 if (params.in_out() == SOCK_OUT) {
340 return;
341 }
342 if (params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
343 SOCK_FLOAT))
344 {
345 params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
346 bNode &node = params.add_node("ShaderNodeTexSky");
347 NodeTexSky *tex = (NodeTexSky *)node.storage;
348 tex->sun_disc = false;
349 params.update_and_connect_available_socket(node, "Vector");
350 });
351 }
352}
353
354} // namespace blender::nodes::node_shader_tex_sky_cc
355
356/* node type definition */
358{
359 namespace file_ns = blender::nodes::node_shader_tex_sky_cc;
360
361 static blender::bke::bNodeType ntype;
362
363 sh_node_type_base(&ntype, "ShaderNodeTexSky", SH_NODE_TEX_SKY);
364 ntype.ui_name = "Sky Texture";
365 ntype.ui_description = "Generate a procedural sky texture";
366 ntype.enum_name_legacy = "TEX_SKY";
368 ntype.declare = file_ns::node_declare;
369 ntype.draw_buttons = file_ns::node_shader_buts_tex_sky;
371 ntype.initfunc = file_ns::node_shader_init_tex_sky;
374 ntype.gpu_fn = file_ns::node_shader_gpu_tex_sky;
375 ntype.updatefunc = file_ns::node_shader_update_sky;
376 ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
377
379}
Scene * CTX_data_scene(const bContext *C)
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:457
#define SH_NODE_TEX_SKY
bool BKE_scene_uses_blender_eevee(const Scene *scene)
Definition scene.cc:2824
void BKE_texture_mapping_default(struct TexMapping *texmap, int type)
Definition texture.cc:234
void BKE_texture_colormapping_default(struct ColorMapping *colormap)
Definition texture.cc:337
#define DEG2RADF(_deg)
#define M_PI_2
#define M_PI
#define ELEM(...)
#define RPT_(msgid)
#define IFACE_(msgid)
#define GPU_SKY_WIDTH
#define GPU_SKY_HEIGHT
@ SHD_SKY_PREETHAM
@ SHD_SKY_HOSEK
@ SHD_SKY_MULTIPLE_SCATTERING
@ SHD_SKY_SINGLE_SCATTERING
@ SOCK_OUT
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_FLOAT
@ TEXMAP_TYPE_POINT
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
GPUNodeLink * GPU_image_sky(GPUMaterial *mat, int width, int height, const float *pixels, float *layer, GPUSamplerState sampler_state)
GPUNodeLink * GPU_uniform(const float *num)
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
@ GPU_SAMPLER_EXTEND_MODE_EXTEND
@ GPU_SAMPLER_FILTERING_LINEAR
#define C
Definition RandGen.cpp:29
@ UI_ITEM_R_SPLIT_EMPTY_NAME
const T * data() const
Definition BLI_array.hh:312
Vector< SocketDeclaration * > outputs
nullptr float
#define expf(x)
#define fmodf(x, y)
#define acosf(x)
#define copysignf(x, y)
uint col
#define in
#define out
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define T
#define T2
Definition md5.cpp:21
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:4739
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
void node_type_size_preset(bNodeType &ntype, eNodeSizePreset size)
Definition node.cc:5396
static void sky_simplify_multiscatter_elevation_rotation(float &sun_elevation, float &sun_rotation)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void sky_precompute_old(SkyModelPreetham *sunsky, const float sun_angles[], float turbidity)
static void node_shader_init_tex_sky(bNodeTree *, bNode *node)
static int node_shader_gpu_tex_sky(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
static float sky_perez_function(const float *lam, float theta, float gamma)
static void node_declare(NodeDeclarationBuilder &b)
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, Span< SocketDeclaration * > declarations)
color xyz_to_rgb(float x, float y, float z)
Definition node_color.h:73
void register_node_type_sh_tex_sky()
void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *)
void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
void sh_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
#define fabsf
#define tanf
#define cosf
#define atan2f
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
void SKY_arhosekskymodelstate_free(SKY_ArHosekSkyModelState *state)
SKY_ArHosekSkyModelState * SKY_arhosek_xyz_skymodelstate_alloc_init(const double turbidity, const double albedo, const double elevation)
void SKY_multiple_scattering_precompute_texture(float *pixels, int stride, int width, int height, float sun_elevation, float altitude, float air_density, float aerosol_density, float ozone_density)
void SKY_single_scattering_precompute_texture(float *pixels, int stride, int width, int height, float sun_elevation, float altitude, float air_density, float aerosol_density, float ozone_density)
TexMapping tex_mapping
ColorMapping color_mapping
float aerosol_density
NodeTexBase base
float sun_direction[3]
SKY_ArHosekSkyModelConfiguration configs[11]
Definition sky_hosek.h:312
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:281
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238