diff options
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 4 | ||||
-rw-r--r-- | source/blender/gpu/GPU_material.h | 7 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.cc | 4 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 61 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_node_graph.c | 31 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_node_graph.h | 6 | ||||
-rw-r--r-- | source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl | 44 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_color_types.h | 3 | ||||
-rw-r--r-- | source/blender/nodes/shader/CMakeLists.txt | 16 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_sky.cc | 52 |
10 files changed, 218 insertions, 10 deletions
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index c75049508f9..820242720c8 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1631,6 +1631,10 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial /* Color Ramp */ DRW_shgroup_uniform_texture(grp, tex->sampler_name, *tex->colorband); } + else if (tex->sky) { + /* Sky */ + DRW_shgroup_uniform_texture_ex(grp, tex->sampler_name, *tex->sky, tex->sampler_state); + } } GPUUniformBuf *ubo = GPU_material_uniform_buffer_get(material); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 023221543ec..922988bf95a 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -162,6 +162,12 @@ GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct ImageUser *iuser, eGPUSamplerState sampler_state); GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); +GPUNodeLink *GPU_image_sky(GPUMaterial *mat, + int width, + int height, + const float *pixels, + float *layer, + eGPUSamplerState sampler_state); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row); /** @@ -297,6 +303,7 @@ typedef struct GPUMaterialTexture { struct ImageUser iuser; bool iuser_available; struct GPUTexture **colorband; + struct GPUTexture **sky; char sampler_name[32]; /* Name of sampler in GLSL. */ char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */ int users; diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 75e148e0a8f..2241bcf9f9b 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -386,6 +386,10 @@ void GPUCodegen::generate_resources() const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH); } + else if (tex->sky) { + const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); + info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); + } else if (tex->tiled_mapping_name[0] != '\0') { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); info.sampler(slot++, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 75066b21e7b..96809db1587 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -41,12 +41,18 @@ /* Structs */ #define MAX_COLOR_BAND 128 +#define MAX_GPU_SKIES 8 typedef struct GPUColorBandBuilder { float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4]; int current_layer; } GPUColorBandBuilder; +typedef struct GPUSkyBuilder { + float pixels[MAX_GPU_SKIES][GPU_SKY_WIDTH * GPU_SKY_HEIGHT][4]; + int current_layer; +} GPUSkyBuilder; + struct GPUMaterial { /* Contains GPUShader and source code for deferred compilation. * Can be shared between similar material (i.e: sharing same nodetree topology). */ @@ -73,6 +79,10 @@ struct GPUMaterial { GPUTexture *coba_tex; /** Builder for coba_tex. */ GPUColorBandBuilder *coba_builder; + /** 2D Texture array containing all sky textures. */ + GPUTexture *sky_tex; + /** Builder for sky_tex. */ + GPUSkyBuilder *sky_builder; /* Low level node graph(s). Also contains resources needed by the material. */ GPUNodeGraph graph; @@ -98,6 +108,35 @@ struct GPUMaterial { /* Functions */ +GPUTexture **gpu_material_sky_texture_layer_set( + GPUMaterial *mat, int width, int height, const float *pixels, float *row) +{ + /* In order to put all sky textures into one 2D array texture, + * we need them to be the same size. */ + BLI_assert(width == GPU_SKY_WIDTH); + BLI_assert(height == GPU_SKY_HEIGHT); + UNUSED_VARS_NDEBUG(width, height); + + if (mat->sky_builder == NULL) { + mat->sky_builder = MEM_mallocN(sizeof(GPUSkyBuilder), "GPUSkyBuilder"); + mat->sky_builder->current_layer = 0; + } + + int layer = mat->sky_builder->current_layer; + *row = (float)layer; + + if (*row == MAX_GPU_SKIES) { + printf("Too many sky textures in shader!\n"); + } + else { + float *dst = (float *)mat->sky_builder->pixels[layer]; + memcpy(dst, pixels, sizeof(float) * GPU_SKY_WIDTH * GPU_SKY_HEIGHT * 4); + mat->sky_builder->current_layer += 1; + } + + return &mat->sky_tex; +} + GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, @@ -143,6 +182,24 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat) mat->coba_builder = NULL; } +static void gpu_material_sky_texture_build(GPUMaterial *mat) +{ + if (mat->sky_builder == NULL) { + return; + } + + mat->sky_tex = GPU_texture_create_2d_array("mat_sky", + GPU_SKY_WIDTH, + GPU_SKY_HEIGHT, + mat->sky_builder->current_layer, + 1, + GPU_RGBA32F, + (float *)mat->sky_builder->pixels); + + MEM_freeN(mat->sky_builder); + mat->sky_builder = NULL; +} + void GPU_material_free_single(GPUMaterial *material) { bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0; @@ -161,6 +218,9 @@ void GPU_material_free_single(GPUMaterial *material) if (material->coba_tex != NULL) { GPU_texture_free(material->coba_tex); } + if (material->sky_tex != NULL) { + GPU_texture_free(material->sky_tex); + } if (material->sss_profile != NULL) { GPU_uniformbuf_free(material->sss_profile); } @@ -684,6 +744,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, ntreeGPUMaterialNodes(localtree, mat); gpu_material_ramp_texture_build(mat); + gpu_material_sky_texture_build(mat); { /* Create source code and search pass cache for an already compiled version. */ diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index f82af7538b5..a305413905b 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -112,6 +112,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType break; case GPU_NODE_LINK_IMAGE: case GPU_NODE_LINK_IMAGE_TILED: + case GPU_NODE_LINK_IMAGE_SKY: case GPU_NODE_LINK_COLORBAND: input->source = GPU_SOURCE_TEX; input->texture = link->texture; @@ -438,6 +439,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, struct GPUTexture **colorband, + struct GPUTexture **sky, GPUNodeLinkType link_type, eGPUSamplerState sampler_state) { @@ -445,7 +447,8 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, int num_textures = 0; GPUMaterialTexture *tex = graph->textures.first; for (; tex; tex = tex->next) { - if (tex->ima == ima && tex->colorband == colorband && tex->sampler_state == sampler_state) { + if (tex->ima == ima && tex->colorband == colorband && tex->sky == sky && + tex->sampler_state == sampler_state) { break; } num_textures++; @@ -460,6 +463,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, tex->iuser_available = true; } tex->colorband = colorband; + tex->sky = sky; tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); if (ELEM(link_type, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING)) { @@ -580,7 +584,24 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE; link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, NULL, link->link_type, sampler_state); + graph, ima, iuser, NULL, NULL, link->link_type, sampler_state); + return link; +} + +GPUNodeLink *GPU_image_sky(GPUMaterial *mat, + int width, + int height, + const float *pixels, + float *layer, + eGPUSamplerState sampler_state) +{ + struct GPUTexture **sky = gpu_material_sky_texture_layer_set(mat, width, height, pixels, layer); + + GPUNodeGraph *graph = gpu_material_node_graph(mat); + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_IMAGE_SKY; + link->texture = gpu_node_graph_add_texture( + graph, NULL, NULL, NULL, sky, link->link_type, sampler_state); return link; } @@ -593,7 +614,7 @@ GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED; link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, NULL, link->link_type, sampler_state); + graph, ima, iuser, NULL, NULL, link->link_type, sampler_state); return link; } @@ -603,7 +624,7 @@ GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, Image *ima, ImageUser *iu GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING; link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, NULL, link->link_type, GPU_SAMPLER_MAX); + graph, ima, iuser, NULL, NULL, link->link_type, GPU_SAMPLER_MAX); return link; } @@ -616,7 +637,7 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_COLORBAND; link->texture = gpu_node_graph_add_texture( - graph, NULL, NULL, colorband, link->link_type, GPU_SAMPLER_MAX); + graph, NULL, NULL, colorband, NULL, link->link_type, GPU_SAMPLER_MAX); return link; } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 74afb721a1c..085620b30e4 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -47,6 +47,7 @@ typedef enum { GPU_NODE_LINK_IMAGE, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING, + GPU_NODE_LINK_IMAGE_SKY, GPU_NODE_LINK_OUTPUT, GPU_NODE_LINK_UNIFORM, GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN, @@ -197,6 +198,11 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat, int size, float *pixels, float *row); +/** + * Returns the address of the future pointer to sky_tex + */ +struct GPUTexture **gpu_material_sky_texture_layer_set( + struct GPUMaterial *mat, int width, int height, const float *pixels, float *layer); #ifdef __cplusplus } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl index b6aad5904ff..c4b47bc1756 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_sky.glsl @@ -144,7 +144,47 @@ void node_tex_sky_hosekwilkie(vec3 co, color = vec4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1); } -void node_tex_sky_nishita(vec3 co, out vec4 color) +void node_tex_sky_nishita(vec3 co, + float sun_rotation, + vec3 xyz_to_r, + vec3 xyz_to_g, + vec3 xyz_to_b, + sampler2DArray ima, + float layer, + out vec4 color) { - color = vec4(1.0); + vec3 spherical = sky_spherical_coordinates(co); + + vec3 xyz; + if (co.z < -0.4) { + /* too far below the horizon, just return black */ + color = vec4(0, 0, 0, 1); + } + else { + /* evaluate longitudinal position on the map */ + float x = (spherical.y + M_PI + sun_rotation) / M_2PI; + if (x > 1.0) { + x -= 1.0; + } + + float fade; + float y; + if (co.z < 0.0) { + /* we're below the horizon, so extend the map by blending from values at the horizon + * to zero according to a cubic falloff */ + fade = 1.0 + co.z * 2.5; + fade = fade * fade * fade; + y = 0.0; + } + else { + /* we're above the horizon, so compute the lateral position by inverting the remapped + * coordinates that are preserve to have more detail near the horizon. */ + fade = 1.0; + y = sqrt((M_PI_2 - spherical.x) / M_PI_2); + } + + /* look up color in the precomputed map and convert to RGB */ + xyz = fade * texture(ima, vec3(x, y, layer)).rgb; + color = vec4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1); + } } diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 623d1dd6440..4eb64290032 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -21,6 +21,9 @@ extern "C" { #define CM_TOT 4 +#define GPU_SKY_WIDTH 512 +#define GPU_SKY_HEIGHT 128 + typedef struct CurveMapPoint { float x, y; /** Shorty for result lookup. */ diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 7885ad78225..e78bf55d840 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -150,6 +150,22 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${TBB_LIBRARIES} + ) +endif() + blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_UNITY_BUILD) diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc index f5a4d087dbd..97b7f2616ae 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc @@ -4,6 +4,8 @@ #include "node_shader_util.hh" #include "sky_model.h" +#include "BLI_task.hh" + #include "BKE_context.h" #include "BKE_scene.h" @@ -36,7 +38,7 @@ static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA * if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) { Scene *scene = CTX_data_scene(C); if (BKE_scene_uses_blender_eevee(scene)) { - uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR); + uiItemL(layout, TIP_("Sun disc not available in Eevee"), ICON_ERROR); } uiItemR(layout, ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0); @@ -179,7 +181,7 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, GPU_uniform(xyz_to_rgb.g), GPU_uniform(xyz_to_rgb.b)); } - if (tex->sky_model == 1) { + else if (tex->sky_model == 1) { /* Hosek / Wilkie */ sun_angles[0] = fmin(M_PI_2, sun_angles[0]); /* clamp to horizon */ SKY_ArHosekSkyModelState *sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init( @@ -219,8 +221,52 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, GPU_uniform(xyz_to_rgb.g), GPU_uniform(xyz_to_rgb.b)); } + else { + /* Nishita */ + + Array<float> pixels(4 * GPU_SKY_WIDTH * GPU_SKY_HEIGHT); + + threading::parallel_for(IndexRange(GPU_SKY_HEIGHT), 2, [&](IndexRange range) { + SKY_nishita_skymodel_precompute_texture(pixels.data(), + 4, + range.first(), + range.one_after_last(), + GPU_SKY_WIDTH, + GPU_SKY_HEIGHT, + tex->sun_elevation, + tex->altitude, + tex->air_density, + tex->dust_density, + tex->ozone_density); + }); + + float sun_rotation = fmodf(tex->sun_rotation, 2.0f * M_PI); + if (sun_rotation < 0.0f) { + sun_rotation += 2.0f * M_PI; + } + sun_rotation = 2.0f * M_PI - sun_rotation; + + XYZ_to_RGB xyz_to_rgb; + get_XYZ_to_RGB_for_gpu(&xyz_to_rgb); - return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out); + eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_FILTER; + /* To fix pole issue we clamp the v coordinate. */ + sampler &= ~GPU_SAMPLER_REPEAT_T; + float layer; + GPUNodeLink *sky_texture = GPU_image_sky( + mat, GPU_SKY_WIDTH, GPU_SKY_HEIGHT, pixels.data(), &layer, sampler); + return GPU_stack_link(mat, + node, + "node_tex_sky_nishita", + in, + out, + GPU_constant(&sun_rotation), + GPU_uniform(xyz_to_rgb.r), + GPU_uniform(xyz_to_rgb.g), + GPU_uniform(xyz_to_rgb.b), + sky_texture, + GPU_constant(&layer)); + } } static void node_shader_update_sky(bNodeTree *ntree, bNode *node) |