diff options
Diffstat (limited to 'source/blender/gpu')
-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 |
6 files changed, 146 insertions, 7 deletions
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); + } } |