Workbench Simplification Refactor
This patch is (almost) a complete rewrite of workbench engine. The features remain unchanged but the code quality is greatly improved. Hair shading is brighter but also more correct. This also introduce the concept of `DRWShaderLibrary` to make a simple include system inside the GLSL files. Differential Revision: https://developer.blender.org/D7060
This commit is contained in:
@@ -191,10 +191,14 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Direct access. elem is element index inside the chosen chunk. */
|
||||
/* Direct access. elem is element index inside the chosen chunk.
|
||||
* Double usage: You can set chunk to 0 and set the absolute elem index.
|
||||
* The correct chunk will be retrieve. */
|
||||
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
|
||||
{
|
||||
BLI_assert(chunk < mblk->chunk_len);
|
||||
BLI_assert(elem < (mblk->chunk_size / mblk->elem_size));
|
||||
int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
|
||||
chunk += elem / elem_per_chunk;
|
||||
elem = elem % elem_per_chunk;
|
||||
return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
|
||||
}
|
||||
|
||||
@@ -97,19 +97,18 @@ set(SRC
|
||||
engines/eevee/eevee_subsurface.c
|
||||
engines/eevee/eevee_temporal_sampling.c
|
||||
engines/eevee/eevee_volumes.c
|
||||
engines/workbench/solid_mode.c
|
||||
engines/workbench/transparent_mode.c
|
||||
engines/workbench/workbench_data.c
|
||||
engines/workbench/workbench_deferred.c
|
||||
engines/workbench/workbench_effect_aa.c
|
||||
engines/workbench/workbench_effect_antialiasing.c
|
||||
engines/workbench/workbench_effect_cavity.c
|
||||
engines/workbench/workbench_effect_dof.c
|
||||
engines/workbench/workbench_effect_fxaa.c
|
||||
engines/workbench/workbench_effect_taa.c
|
||||
engines/workbench/workbench_effect_outline.c
|
||||
engines/workbench/workbench_engine.c
|
||||
engines/workbench/workbench_forward.c
|
||||
engines/workbench/workbench_materials.c
|
||||
engines/workbench/workbench_opaque.c
|
||||
engines/workbench/workbench_render.c
|
||||
engines/workbench/workbench_studiolight.c
|
||||
engines/workbench/workbench_shader.c
|
||||
engines/workbench/workbench_shadow.c
|
||||
engines/workbench/workbench_transparent.c
|
||||
engines/workbench/workbench_volume.c
|
||||
engines/external/external_engine.c
|
||||
engines/gpencil/gpencil_antialiasing.c
|
||||
@@ -247,28 +246,32 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
|
||||
data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
|
||||
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
|
||||
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
|
||||
|
||||
data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
|
||||
|
||||
@@ -381,9 +381,6 @@ static void OVERLAY_cache_finish(void *vedata)
|
||||
|
||||
DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
|
||||
|
||||
GPU_framebuffer_ensure_config(
|
||||
&dfbl->default_fb,
|
||||
{GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
|
||||
GPU_framebuffer_ensure_config(
|
||||
&dfbl->in_front_fb,
|
||||
{GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
|
||||
|
||||
@@ -68,22 +68,17 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
|
||||
OVERLAY_shader_wireframe();
|
||||
|
||||
for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) {
|
||||
/* Only do stencil test if stencil buffer is written by the render engine. */
|
||||
DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL;
|
||||
DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
|
||||
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
|
||||
DRWPass *pass;
|
||||
uint stencil_mask;
|
||||
|
||||
if (xray == 0) {
|
||||
DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state);
|
||||
DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state);
|
||||
pass = psl->wireframe_ps;
|
||||
stencil_mask = 0xFF;
|
||||
}
|
||||
else {
|
||||
DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state);
|
||||
pass = psl->wireframe_xray_ps;
|
||||
stencil_mask = 0x00;
|
||||
}
|
||||
|
||||
for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
|
||||
@@ -94,17 +89,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
|
||||
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
|
||||
DRW_shgroup_stencil_mask(grp, stencil_mask);
|
||||
|
||||
pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
|
||||
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
|
||||
DRW_shgroup_stencil_mask(grp, stencil_mask);
|
||||
}
|
||||
|
||||
pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
|
||||
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
|
||||
DRW_shgroup_stencil_mask(grp, stencil_mask);
|
||||
}
|
||||
|
||||
if (is_material_shmode) {
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
uniform sampler2D colorBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
uniform usampler2D objectId;
|
||||
|
||||
uniform vec2 invertedViewportSize;
|
||||
uniform mat4 WinMatrix; /* inverse WinMatrix */
|
||||
|
||||
uniform vec4 viewvecs[3];
|
||||
uniform vec4 ssao_params;
|
||||
uniform vec4 ssao_settings;
|
||||
uniform vec2 curvature_settings;
|
||||
uniform sampler2D ssao_jitter;
|
||||
|
||||
layout(std140) uniform samples_block
|
||||
{
|
||||
vec4 ssao_samples[500];
|
||||
};
|
||||
|
||||
#define ssao_samples_num ssao_params.x
|
||||
#define jitter_tilling ssao_params.yz
|
||||
#define ssao_iteration ssao_params.w
|
||||
|
||||
#define ssao_distance ssao_settings.x
|
||||
#define ssao_factor_cavity ssao_settings.y
|
||||
#define ssao_factor_edge ssao_settings.z
|
||||
#define ssao_attenuation ssao_settings.w
|
||||
|
||||
vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
|
||||
{
|
||||
if (WinMatrix[3][3] == 0.0) {
|
||||
/* Perspective */
|
||||
float d = 2.0 * depth - 1.0;
|
||||
|
||||
float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
|
||||
|
||||
return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
|
||||
}
|
||||
else {
|
||||
/* Orthographic */
|
||||
vec3 offset = vec3(uvcoords, depth);
|
||||
|
||||
return viewvecs[0].xyz + offset * viewvecs[1].xyz;
|
||||
}
|
||||
}
|
||||
|
||||
/* forward declaration */
|
||||
void ssao_factors(in float depth,
|
||||
in vec3 normal,
|
||||
in vec3 position,
|
||||
in vec2 screenco,
|
||||
out float cavities,
|
||||
out float edges);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
|
||||
float cavity = 0.0, edges = 0.0, curvature = 0.0;
|
||||
|
||||
#ifdef USE_CAVITY
|
||||
float depth = texelFetch(depthBuffer, texel, 0).x;
|
||||
vec3 position = get_view_space_from_depth(screenco, depth);
|
||||
vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
|
||||
|
||||
ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CURVATURE
|
||||
curvature = calculate_curvature(
|
||||
objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y);
|
||||
#endif
|
||||
|
||||
float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
|
||||
|
||||
/* Using UNORM render target so compress the range. */
|
||||
fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE);
|
||||
}
|
||||
@@ -1,77 +1,87 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
|
||||
/* from The Alchemy screen-space ambient obscurance algorithm
|
||||
layout(std140) uniform samples_block
|
||||
{
|
||||
vec4 samples_coords[512];
|
||||
};
|
||||
|
||||
uniform sampler2D cavityJitter;
|
||||
|
||||
/* From The Alchemy screen-space ambient obscurance algorithm
|
||||
* http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
|
||||
|
||||
void ssao_factors(in float depth,
|
||||
in vec3 normal,
|
||||
in vec3 position,
|
||||
in vec2 screenco,
|
||||
out float cavities,
|
||||
out float edges)
|
||||
void cavity_compute(vec2 screenco,
|
||||
sampler2D depthBuffer,
|
||||
sampler2D normalBuffer,
|
||||
out float cavities,
|
||||
out float edges)
|
||||
{
|
||||
cavities = edges = 0.0;
|
||||
/* early out if there is no need for SSAO */
|
||||
if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0) {
|
||||
|
||||
float depth = texture(depthBuffer, screenco).x;
|
||||
|
||||
/* Early out if background and infront. */
|
||||
if (depth == 1.0 || depth == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* take the normalized ray direction here */
|
||||
vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
|
||||
vec3 position = view_position_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco));
|
||||
|
||||
vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale;
|
||||
vec3 noise = texture(cavityJitter, jitter_co).rgb;
|
||||
|
||||
/* find the offset in screen space by multiplying a point
|
||||
* in camera space at the depth of the point by the projection matrix. */
|
||||
vec2 offset;
|
||||
float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
|
||||
offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
|
||||
offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
|
||||
float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
|
||||
offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord;
|
||||
offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord;
|
||||
/* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
|
||||
offset *= 0.5;
|
||||
|
||||
int num_samples = int(ssao_samples_num);
|
||||
|
||||
/* Note. Putting noise usage here to put some ALU after texture fetch. */
|
||||
vec2 rotX = noise.rg;
|
||||
vec2 rotY = vec2(-rotX.y, rotX.x);
|
||||
|
||||
for (int x = 0; x < num_samples; x++) {
|
||||
int sample_index = x + (int(ssao_iteration) * num_samples);
|
||||
if (sample_index > 500) {
|
||||
continue;
|
||||
}
|
||||
/* ssao_samples[x].xy is sample direction (normalized).
|
||||
* ssao_samples[x].z is sample distance from disk center. */
|
||||
|
||||
int sample_start = world_data.cavity_sample_start;
|
||||
int sample_end = world_data.cavity_sample_end;
|
||||
for (int i = sample_start; i < sample_end && i < 512; i++) {
|
||||
/* sample_coord.xy is sample direction (normalized).
|
||||
* sample_coord.z is sample distance from disk center. */
|
||||
vec3 sample_coord = samples_coords[i].xyz;
|
||||
/* Rotate with random direction to get jittered result. */
|
||||
vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX),
|
||||
dot(ssao_samples[sample_index].xy, rotY));
|
||||
dir_jittered.xy *= ssao_samples[sample_index].z + noise.b;
|
||||
vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY));
|
||||
dir_jittered.xy *= sample_coord.z + noise.b;
|
||||
|
||||
vec2 uvcoords = screenco.xy + dir_jittered * offset;
|
||||
|
||||
if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) {
|
||||
vec2 uvcoords = screenco + dir_jittered * offset;
|
||||
/* Out of screen case. */
|
||||
if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float depth_new = texture(depthBuffer, uvcoords).r;
|
||||
|
||||
/* Sample depth. */
|
||||
float s_depth = texture(depthBuffer, uvcoords).r;
|
||||
/* Handle Background case */
|
||||
bool is_background = (depth_new == 1.0);
|
||||
|
||||
bool is_background = (s_depth == 1.0);
|
||||
/* This trick provide good edge effect even if no neighbor is found. */
|
||||
vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
|
||||
s_depth = (is_background) ? depth : s_depth;
|
||||
vec3 s_pos = view_position_from_depth(
|
||||
uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix);
|
||||
|
||||
if (is_background) {
|
||||
pos_new.z -= ssao_distance;
|
||||
s_pos.z -= world_data.cavity_distance;
|
||||
}
|
||||
|
||||
vec3 dir = pos_new - position;
|
||||
vec3 dir = s_pos - position;
|
||||
float len = length(dir);
|
||||
float f_cavities = dot(dir, normal);
|
||||
float f_edge = -f_cavities;
|
||||
float f_bias = 0.05 * len + 0.0001;
|
||||
|
||||
float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
|
||||
float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation));
|
||||
|
||||
/* use minor bias here to avoid self shadowing */
|
||||
if (f_cavities > -f_bias) {
|
||||
@@ -82,11 +92,10 @@ void ssao_factors(in float depth,
|
||||
edges += f_edge * attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
cavities /= ssao_samples_num;
|
||||
edges /= ssao_samples_num;
|
||||
cavities *= world_data.cavity_sample_count_inv;
|
||||
edges *= world_data.cavity_sample_count_inv;
|
||||
|
||||
/* don't let cavity wash out the surface appearance */
|
||||
cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
|
||||
edges = edges * ssao_factor_edge;
|
||||
cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0);
|
||||
edges = edges * world_data.cavity_ridge_factor;
|
||||
}
|
||||
|
||||
@@ -1,30 +1,16 @@
|
||||
#define NO_OBJECT_ID uint(0)
|
||||
|
||||
#define EPSILON 0.00001
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
#define CAVITY_BUFFER_RANGE 4.0
|
||||
|
||||
/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
|
||||
#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
|
||||
const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)),
|
||||
vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
|
||||
vec4(P(3.0), P(11.0), P(1.0), P(9.0)),
|
||||
vec4(P(15.0), P(7.0), P(13.0), P(5.0)));
|
||||
|
||||
float bayer_dither_noise()
|
||||
{
|
||||
ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
|
||||
ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
|
||||
return dither_mat4x4[tx1.x][tx1.y];
|
||||
}
|
||||
|
||||
#ifdef WORKBENCH_ENCODE_NORMALS
|
||||
|
||||
# define WB_Normal vec2
|
||||
|
||||
/* From http://aras-p.info/texts/CompactNormalStorage.html
|
||||
* Using Method #4: Spheremap Transform */
|
||||
vec3 workbench_normal_decode(WB_Normal enc)
|
||||
vec3 workbench_normal_decode(vec4 enc)
|
||||
{
|
||||
vec2 fenc = enc.xy * 4.0 - 2.0;
|
||||
float f = dot(fenc, fenc);
|
||||
@@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc)
|
||||
|
||||
/* From http://aras-p.info/texts/CompactNormalStorage.html
|
||||
* Using Method #4: Spheremap Transform */
|
||||
WB_Normal workbench_normal_encode(vec3 n)
|
||||
WB_Normal workbench_normal_encode(bool front_face, vec3 n)
|
||||
{
|
||||
n = normalize(front_face ? n : -n);
|
||||
float p = sqrt(n.z * 8.0 + 8.0);
|
||||
n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0);
|
||||
return n.xy;
|
||||
@@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n)
|
||||
#else
|
||||
# define WB_Normal vec3
|
||||
/* Well just do nothing... */
|
||||
# define workbench_normal_encode(a) (a)
|
||||
# define workbench_normal_decode(a) (a)
|
||||
# define workbench_normal_encode(f, a) (a)
|
||||
# define workbench_normal_decode(a) (a.xyz)
|
||||
#endif /* WORKBENCH_ENCODE_NORMALS */
|
||||
|
||||
/* Encoding into the alpha of a RGBA8 UNORM texture. */
|
||||
/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */
|
||||
#define TARGET_BITCOUNT 8u
|
||||
#define METALLIC_BITS 3u /* Metallic channel is less important. */
|
||||
#define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS)
|
||||
#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS)
|
||||
|
||||
/* Encode 2 float into 1 with the desired precision. */
|
||||
float workbench_float_pair_encode(float v1, float v2)
|
||||
{
|
||||
// const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
|
||||
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
|
||||
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
|
||||
/* Same as above because some compiler are dumb af. and think we use mediump int. */
|
||||
const int total_mask = 0xFF;
|
||||
const int v1_mask = 0x1F;
|
||||
const int v2_mask = 0x7;
|
||||
int iv1 = int(v1 * float(v1_mask));
|
||||
int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS);
|
||||
return float(iv1 | iv2) * (1.0 / float(total_mask));
|
||||
return float(iv1 | iv2);
|
||||
}
|
||||
|
||||
void workbench_float_pair_decode(float data, out float v1, out float v2)
|
||||
{
|
||||
// const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS);
|
||||
// const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS);
|
||||
// const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS);
|
||||
/* Same as above because some compiler are dumb af. and think we use mediump int. */
|
||||
const int total_mask = 0xFF;
|
||||
const int v1_mask = 0x1F;
|
||||
const int v2_mask = 0x7;
|
||||
int idata = int(data * float(total_mask));
|
||||
int idata = int(data);
|
||||
v1 = float(idata & v1_mask) * (1.0 / float(v1_mask));
|
||||
v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask));
|
||||
}
|
||||
|
||||
float calculate_transparent_weight(float z, float alpha)
|
||||
{
|
||||
#if 0
|
||||
/* Eq 10 : Good for surfaces with varying opacity (like particles) */
|
||||
float a = min(1.0, alpha * 10.0) + 0.01;
|
||||
float b = -gl_FragCoord.z * 0.95 + 1.0;
|
||||
float w = a * a * a * 3e2 * b * b * b;
|
||||
#else
|
||||
/* Eq 7 put more emphasis on surfaces closer to the view. */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
|
||||
/* Same as eq 7, but optimized. */
|
||||
float a = abs(z) / 5.0;
|
||||
float b = abs(z) / 200.0;
|
||||
b *= b;
|
||||
float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
|
||||
#endif
|
||||
return alpha * clamp(w, 1e-2, 3e2);
|
||||
}
|
||||
|
||||
/* Special function only to be used with calculate_transparent_weight(). */
|
||||
float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
|
||||
{
|
||||
if (proj_mat[3][3] == 0.0) {
|
||||
float d = 2.0 * depth - 1.0;
|
||||
return -proj_mat[3][2] / (d + proj_mat[2][2]);
|
||||
}
|
||||
else {
|
||||
/* Return depth from near plane. */
|
||||
return depth * viewvecs[1].z;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
|
||||
{
|
||||
return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) :
|
||||
vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
|
||||
{
|
||||
/* Quick creation of an orthonormal basis */
|
||||
float a = 1.0 / (1.0 + I.z);
|
||||
float b = -I.x * I.y * a;
|
||||
vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
|
||||
vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
|
||||
vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
|
||||
if (flipped) {
|
||||
matcap_uv.x = -matcap_uv.x;
|
||||
if (proj_mat[3][3] == 0.0) {
|
||||
return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz);
|
||||
}
|
||||
return matcap_uv * 0.496 + 0.5;
|
||||
}
|
||||
|
||||
bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
|
||||
{
|
||||
vec2 tile_pos = floor(co.xy);
|
||||
|
||||
if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
|
||||
return false;
|
||||
|
||||
float tile = 10.0 * tile_pos.y + tile_pos.x;
|
||||
if (tile >= textureSize(map, 0).x)
|
||||
return false;
|
||||
|
||||
/* Fetch tile information. */
|
||||
float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
|
||||
if (tile_layer < 0.0)
|
||||
return false;
|
||||
|
||||
vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
|
||||
|
||||
co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture(sampler2D image,
|
||||
vec2 coord,
|
||||
bool nearest_sampling,
|
||||
bool premultiplied)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(image, 0).xy);
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
|
||||
vec4 color = texture(image, uv);
|
||||
|
||||
/* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
|
||||
if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
|
||||
color.rgb = color.rgb / color.a;
|
||||
else {
|
||||
return vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture_array(sampler2DArray tile_array,
|
||||
sampler1DArray tile_data,
|
||||
vec2 coord,
|
||||
bool nearest_sampling,
|
||||
bool premultiplied)
|
||||
vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
|
||||
if (proj_mat[3][3] == 0.0) {
|
||||
/* Perspective */
|
||||
float d = 2.0 * depth - 1.0;
|
||||
|
||||
vec3 uv = vec3(coord, 0);
|
||||
if (!node_tex_tile_lookup(uv, tile_array, tile_data))
|
||||
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||
float zview = -proj_mat[3][2] / (d + proj_mat[2][2]);
|
||||
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
|
||||
vec4 color = texture(tile_array, uv);
|
||||
|
||||
/* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
|
||||
if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
|
||||
color.rgb = color.rgb / color.a;
|
||||
return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
|
||||
}
|
||||
else {
|
||||
/* Orthographic */
|
||||
vec3 offset = vec3(uvcoords, depth);
|
||||
|
||||
return color;
|
||||
return viewvecs[0].xyz + offset * viewvecs[1].xyz;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
|
||||
|
||||
uniform sampler2D materialBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
|
||||
vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st));
|
||||
vec4 mat_data = texture(materialBuffer, uvcoordsvar.st);
|
||||
|
||||
vec3 base_color = mat_data.rgb;
|
||||
|
||||
float roughness, metallic;
|
||||
workbench_float_pair_decode(mat_data.a, roughness, metallic);
|
||||
|
||||
#ifdef V3D_LIGHTING_MATCAP
|
||||
/* When using matcaps, mat_data.a is the backface sign. */
|
||||
N = (mat_data.a > 0.0) ? N : -N;
|
||||
|
||||
fragColor.rgb = get_matcap_lighting(base_color, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_STUDIO
|
||||
fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_FLAT
|
||||
fragColor.rgb = base_color;
|
||||
#endif
|
||||
|
||||
fragColor.rgb *= get_shadow(N);
|
||||
|
||||
fragColor.a = 1.0;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#ifndef CURVATURE_OFFSET
|
||||
# define CURVATURE_OFFSET 1
|
||||
#endif
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
float curvature_soft_clamp(float curvature, float control)
|
||||
{
|
||||
@@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control)
|
||||
return 0.25 / control;
|
||||
}
|
||||
|
||||
float calculate_curvature(
|
||||
usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley)
|
||||
void curvature_compute(vec2 uv,
|
||||
usampler2D objectIdBuffer,
|
||||
sampler2D normalBuffer,
|
||||
out float curvature)
|
||||
{
|
||||
uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r;
|
||||
uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r;
|
||||
uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r;
|
||||
uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r;
|
||||
curvature = 0.0;
|
||||
|
||||
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
|
||||
uint object_up = texture(objectIdBuffer, uv + offset.zy).r;
|
||||
uint object_down = texture(objectIdBuffer, uv - offset.zy).r;
|
||||
uint object_right = texture(objectIdBuffer, uv + offset.xz).r;
|
||||
uint object_left = texture(objectIdBuffer, uv - offset.xz).r;
|
||||
|
||||
/* Remove object outlines. */
|
||||
if ((object_up != object_down) || (object_right != object_left)) {
|
||||
return 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg;
|
||||
vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg;
|
||||
vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg;
|
||||
vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg;
|
||||
float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g;
|
||||
float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g;
|
||||
float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r;
|
||||
float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r;
|
||||
|
||||
normal_up = workbench_normal_decode(normal_up).rg;
|
||||
normal_down = workbench_normal_decode(normal_down).rg;
|
||||
normal_left = workbench_normal_decode(normal_left).rg;
|
||||
normal_right = workbench_normal_decode(normal_right).rg;
|
||||
|
||||
float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r));
|
||||
float normal_diff = (normal_up - normal_down) + (normal_right - normal_left);
|
||||
|
||||
if (normal_diff < 0) {
|
||||
return -2.0 * curvature_soft_clamp(-normal_diff, valley);
|
||||
curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley);
|
||||
}
|
||||
else {
|
||||
curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge);
|
||||
}
|
||||
|
||||
return 2.0 * curvature_soft_clamp(normal_diff, ridge);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,42 @@ struct LightData {
|
||||
};
|
||||
|
||||
struct WorldData {
|
||||
vec4 viewvecs[3];
|
||||
vec4 viewport_size;
|
||||
vec4 object_outline_color;
|
||||
vec4 shadow_direction_vs;
|
||||
float shadow_focus;
|
||||
float shadow_shift;
|
||||
float shadow_mul;
|
||||
float shadow_add;
|
||||
/* - 16 bytes alignment- */
|
||||
LightData lights[4];
|
||||
vec4 ambient_color;
|
||||
int num_lights;
|
||||
int matcap_orientation;
|
||||
|
||||
int cavity_sample_start;
|
||||
int cavity_sample_end;
|
||||
float cavity_sample_count_inv;
|
||||
float cavity_jitter_scale;
|
||||
|
||||
float cavity_valley_factor;
|
||||
float cavity_ridge_factor;
|
||||
float cavity_attenuation;
|
||||
float cavity_distance;
|
||||
|
||||
float curvature_ridge;
|
||||
float curvature_valley;
|
||||
float ui_scale;
|
||||
float _pad0;
|
||||
|
||||
int matcap_orientation;
|
||||
bool use_specular;
|
||||
int _pad1;
|
||||
int _pad2;
|
||||
};
|
||||
|
||||
#define viewport_size_inv viewport_size.zw
|
||||
|
||||
layout(std140) uniform world_block
|
||||
{
|
||||
WorldData world_data;
|
||||
};
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
uniform usampler2D objectId;
|
||||
|
||||
uniform vec2 invertedViewportSize;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
layout(std140) uniform world_block
|
||||
{
|
||||
WorldData world_data;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
|
||||
|
||||
#ifndef V3D_SHADING_OBJECT_OUTLINE
|
||||
|
||||
fragColor = vec4(0.0);
|
||||
|
||||
#else /* !V3D_SHADING_OBJECT_OUTLINE */
|
||||
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
uint object_id = texelFetch(objectId, texel, 0).r;
|
||||
float object_outline = calculate_object_outline(objectId, texel, object_id);
|
||||
|
||||
fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline);
|
||||
|
||||
#endif /* !V3D_SHADING_OBJECT_OUTLINE */
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform usampler2D objectId;
|
||||
uniform sampler2D materialBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
/* normalBuffer contains viewport normals */
|
||||
uniform sampler2D cavityBuffer;
|
||||
uniform sampler2D matcapDiffuseImage;
|
||||
uniform sampler2D matcapSpecularImage;
|
||||
|
||||
uniform vec2 invertedViewportSize;
|
||||
uniform vec4 viewvecs[3];
|
||||
uniform float shadowMultiplier;
|
||||
uniform float lightMultiplier;
|
||||
uniform float shadowShift = 0.1;
|
||||
uniform float shadowFocus = 1.0;
|
||||
|
||||
uniform vec3 materialSingleColor;
|
||||
|
||||
layout(std140) uniform world_block
|
||||
{
|
||||
WorldData world_data;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
|
||||
|
||||
float roughness, metallic;
|
||||
vec3 base_color;
|
||||
|
||||
#ifndef MATDATA_PASS_ENABLED
|
||||
base_color = materialSingleColor;
|
||||
metallic = 0.0;
|
||||
roughness = 0.5;
|
||||
#else
|
||||
vec4 material_data = texelFetch(materialBuffer, texel, 0);
|
||||
base_color = material_data.rgb;
|
||||
workbench_float_pair_decode(material_data.a, roughness, metallic);
|
||||
#endif
|
||||
|
||||
/* Do we need normals */
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg);
|
||||
#endif
|
||||
|
||||
vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
|
||||
|
||||
/* -------- SHADING --------- */
|
||||
#ifdef V3D_LIGHTING_FLAT
|
||||
vec3 shaded_color = base_color;
|
||||
|
||||
#elif defined(V3D_LIGHTING_MATCAP)
|
||||
/* When using matcaps, the metallic is the backface sign. */
|
||||
normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport;
|
||||
bool flipped = world_data.matcap_orientation != 0;
|
||||
vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
|
||||
vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
|
||||
|
||||
# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
|
||||
vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
|
||||
# else
|
||||
vec3 matcap_specular = vec3(0.0);
|
||||
# endif
|
||||
|
||||
vec3 shaded_color = matcap_diffuse * base_color + matcap_specular;
|
||||
|
||||
#elif defined(V3D_LIGHTING_STUDIO)
|
||||
|
||||
# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
|
||||
vec3 specular_color = mix(vec3(0.05), base_color, metallic);
|
||||
vec3 diffuse_color = mix(base_color, vec3(0.0), metallic);
|
||||
# else
|
||||
roughness = 0.0;
|
||||
vec3 specular_color = vec3(0.0);
|
||||
vec3 diffuse_color = base_color;
|
||||
# endif
|
||||
|
||||
vec3 shaded_color = get_world_lighting(
|
||||
world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs);
|
||||
#endif
|
||||
|
||||
/* -------- POST EFFECTS --------- */
|
||||
#ifdef WB_CAVITY
|
||||
/* Using UNORM texture so decompress the range */
|
||||
shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE;
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_SHADOW
|
||||
float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz);
|
||||
float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
|
||||
shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_OBJECT_OUTLINE
|
||||
uint object_id = texelFetch(objectId, texel, 0).r;
|
||||
float object_outline = calculate_object_outline(objectId, texel, object_id);
|
||||
shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline);
|
||||
#endif
|
||||
|
||||
fragColor = vec4(shaded_color, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl)
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
uniform usampler2D objectIdBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
float cavity = 0.0, edges = 0.0, curvature = 0.0;
|
||||
|
||||
#ifdef USE_CAVITY
|
||||
cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CURVATURE
|
||||
curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature);
|
||||
#endif
|
||||
|
||||
float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
|
||||
|
||||
fragColor.rgb = vec3(final_cavity_factor);
|
||||
fragColor.a = 1.0;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D colorBuffer;
|
||||
uniform vec2 invertedViewportSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
FragColor = FxaaPixelShader(
|
||||
uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
uniform usampler2D objectIdBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
|
||||
vec2 uv = uvcoordsvar.st;
|
||||
|
||||
uint center_id = texture(objectIdBuffer, uv).r;
|
||||
uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r,
|
||||
texture(objectIdBuffer, uv - offset.zy).r,
|
||||
texture(objectIdBuffer, uv + offset.xz).r,
|
||||
texture(objectIdBuffer, uv - offset.xz).r);
|
||||
|
||||
float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25));
|
||||
|
||||
fragColor = world_data.object_outline_color * outline_opacity;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
uniform sampler2D edgesTex;
|
||||
uniform sampler2D areaTex;
|
||||
uniform sampler2D searchTex;
|
||||
uniform sampler2D blendTex;
|
||||
uniform sampler2D colorTex;
|
||||
uniform float mixFactor;
|
||||
uniform float taaSampleCountInv;
|
||||
|
||||
in vec2 uvs;
|
||||
in vec2 pixcoord;
|
||||
in vec4 offset[3];
|
||||
|
||||
#if SMAA_STAGE == 0
|
||||
out vec2 fragColor;
|
||||
#else
|
||||
out vec4 fragColor;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#if SMAA_STAGE == 0
|
||||
/* Detect edges in color and revealage buffer. */
|
||||
fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
|
||||
/* Discard if there is no edge. */
|
||||
if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
#elif SMAA_STAGE == 1
|
||||
fragColor = SMAABlendingWeightCalculationPS(
|
||||
uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
|
||||
|
||||
#elif SMAA_STAGE == 2
|
||||
fragColor = vec4(0.0);
|
||||
if (mixFactor > 0.0) {
|
||||
fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
|
||||
}
|
||||
if (mixFactor < 1.0) {
|
||||
fragColor += texture(colorTex, uvs) * (1.0 - mixFactor);
|
||||
}
|
||||
fragColor *= taaSampleCountInv;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
out vec2 uvs;
|
||||
out vec2 pixcoord;
|
||||
out vec4 offset[3];
|
||||
|
||||
void main()
|
||||
{
|
||||
int v = gl_VertexID % 3;
|
||||
float x = -1.0 + float((v & 1) << 2);
|
||||
float y = -1.0 + float((v & 2) << 1);
|
||||
gl_Position = vec4(x, y, 1.0, 1.0);
|
||||
uvs = (gl_Position.xy + 1.0) * 0.5;
|
||||
|
||||
#if SMAA_STAGE == 0
|
||||
SMAAEdgeDetectionVS(uvs, offset);
|
||||
#elif SMAA_STAGE == 1
|
||||
SMAABlendingWeightCalculationVS(uvs, pixcoord, offset);
|
||||
#elif SMAA_STAGE == 2
|
||||
SMAANeighborhoodBlendingVS(uvs, offset[0]);
|
||||
#endif
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
uniform sampler2D historyBuffer;
|
||||
|
||||
uniform sampler2D colorBuffer;
|
||||
|
||||
out vec4 colorOutput;
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
uniform float mixFactor;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
vec4 color_buffer = texelFetch(colorBuffer, texel, 0);
|
||||
vec4 history_buffer = texelFetch(historyBuffer, texel, 0);
|
||||
colorOutput = mix(history_buffer, color_buffer, mixFactor);
|
||||
fragColor = texture(colorBuffer, uvcoordsvar.st);
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform usampler2D objectId;
|
||||
uniform sampler2D transparentAccum;
|
||||
uniform sampler2D transparentRevealage;
|
||||
uniform vec2 invertedViewportSize;
|
||||
|
||||
#ifndef ALPHA_COMPOSITE
|
||||
layout(std140) uniform world_block
|
||||
{
|
||||
WorldData world_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
|
||||
|
||||
/* Listing 4 */
|
||||
vec4 trans_accum = texelFetch(transparentAccum, texel, 0);
|
||||
float trans_revealage = trans_accum.a;
|
||||
trans_accum.a = texelFetch(transparentRevealage, texel, 0).r;
|
||||
|
||||
vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4);
|
||||
|
||||
fragColor.a = 1.0 - trans_revealage;
|
||||
fragColor.rgb = trans_color * fragColor.a;
|
||||
|
||||
#ifdef V3D_SHADING_OBJECT_OUTLINE
|
||||
uint object_id = texelFetch(objectId, texel, 0).r;
|
||||
float outline = calculate_object_outline(objectId, texel, object_id);
|
||||
fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline);
|
||||
#endif
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
layout(location = 0) out uint objectId;
|
||||
|
||||
uniform float ImageTransparencyCutoff = 0.1;
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
uniform sampler2D image;
|
||||
|
||||
in vec2 uv_interp;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
if (texture(image, uv_interp).a < ImageTransparencyCutoff) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
objectId = uint(resource_id + 1) & 0xFFu;
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
|
||||
uniform float ImageTransparencyCutoff = 0.1;
|
||||
#ifdef TEXTURE_IMAGE_ARRAY
|
||||
uniform sampler2DArray image_tile_array;
|
||||
uniform sampler1DArray image_tile_data;
|
||||
#else
|
||||
uniform sampler2D image;
|
||||
#endif
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremultiplied;
|
||||
|
||||
uniform float alpha = 0.5;
|
||||
uniform vec2 invertedViewportSize;
|
||||
uniform vec4 viewvecs[3];
|
||||
|
||||
uniform vec4 materialColorAndMetal;
|
||||
uniform float materialRoughness;
|
||||
|
||||
uniform float shadowMultiplier = 0.5;
|
||||
uniform float lightMultiplier = 1.0;
|
||||
uniform float shadowShift = 0.1;
|
||||
uniform float shadowFocus = 1.0;
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
in vec3 normal_viewport;
|
||||
#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
in vec2 uv_interp;
|
||||
#endif
|
||||
#ifdef V3D_SHADING_VERTEX_COLOR
|
||||
in vec3 vertexColor;
|
||||
#endif
|
||||
#ifdef V3D_LIGHTING_MATCAP
|
||||
uniform sampler2D matcapDiffuseImage;
|
||||
uniform sampler2D matcapSpecularImage;
|
||||
#endif
|
||||
|
||||
layout(std140) uniform world_block
|
||||
{
|
||||
WorldData world_data;
|
||||
};
|
||||
|
||||
layout(location = 0) out vec4 transparentAccum;
|
||||
layout(location = 1) out
|
||||
float revealageAccum; /* revealage actually stored in transparentAccum.a */
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base_color;
|
||||
|
||||
#if defined(V3D_SHADING_TEXTURE_COLOR)
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
base_color = workbench_sample_texture_array(
|
||||
image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
|
||||
# else
|
||||
base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
|
||||
# endif
|
||||
if (base_color.a < ImageTransparencyCutoff) {
|
||||
discard;
|
||||
}
|
||||
#elif defined(V3D_SHADING_VERTEX_COLOR)
|
||||
base_color.rgb = vertexColor;
|
||||
#else
|
||||
base_color.rgb = materialColorAndMetal.rgb;
|
||||
#endif /* V3D_SHADING_TEXTURE_COLOR */
|
||||
|
||||
vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
|
||||
vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
vec3 nor = normalize(normal_viewport);
|
||||
#endif
|
||||
|
||||
/* -------- SHADING --------- */
|
||||
#ifdef V3D_LIGHTING_FLAT
|
||||
vec3 shaded_color = base_color.rgb;
|
||||
|
||||
#elif defined(V3D_LIGHTING_MATCAP)
|
||||
bool flipped = world_data.matcap_orientation != 0;
|
||||
vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
|
||||
vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb;
|
||||
# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
|
||||
vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb;
|
||||
# else
|
||||
vec3 matcap_specular = vec3(0.0);
|
||||
# endif
|
||||
vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular;
|
||||
|
||||
#elif defined(V3D_LIGHTING_STUDIO)
|
||||
# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
|
||||
float metallic = materialColorAndMetal.a;
|
||||
vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic);
|
||||
vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic);
|
||||
# else
|
||||
vec3 specular_color = vec3(0.0);
|
||||
vec3 diffuse_color = base_color.rgb;
|
||||
# endif
|
||||
|
||||
vec3 shaded_color = get_world_lighting(
|
||||
world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_SHADOW
|
||||
float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz);
|
||||
float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor);
|
||||
shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
|
||||
#endif
|
||||
|
||||
/* Based on :
|
||||
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
|
||||
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
|
||||
*/
|
||||
/* Listing 4 */
|
||||
float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix);
|
||||
float weight = calculate_transparent_weight(z, alpha);
|
||||
transparentAccum = vec4(shaded_color * weight, alpha);
|
||||
revealageAccum = weight;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
uniform sampler2D depthBuffer;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
|
||||
|
||||
/* background, discard */
|
||||
if (depth >= 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
gl_FragDepth = depth;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
/* TODO(fclem) deduplicate code. */
|
||||
bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
|
||||
{
|
||||
vec2 tile_pos = floor(co.xy);
|
||||
|
||||
if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
|
||||
return false;
|
||||
|
||||
float tile = 10.0 * tile_pos.y + tile_pos.x;
|
||||
if (tile >= textureSize(map, 0).x)
|
||||
return false;
|
||||
|
||||
/* Fetch tile information. */
|
||||
float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
|
||||
if (tile_layer < 0.0)
|
||||
return false;
|
||||
|
||||
vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
|
||||
|
||||
co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(image, 0).xy);
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
|
||||
return texture(image, uv);
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture_array(sampler2DArray tile_array,
|
||||
sampler1DArray tile_data,
|
||||
vec2 coord,
|
||||
bool nearest_sampling)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
|
||||
|
||||
vec3 uv = vec3(coord, 0);
|
||||
if (!node_tex_tile_lookup(uv, tile_array, tile_data))
|
||||
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
|
||||
return texture(tile_array, uv);
|
||||
}
|
||||
|
||||
uniform sampler2DArray imageTileArray;
|
||||
uniform sampler1DArray imageTileData;
|
||||
uniform sampler2D imageTexture;
|
||||
|
||||
uniform float imageTransparencyCutoff = 0.1;
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremult;
|
||||
|
||||
vec3 workbench_image_color(vec2 uvs)
|
||||
{
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest);
|
||||
# else
|
||||
vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest);
|
||||
# endif
|
||||
|
||||
/* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
|
||||
if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) {
|
||||
color.rgb /= color.a;
|
||||
}
|
||||
|
||||
# ifdef GPU_FRAGMENT_SHADER
|
||||
if (color.a < imageTransparencyCutoff) {
|
||||
discard;
|
||||
}
|
||||
# endif
|
||||
|
||||
return color.rgb;
|
||||
#else
|
||||
return vec3(1.0);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
|
||||
{
|
||||
/* Quick creation of an orthonormal basis */
|
||||
float a = 1.0 / (1.0 + I.z);
|
||||
float b = -I.x * I.y * a;
|
||||
vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
|
||||
vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
|
||||
vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
|
||||
if (flipped) {
|
||||
matcap_uv.x = -matcap_uv.x;
|
||||
}
|
||||
return matcap_uv * 0.496 + 0.5;
|
||||
}
|
||||
|
||||
uniform sampler2D matcapDiffuseImage;
|
||||
uniform sampler2D matcapSpecularImage;
|
||||
|
||||
vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I)
|
||||
{
|
||||
bool flipped = world_data.matcap_orientation != 0;
|
||||
vec2 uv = matcap_uv_compute(I, N, flipped);
|
||||
|
||||
vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb;
|
||||
vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb;
|
||||
|
||||
return diffuse * base_color + specular * float(world_data.use_specular);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
layout(std140) uniform material_block
|
||||
{
|
||||
vec4 mat_data[4096];
|
||||
};
|
||||
|
||||
/* If set to -1, the resource handle is used instead. */
|
||||
uniform int materialIndex;
|
||||
|
||||
void workbench_material_data_get(
|
||||
int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
|
||||
{
|
||||
handle = (materialIndex != -1) ? materialIndex : handle;
|
||||
vec4 data = mat_data[uint(handle) & 0xFFFu];
|
||||
color = data.rgb;
|
||||
|
||||
uint encoded_data = floatBitsToUint(data.w);
|
||||
alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0);
|
||||
roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0);
|
||||
metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(depthBuffer, uvcoordsvar.st).r;
|
||||
/* Discard background pixels. */
|
||||
if (depth == 1.0) {
|
||||
discard;
|
||||
}
|
||||
/* Make this fragment occlude any fragment that will try to
|
||||
* render over it in the normal passes. */
|
||||
gl_FragDepth = 0.0;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#define OBJECT_OUTLINE_OFFSET 1
|
||||
|
||||
float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id)
|
||||
{
|
||||
uvec4 oid_offset = uvec4(
|
||||
texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r,
|
||||
texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r,
|
||||
texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r,
|
||||
texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r);
|
||||
|
||||
return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25));
|
||||
}
|
||||
@@ -1,92 +1,29 @@
|
||||
|
||||
uniform vec4 materialColorAndMetal;
|
||||
uniform float materialRoughness;
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
|
||||
|
||||
#ifdef TEXTURE_IMAGE_ARRAY
|
||||
uniform sampler2DArray image_tile_array;
|
||||
uniform sampler1DArray image_tile_data;
|
||||
#else
|
||||
uniform sampler2D image;
|
||||
#endif
|
||||
uniform float ImageTransparencyCutoff = 0.1;
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremultiplied;
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
in vec3 normal_viewport;
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
in vec2 uv_interp;
|
||||
#endif
|
||||
#ifdef V3D_SHADING_VERTEX_COLOR
|
||||
in vec3 vertexColor;
|
||||
#endif
|
||||
|
||||
#ifdef HAIR_SHADER
|
||||
flat in float hair_rand;
|
||||
#endif
|
||||
|
||||
#ifdef MATDATA_PASS_ENABLED
|
||||
layout(location = 0) out vec4 materialData;
|
||||
#endif
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
layout(location = 1) out uint objectId;
|
||||
#endif
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
layout(location = 2) out WB_Normal normalViewport;
|
||||
#endif
|
||||
layout(location = 1) out WB_Normal normalData;
|
||||
layout(location = 2) out uint objectId;
|
||||
|
||||
uniform bool useMatcap = false;
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef MATDATA_PASS_ENABLED
|
||||
float metallic, roughness;
|
||||
vec4 color;
|
||||
normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
|
||||
|
||||
# if defined(V3D_SHADING_TEXTURE_COLOR)
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
color = workbench_sample_texture_array(
|
||||
image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
|
||||
# else
|
||||
color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
|
||||
# endif
|
||||
if (color.a < ImageTransparencyCutoff) {
|
||||
discard;
|
||||
materialData = vec4(color_interp, packed_rough_metal);
|
||||
|
||||
objectId = uint(object_id);
|
||||
|
||||
if (useMatcap) {
|
||||
/* For matcaps, save front facing in alpha channel. */
|
||||
materialData.a = float(gl_FrontFacing);
|
||||
}
|
||||
# elif defined(V3D_SHADING_VERTEX_COLOR)
|
||||
color.rgb = vertexColor;
|
||||
# else
|
||||
color.rgb = materialColorAndMetal.rgb;
|
||||
# endif
|
||||
|
||||
# ifdef V3D_LIGHTING_MATCAP
|
||||
/* Encode front facing in metallic channel. */
|
||||
metallic = float(gl_FrontFacing);
|
||||
roughness = 0.0;
|
||||
# else
|
||||
metallic = materialColorAndMetal.a;
|
||||
roughness = materialRoughness;
|
||||
# endif
|
||||
|
||||
# ifdef HAIR_SHADER
|
||||
/* Add some variation to the hairs to avoid uniform look. */
|
||||
float hair_variation = hair_rand * 0.1;
|
||||
color = clamp(color - hair_variation, 0.0, 1.0);
|
||||
metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
|
||||
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
|
||||
# endif
|
||||
|
||||
materialData.rgb = color.rgb;
|
||||
materialData.a = workbench_float_pair_encode(roughness, metallic);
|
||||
#endif /* MATDATA_PASS_ENABLED */
|
||||
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
objectId = uint(resource_id + 1) & 0xFFu;
|
||||
#endif
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
|
||||
n = normalize(n);
|
||||
normalViewport = workbench_normal_encode(n);
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
materialData.rgb = workbench_image_color(uv_interp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
|
||||
|
||||
uniform samplerBuffer ac; /* active color layer */
|
||||
uniform samplerBuffer au; /* active texture layer */
|
||||
|
||||
/* From http://libnoise.sourceforge.net/noisegen/index.html */
|
||||
float integer_noise(int n)
|
||||
{
|
||||
n = (n >> 13) ^ n;
|
||||
int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
|
||||
return (float(nn) / 1073741824.0);
|
||||
}
|
||||
|
||||
vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand)
|
||||
{
|
||||
/* To "simulate" anisotropic shading, randomize hair normal per strand. */
|
||||
vec3 nor = cross(tan, binor);
|
||||
nor = normalize(mix(nor, -tan, rand * 0.1));
|
||||
float cos_theta = (rand * 2.0 - 1.0) * 0.2;
|
||||
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
|
||||
nor = nor * sin_theta + binor * cos_theta;
|
||||
return nor;
|
||||
}
|
||||
|
||||
void workbench_hair_random_material(float rand,
|
||||
inout vec3 color,
|
||||
inout float roughness,
|
||||
inout float metallic)
|
||||
{
|
||||
/* Center noise around 0. */
|
||||
rand -= 0.5;
|
||||
rand *= 0.1;
|
||||
/* Add some variation to the hairs to avoid uniform look. */
|
||||
metallic = clamp(metallic + rand, 0.0, 1.0);
|
||||
roughness = clamp(roughness + rand, 0.0, 1.0);
|
||||
/* Modulate by color intensity to reduce very high contrast when color is dark. */
|
||||
color = clamp(color + rand * (color + 0.05), 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||
float time, thick_time, thickness;
|
||||
vec3 world_pos, tan, binor;
|
||||
hair_get_pos_tan_binor_time(is_persp,
|
||||
ModelMatrixInverse,
|
||||
ViewMatrixInverse[3].xyz,
|
||||
ViewMatrixInverse[2].xyz,
|
||||
world_pos,
|
||||
tan,
|
||||
binor,
|
||||
time,
|
||||
thickness,
|
||||
thick_time);
|
||||
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
float hair_rand = integer_noise(hair_get_strand_id());
|
||||
vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand);
|
||||
|
||||
#ifdef USE_WORLD_CLIP_PLANES
|
||||
world_clip_planes_calc_clip_distance(world_pos);
|
||||
#endif
|
||||
|
||||
uv_interp = hair_get_customdata_vec2(au);
|
||||
|
||||
normal_interp = normalize(normal_world_to_view(nor));
|
||||
|
||||
#ifdef OPAQUE_MATERIAL
|
||||
float metallic, roughness;
|
||||
#endif
|
||||
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
|
||||
|
||||
if (materialIndex == 0) {
|
||||
color_interp = hair_get_customdata_vec3(ac);
|
||||
}
|
||||
|
||||
/* Hairs have lots of layer and can rapidly become the most prominent surface.
|
||||
* So we lower their alpha artificially. */
|
||||
alpha_interp *= 0.3;
|
||||
|
||||
workbench_hair_random_material(hair_rand, color_interp, roughness, metallic);
|
||||
|
||||
#ifdef OPAQUE_MATERIAL
|
||||
packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
|
||||
#endif
|
||||
|
||||
object_id = int((uint(resource_id) + 1u) & 0xFFu);
|
||||
}
|
||||
@@ -1,110 +1,40 @@
|
||||
|
||||
#ifndef HAIR_SHADER
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
|
||||
|
||||
in vec3 pos;
|
||||
in vec3 nor;
|
||||
in vec2 au; /* active texture layer */
|
||||
# ifdef V3D_SHADING_VERTEX_COLOR
|
||||
in vec4 ac; /* active color */
|
||||
# endif
|
||||
# define uv au
|
||||
#else /* HAIR_SHADER */
|
||||
|
||||
# ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
uniform samplerBuffer au; /* active texture layer */
|
||||
# endif
|
||||
# ifdef V3D_SHADING_VERTEX_COLOR
|
||||
uniform samplerBuffer ac; /* active color layer */
|
||||
# endif
|
||||
|
||||
flat out float hair_rand;
|
||||
#endif /* HAIR_SHADER */
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
out vec3 normal_viewport;
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
out vec2 uv_interp;
|
||||
#endif
|
||||
#ifdef V3D_SHADING_VERTEX_COLOR
|
||||
out vec3 vertexColor;
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
RESOURCE_ID_VARYING
|
||||
#endif
|
||||
|
||||
/* From http://libnoise.sourceforge.net/noisegen/index.html */
|
||||
float integer_noise(int n)
|
||||
{
|
||||
n = (n >> 13) ^ n;
|
||||
int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
|
||||
return (float(nn) / 1073741824.0);
|
||||
}
|
||||
|
||||
vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand)
|
||||
{
|
||||
/* To "simulate" anisotropic shading, randomize hair normal per strand. */
|
||||
vec3 nor = cross(tan, binor);
|
||||
nor = normalize(mix(nor, -tan, rand * 0.1));
|
||||
float cos_theta = (rand * 2.0 - 1.0) * 0.2;
|
||||
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
|
||||
nor = nor * sin_theta + binor * cos_theta;
|
||||
return nor;
|
||||
}
|
||||
in vec2 au; /* active texture layer */
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef HAIR_SHADER
|
||||
# ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
vec2 uv = hair_get_customdata_vec2(au);
|
||||
# endif
|
||||
float time, thick_time, thickness;
|
||||
vec3 world_pos, tan, binor;
|
||||
hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
|
||||
ModelMatrixInverse,
|
||||
ViewMatrixInverse[3].xyz,
|
||||
ViewMatrixInverse[2].xyz,
|
||||
world_pos,
|
||||
tan,
|
||||
binor,
|
||||
time,
|
||||
thickness,
|
||||
thick_time);
|
||||
|
||||
hair_rand = integer_noise(hair_get_strand_id());
|
||||
vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand);
|
||||
#else
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
#endif
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
uv_interp = uv;
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_VERTEX_COLOR
|
||||
# ifndef HAIR_SHADER
|
||||
vertexColor = ac.rgb;
|
||||
# else
|
||||
vertexColor = hair_get_customdata_vec4(ac).rgb;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
# ifndef HAIR_SHADER
|
||||
normal_viewport = normal_object_to_view(nor);
|
||||
normal_viewport = normalize(normal_viewport);
|
||||
# else
|
||||
normal_viewport = normal_world_to_view(nor);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
PASS_RESOURCE_ID
|
||||
#endif
|
||||
|
||||
#ifdef USE_WORLD_CLIP_PLANES
|
||||
world_clip_planes_calc_clip_distance(world_pos);
|
||||
#endif
|
||||
|
||||
uv_interp = au;
|
||||
|
||||
normal_interp = normalize(normal_object_to_view(nor));
|
||||
|
||||
#ifdef OPAQUE_MATERIAL
|
||||
float metallic, roughness;
|
||||
#endif
|
||||
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
|
||||
|
||||
if (materialIndex == 0) {
|
||||
color_interp = ac.rgb;
|
||||
}
|
||||
|
||||
#ifdef OPAQUE_MATERIAL
|
||||
packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
|
||||
#endif
|
||||
|
||||
object_id = int((uint(resource_id) + 1u) & 0xFFu);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#ifdef GPU_VERTEX_SHADER
|
||||
# define IN_OUT out
|
||||
#else
|
||||
# define IN_OUT in
|
||||
#endif
|
||||
|
||||
IN_OUT ShaderStageInterface
|
||||
{
|
||||
vec3 normal_interp;
|
||||
vec3 color_interp;
|
||||
float alpha_interp;
|
||||
vec2 uv_interp;
|
||||
#ifdef TRANSPARENT_MATERIAL
|
||||
flat float roughness;
|
||||
flat float metallic;
|
||||
#else
|
||||
flat float packed_rough_metal;
|
||||
#endif
|
||||
flat int object_id;
|
||||
};
|
||||
@@ -1,15 +1,19 @@
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 materialData;
|
||||
layout(location = 1) out vec4 normalData;
|
||||
layout(location = 2) out uint objectId;
|
||||
|
||||
void main()
|
||||
{
|
||||
const float intensity = 0.25;
|
||||
const float a = 0.25;
|
||||
#ifdef SHADOW_PASS
|
||||
fragColor = vec4(
|
||||
(gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0);
|
||||
materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0);
|
||||
#else
|
||||
fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) :
|
||||
vec3(-intensity, -intensity, intensity),
|
||||
1.0);
|
||||
materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a);
|
||||
#endif
|
||||
materialData.a = 0.0;
|
||||
normalData = vec4(0.0);
|
||||
objectId = 0u;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
|
||||
|
||||
/* Revealage is actually stored in transparentAccum alpha channel.
|
||||
* This is a workaround to older hardware not having separate blend equation per render target. */
|
||||
layout(location = 0) out vec4 transparentAccum;
|
||||
layout(location = 1) out vec4 revealageAccum;
|
||||
|
||||
/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */
|
||||
layout(location = 2) out uint objectId;
|
||||
|
||||
/* Special function only to be used with calculate_transparent_weight(). */
|
||||
float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
|
||||
{
|
||||
if (proj_mat[3][3] == 0.0) {
|
||||
float d = 2.0 * depth - 1.0;
|
||||
return -proj_mat[3][2] / (d + proj_mat[2][2]);
|
||||
}
|
||||
else {
|
||||
/* Return depth from near plane. */
|
||||
return depth * viewvecs[1].z;
|
||||
}
|
||||
}
|
||||
|
||||
/* Based on :
|
||||
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
|
||||
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
|
||||
*/
|
||||
float calculate_transparent_weight(void)
|
||||
{
|
||||
float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix);
|
||||
#if 0
|
||||
/* Eq 10 : Good for surfaces with varying opacity (like particles) */
|
||||
float a = min(1.0, alpha * 10.0) + 0.01;
|
||||
float b = -gl_FragCoord.z * 0.95 + 1.0;
|
||||
float w = a * a * a * 3e2 * b * b * b;
|
||||
#else
|
||||
/* Eq 7 put more emphasis on surfaces closer to the view. */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
|
||||
/* Same as eq 7, but optimized. */
|
||||
float a = abs(z) / 5.0;
|
||||
float b = abs(z) / 200.0;
|
||||
b *= b;
|
||||
float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
|
||||
#endif
|
||||
return clamp(w, 1e-2, 3e2);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
|
||||
vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv;
|
||||
vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 N = normalize(normal_interp);
|
||||
|
||||
vec3 color = color_interp;
|
||||
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
color = workbench_image_color(uv_interp);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_MATCAP
|
||||
vec3 shaded_color = get_matcap_lighting(color, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_STUDIO
|
||||
vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_FLAT
|
||||
vec3 shaded_color = color;
|
||||
#endif
|
||||
|
||||
shaded_color *= get_shadow(N);
|
||||
|
||||
/* Listing 4 */
|
||||
float weight = calculate_transparent_weight() * alpha_interp;
|
||||
transparentAccum = vec4(shaded_color * weight, alpha_interp);
|
||||
revealageAccum = vec4(weight);
|
||||
|
||||
objectId = uint(object_id);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
uniform sampler2D transparentAccum;
|
||||
uniform sampler2D transparentRevealage;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
/* Based on :
|
||||
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
|
||||
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Revealage is actually stored in transparentAccum alpha channel.
|
||||
* This is a workaround to older hardware not having separate blend equation per render target.
|
||||
*/
|
||||
vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
|
||||
float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
|
||||
float trans_reveal = trans_accum.a;
|
||||
|
||||
/* Listing 4 */
|
||||
fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4);
|
||||
fragColor.a = 1.0 - trans_reveal;
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
|
||||
uniform sampler3D densityTexture;
|
||||
@@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture;
|
||||
uniform sampler1D transferTexture;
|
||||
|
||||
uniform int samplesLen = 256;
|
||||
uniform float noiseOfs = 0.0f;
|
||||
uniform float noiseOfs = 0.0;
|
||||
uniform float stepLength; /* Step length in local space. */
|
||||
uniform float densityScale; /* Simple Opacity multiplicator. */
|
||||
uniform vec4 viewvecs[3];
|
||||
uniform vec3 activeColor;
|
||||
|
||||
uniform float slicePosition;
|
||||
@@ -23,34 +27,11 @@ in vec3 localPos;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
#define M_PI 3.1415926535897932 /* pi */
|
||||
|
||||
float phase_function_isotropic()
|
||||
{
|
||||
return 1.0 / (4.0 * M_PI);
|
||||
}
|
||||
|
||||
float get_view_z_from_depth(float depth)
|
||||
{
|
||||
if (ProjectionMatrix[3][3] == 0.0) {
|
||||
float d = 2.0 * depth - 1.0;
|
||||
return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
|
||||
}
|
||||
else {
|
||||
return viewvecs[0].z + depth * viewvecs[1].z;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
|
||||
{
|
||||
if (ProjectionMatrix[3][3] == 0.0) {
|
||||
return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth);
|
||||
}
|
||||
else {
|
||||
return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
|
||||
}
|
||||
}
|
||||
|
||||
float max_v3(vec3 v)
|
||||
{
|
||||
return max(v.x, max(v.y, v.z));
|
||||
@@ -209,8 +190,10 @@ void main()
|
||||
|
||||
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
|
||||
float depth_end = min(depth, gl_FragCoord.z);
|
||||
vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end);
|
||||
vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0);
|
||||
vec3 vs_ray_end = view_position_from_depth(
|
||||
screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 vs_ray_ori = view_position_from_depth(
|
||||
screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0);
|
||||
vs_ray_dir /= abs(vs_ray_dir.z);
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
|
||||
|
||||
uniform float slicePosition;
|
||||
uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
/* [Drobot2014a] Low Level Optimizations for GCN */
|
||||
vec4 fast_rcp(vec4 v)
|
||||
{
|
||||
@@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w)
|
||||
return clamp((NL + w) * denom, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 get_world_lighting(
|
||||
WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I)
|
||||
vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
|
||||
{
|
||||
vec3 specular_color, diffuse_color;
|
||||
|
||||
if (world_data.use_specular) {
|
||||
diffuse_color = mix(base_color, vec3(0.0), metallic);
|
||||
specular_color = mix(vec3(0.05), base_color, metallic);
|
||||
}
|
||||
else {
|
||||
diffuse_color = base_color;
|
||||
specular_color = vec3(0.0);
|
||||
}
|
||||
|
||||
vec3 specular_light = world_data.ambient_color.rgb;
|
||||
vec3 diffuse_light = world_data.ambient_color.rgb;
|
||||
vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a,
|
||||
@@ -51,37 +63,37 @@ vec3 get_world_lighting(
|
||||
world_data.lights[2].diffuse_color_wrap.a,
|
||||
world_data.lights[3].diffuse_color_wrap.a);
|
||||
|
||||
#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
|
||||
/* Prepare Specular computation. Eval 4 lights at once. */
|
||||
vec3 R = -reflect(I, N);
|
||||
vec4 spec_angle, spec_NL, wrap_NL;
|
||||
prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
|
||||
prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
|
||||
prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
|
||||
prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
|
||||
if (world_data.use_specular) {
|
||||
/* Prepare Specular computation. Eval 4 lights at once. */
|
||||
vec3 R = -reflect(I, N);
|
||||
vec4 spec_angle, spec_NL, wrap_NL;
|
||||
prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
|
||||
prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
|
||||
prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
|
||||
prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
|
||||
|
||||
vec4 gloss = vec4(1.0 - roughness);
|
||||
/* Reduce gloss for smooth light. (simulate bigger light) */
|
||||
gloss *= 1.0 - wrap;
|
||||
vec4 shininess = exp2(10.0 * gloss + 1.0);
|
||||
vec4 gloss = vec4(1.0 - roughness);
|
||||
/* Reduce gloss for smooth light. (simulate bigger light) */
|
||||
gloss *= 1.0 - wrap;
|
||||
vec4 shininess = exp2(10.0 * gloss + 1.0);
|
||||
|
||||
vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
|
||||
vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
|
||||
|
||||
/* Simulate Env. light. */
|
||||
vec4 w = mix(wrap, vec4(1.0), roughness);
|
||||
vec4 spec_env = wrapped_lighting(wrap_NL, w);
|
||||
/* Simulate Env. light. */
|
||||
vec4 w = mix(wrap, vec4(1.0), roughness);
|
||||
vec4 spec_env = wrapped_lighting(wrap_NL, w);
|
||||
|
||||
spec_light = mix(spec_light, spec_env, wrap * wrap);
|
||||
spec_light = mix(spec_light, spec_env, wrap * wrap);
|
||||
|
||||
/* Multiply result by lights specular colors. */
|
||||
specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
|
||||
specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
|
||||
specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
|
||||
specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
|
||||
/* Multiply result by lights specular colors. */
|
||||
specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
|
||||
specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
|
||||
specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
|
||||
specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
|
||||
|
||||
float NV = clamp(dot(N, I), 0.0, 1.0);
|
||||
specular_color = brdf_approx(specular_color, roughness, NV);
|
||||
#endif
|
||||
float NV = clamp(dot(N, I), 0.0, 1.0);
|
||||
specular_color = brdf_approx(specular_color, roughness, NV);
|
||||
}
|
||||
specular_light *= specular_color;
|
||||
|
||||
/* Prepare diffuse computation. Eval 4 lights at once. */
|
||||
@@ -107,3 +119,13 @@ vec3 get_world_lighting(
|
||||
|
||||
return diffuse_light + specular_light;
|
||||
}
|
||||
|
||||
uniform bool forceShadowing = false;
|
||||
|
||||
float get_shadow(vec3 N)
|
||||
{
|
||||
float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
|
||||
float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
|
||||
shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
|
||||
return shadow_mix + world_data.shadow_add;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Simple engine for drawing color and/or depth.
|
||||
* When we only need simple studio shaders.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
/* Functions */
|
||||
|
||||
static void workbench_solid_engine_init(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_deferred_engine_init(data);
|
||||
}
|
||||
|
||||
static void workbench_solid_cache_init(void *vedata)
|
||||
{
|
||||
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_deferred_cache_init(data);
|
||||
}
|
||||
|
||||
static void workbench_solid_cache_populate(void *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_deferred_solid_cache_populate(data, ob);
|
||||
}
|
||||
|
||||
static void workbench_solid_cache_finish(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_deferred_cache_finish(data);
|
||||
}
|
||||
|
||||
static void workbench_solid_draw_scene(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
const int num_samples = workbench_num_viewport_rendering_iterations(data);
|
||||
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
workbench_deferred_draw_scene(data);
|
||||
}
|
||||
workbench_deferred_draw_finish(data);
|
||||
}
|
||||
|
||||
static void workbench_solid_engine_free(void)
|
||||
{
|
||||
workbench_deferred_engine_free();
|
||||
}
|
||||
|
||||
static void workbench_solid_view_update(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_taa_view_updated(data);
|
||||
}
|
||||
|
||||
static void workbench_solid_id_update(void *UNUSED(vedata), struct ID *id)
|
||||
{
|
||||
if (GS(id->name) == ID_OB) {
|
||||
WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(
|
||||
id, &draw_engine_workbench_solid);
|
||||
if (oed != NULL && oed->dd.recalc != 0) {
|
||||
oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0;
|
||||
oed->dd.recalc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_render_to_image(void *vedata,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
{
|
||||
workbench_render(vedata, engine, render_layer, rect);
|
||||
}
|
||||
|
||||
static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
|
||||
|
||||
DrawEngineType draw_engine_workbench_solid = {
|
||||
NULL,
|
||||
NULL,
|
||||
N_("Workbench"),
|
||||
&workbench_data_size,
|
||||
&workbench_solid_engine_init,
|
||||
&workbench_solid_engine_free,
|
||||
&workbench_solid_cache_init,
|
||||
&workbench_solid_cache_populate,
|
||||
&workbench_solid_cache_finish,
|
||||
&workbench_solid_draw_scene,
|
||||
&workbench_solid_view_update,
|
||||
&workbench_solid_id_update,
|
||||
&workbench_render_to_image,
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Simple engine for drawing color and/or depth.
|
||||
* When we only need simple studio shaders.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
/* Functions */
|
||||
|
||||
static void workbench_transparent_engine_init(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_forward_engine_init(data);
|
||||
}
|
||||
|
||||
static void workbench_transparent_cache_init(void *vedata)
|
||||
{
|
||||
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_forward_cache_init(data);
|
||||
}
|
||||
|
||||
static void workbench_transparent_cache_populate(void *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_forward_cache_populate(data, ob);
|
||||
}
|
||||
|
||||
static void workbench_transparent_cache_finish(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_forward_cache_finish(data);
|
||||
}
|
||||
|
||||
static void workbench_transparent_draw_scene(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
const int num_samples = workbench_num_viewport_rendering_iterations(data);
|
||||
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
workbench_forward_draw_scene(data);
|
||||
}
|
||||
workbench_forward_draw_finish(data);
|
||||
}
|
||||
|
||||
static void workbench_transparent_engine_free(void)
|
||||
{
|
||||
workbench_forward_engine_free();
|
||||
}
|
||||
|
||||
static void workbench_transparent_view_update(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_taa_view_updated(data);
|
||||
}
|
||||
|
||||
static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
|
||||
|
||||
DrawEngineType draw_engine_workbench_transparent = {
|
||||
NULL,
|
||||
NULL,
|
||||
N_("Workbench"),
|
||||
&workbench_data_size,
|
||||
&workbench_transparent_engine_init,
|
||||
&workbench_transparent_engine_free,
|
||||
&workbench_transparent_cache_init,
|
||||
&workbench_transparent_cache_populate,
|
||||
&workbench_transparent_cache_finish,
|
||||
&workbench_transparent_draw_scene,
|
||||
&workbench_transparent_view_update,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
@@ -22,133 +22,231 @@
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
#include "BLI_memblock.h"
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "GPU_batch.h"
|
||||
#include "GPU_uniformbuffer.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name World Data
|
||||
* \{ */
|
||||
|
||||
static void workbench_world_data_free(DrawData *dd)
|
||||
GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd;
|
||||
DRW_UBO_FREE_SAFE(data->world_ubo);
|
||||
struct GPUUniformBuffer **ubo = BLI_memblock_alloc(wpd->material_ubo);
|
||||
if (*ubo == NULL) {
|
||||
*ubo = GPU_uniformbuffer_create(sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL, NULL, NULL);
|
||||
}
|
||||
return *ubo;
|
||||
}
|
||||
|
||||
/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData
|
||||
*
|
||||
* See T70167: Some platforms create threads to upload ubo's.
|
||||
*
|
||||
* Reuses the last previous created `world_ubo`. Due to limitations of
|
||||
* DrawData it will only be reused when there is a world attached to the Scene.
|
||||
* Future development: The best location would be to store it in the View3D.
|
||||
*
|
||||
* We don't cache the data itself as there was no indication that that lead to
|
||||
* an improvement.
|
||||
*
|
||||
* This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must
|
||||
* be respected.
|
||||
*/
|
||||
static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd)
|
||||
static void workbench_ubo_free(void *elem)
|
||||
{
|
||||
World *world = scene->world;
|
||||
if (world) {
|
||||
WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure(
|
||||
&world->id,
|
||||
&draw_engine_workbench_solid,
|
||||
sizeof(WORKBENCH_WorldData),
|
||||
NULL,
|
||||
&workbench_world_data_free);
|
||||
|
||||
if (engine_world_data->world_ubo == NULL) {
|
||||
engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World),
|
||||
&wpd->world_data);
|
||||
}
|
||||
else {
|
||||
DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data);
|
||||
}
|
||||
|
||||
/* Borrow world data ubo */
|
||||
wpd->is_world_ubo_owner = false;
|
||||
wpd->world_ubo = engine_world_data->world_ubo;
|
||||
}
|
||||
else {
|
||||
/* there is no world so we cannot cache the UBO. */
|
||||
BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner);
|
||||
if (!wpd->world_ubo) {
|
||||
wpd->is_world_ubo_owner = true;
|
||||
wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
|
||||
}
|
||||
}
|
||||
GPUUniformBuffer **ubo = elem;
|
||||
DRW_UBO_FREE_SAFE(*ubo);
|
||||
}
|
||||
|
||||
static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd)
|
||||
static void workbench_view_layer_data_free(void *storage)
|
||||
{
|
||||
WORKBENCH_UBO_World *wd = &wpd->world_data;
|
||||
float light_direction[3];
|
||||
float view_matrix[4][4];
|
||||
DRW_view_viewmat_get(NULL, view_matrix, false);
|
||||
WORKBENCH_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage;
|
||||
|
||||
workbench_private_data_get_light_direction(light_direction);
|
||||
DRW_UBO_FREE_SAFE(vldata->dof_sample_ubo);
|
||||
DRW_UBO_FREE_SAFE(vldata->world_ubo);
|
||||
DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo);
|
||||
DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx);
|
||||
|
||||
/* Shadow direction. */
|
||||
mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction);
|
||||
BLI_memblock_destroy(vldata->material_ubo_data, NULL);
|
||||
BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free);
|
||||
}
|
||||
|
||||
static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewLayer *view_layer)
|
||||
{
|
||||
WORKBENCH_ViewLayerData **vldata = (WORKBENCH_ViewLayerData **)
|
||||
DRW_view_layer_engine_data_ensure_ex(view_layer,
|
||||
(DrawEngineType *)&workbench_view_layer_data_ensure_ex,
|
||||
&workbench_view_layer_data_free);
|
||||
|
||||
if (*vldata == NULL) {
|
||||
*vldata = MEM_callocN(sizeof(**vldata), "WORKBENCH_ViewLayerData");
|
||||
size_t matbuf_size = sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL;
|
||||
(*vldata)->material_ubo_data = BLI_memblock_create_ex(matbuf_size, matbuf_size * 2);
|
||||
(*vldata)->material_ubo = BLI_memblock_create_ex(sizeof(void *), sizeof(void *) * 8);
|
||||
(*vldata)->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL);
|
||||
}
|
||||
|
||||
return *vldata;
|
||||
}
|
||||
|
||||
/* \} */
|
||||
|
||||
void workbench_clear_color_get(float color[4])
|
||||
static void workbench_viewvecs_update(float r_viewvecs[3][4])
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
float invproj[4][4];
|
||||
const bool is_persp = DRW_view_is_persp_get(NULL);
|
||||
DRW_view_winmat_get(NULL, invproj, true);
|
||||
|
||||
if (!DRW_state_is_scene_render() || !DRW_state_draw_background()) {
|
||||
zero_v4(color);
|
||||
/* view vectors for the corners of the view frustum.
|
||||
* Can be used to recreate the world space position easily */
|
||||
copy_v4_fl4(r_viewvecs[0], -1.0f, -1.0f, -1.0f, 1.0f);
|
||||
copy_v4_fl4(r_viewvecs[1], 1.0f, -1.0f, -1.0f, 1.0f);
|
||||
copy_v4_fl4(r_viewvecs[2], -1.0f, 1.0f, -1.0f, 1.0f);
|
||||
|
||||
/* convert the view vectors to view space */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mul_m4_v4(invproj, r_viewvecs[i]);
|
||||
/* normalized trick see:
|
||||
* http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
|
||||
mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][3]);
|
||||
if (is_persp) {
|
||||
mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][2]);
|
||||
}
|
||||
r_viewvecs[i][3] = 1.0;
|
||||
}
|
||||
else if (scene->world) {
|
||||
copy_v3_v3(color, &scene->world->horr);
|
||||
color[3] = 1.0f;
|
||||
}
|
||||
else {
|
||||
zero_v3(color);
|
||||
color[3] = 1.0f;
|
||||
|
||||
/* we need to store the differences */
|
||||
r_viewvecs[1][0] -= r_viewvecs[0][0];
|
||||
r_viewvecs[1][1] = r_viewvecs[2][1] - r_viewvecs[0][1];
|
||||
|
||||
/* calculate a depth offset as well */
|
||||
if (!is_persp) {
|
||||
float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
|
||||
mul_m4_v4(invproj, vec_far);
|
||||
mul_v3_fl(vec_far, 1.0f / vec_far[3]);
|
||||
r_viewvecs[1][2] = vec_far[2] - r_viewvecs[0][2];
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info)
|
||||
static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
|
||||
{
|
||||
effect_info->jitter_index = 0;
|
||||
effect_info->view_updated = true;
|
||||
StudioLight *studiolight = wpd->studio_light;
|
||||
float view_matrix[4][4], rot_matrix[4][4];
|
||||
DRW_view_viewmat_get(NULL, view_matrix, false);
|
||||
|
||||
if (USE_WORLD_ORIENTATION(wpd)) {
|
||||
axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
|
||||
mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
|
||||
swap_v3_v3(rot_matrix[2], rot_matrix[1]);
|
||||
negate_v3(rot_matrix[2]);
|
||||
}
|
||||
else {
|
||||
unit_m4(rot_matrix);
|
||||
}
|
||||
|
||||
if (U.edit_studio_light) {
|
||||
studiolight = BKE_studiolight_studio_edit_get();
|
||||
}
|
||||
|
||||
/* Studio Lights. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WORKBENCH_UBO_Light *light = &wd->lights[i];
|
||||
|
||||
SolidLight *sl = (studiolight) ? &studiolight->light[i] : NULL;
|
||||
if (sl && sl->flag) {
|
||||
copy_v3_v3(light->light_direction, sl->vec);
|
||||
mul_mat3_m4_v3(rot_matrix, light->light_direction);
|
||||
/* We should predivide the power by PI but that makes the lights really dim. */
|
||||
copy_v3_v3(light->specular_color, sl->spec);
|
||||
copy_v3_v3(light->diffuse_color, sl->col);
|
||||
light->wrapped = sl->smooth;
|
||||
}
|
||||
else {
|
||||
copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
|
||||
copy_v3_fl(light->specular_color, 0.0f);
|
||||
copy_v3_fl(light->diffuse_color, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (studiolight) {
|
||||
copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(wd->ambient_color, 1.0f);
|
||||
}
|
||||
|
||||
wd->use_specular = workbench_is_specular_highlight_enabled(wpd);
|
||||
}
|
||||
|
||||
void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
wpd->material_hash = BLI_ghash_ptr_new(__func__);
|
||||
wpd->material_transp_hash = BLI_ghash_ptr_new(__func__);
|
||||
wpd->preferences = &U;
|
||||
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
Scene *scene = draw_ctx->scene;
|
||||
WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
|
||||
|
||||
wpd->is_playback = DRW_state_is_playback();
|
||||
wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
|
||||
|
||||
wpd->ctx_mode = CTX_data_mode_enum_ex(
|
||||
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
|
||||
|
||||
wpd->preferences = &U;
|
||||
wpd->scene = scene;
|
||||
wpd->sh_cfg = draw_ctx->sh_cfg;
|
||||
wpd->clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
|
||||
wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
|
||||
wpd->vldata = vldata;
|
||||
wpd->world_ubo = vldata->world_ubo;
|
||||
|
||||
wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd);
|
||||
|
||||
wpd->volumes_do = false;
|
||||
BLI_listbase_clear(&wpd->smoke_domains);
|
||||
|
||||
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
|
||||
/* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
|
||||
* But this is a workaround for a missing update tagging from operators. */
|
||||
if (scene->display.shading.type != wpd->shading.type ||
|
||||
XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) {
|
||||
wpd->view_updated = true;
|
||||
}
|
||||
|
||||
wpd->shading = scene->display.shading;
|
||||
wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
|
||||
wpd->use_color_render_settings = true;
|
||||
if (XRAY_FLAG_ENABLED((&scene->display))) {
|
||||
wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
|
||||
}
|
||||
else {
|
||||
wpd->shading.xray_alpha = 1.0f;
|
||||
}
|
||||
|
||||
if (scene->r.alphamode == R_ALPHAPREMUL) {
|
||||
copy_v4_fl(wpd->background_color, 0.0f);
|
||||
}
|
||||
else if (scene->world) {
|
||||
World *wo = scene->world;
|
||||
copy_v4_fl4(wpd->background_color, wo->horr, wo->horg, wo->horb, 1.0f);
|
||||
}
|
||||
else {
|
||||
copy_v4_fl4(wpd->background_color, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wpd->shading = v3d->shading;
|
||||
wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
|
||||
wpd->use_color_render_settings = false;
|
||||
}
|
||||
/* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
|
||||
* But this is a workaround for a missing update tagging from operators. */
|
||||
if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd)) {
|
||||
wpd->view_updated = true;
|
||||
}
|
||||
|
||||
wpd->use_color_management = BKE_scene_check_color_management_enabled(scene);
|
||||
wpd->shading = v3d->shading;
|
||||
if (wpd->shading.type < OB_SOLID) {
|
||||
wpd->shading.xray_alpha = 0.0f;
|
||||
}
|
||||
else if (XRAY_ENABLED(v3d)) {
|
||||
wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
|
||||
}
|
||||
else {
|
||||
wpd->shading.xray_alpha = 1.0f;
|
||||
}
|
||||
|
||||
/* No background. The overlays will draw the correct one. */
|
||||
copy_v4_fl(wpd->background_color, 0.0f);
|
||||
}
|
||||
|
||||
if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
|
||||
wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
|
||||
@@ -162,119 +260,56 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
|
||||
wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO);
|
||||
}
|
||||
|
||||
float shadow_focus = scene->display.shadow_focus;
|
||||
/* Clamp to avoid overshadowing and shading errors. */
|
||||
CLAMP(shadow_focus, 0.0001f, 0.99999f);
|
||||
wpd->shadow_shift = scene->display.shadow_shift;
|
||||
wpd->shadow_focus = 1.0f - shadow_focus * (1.0f - wpd->shadow_shift);
|
||||
wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity;
|
||||
|
||||
WORKBENCH_UBO_World *wd = &wpd->world_data;
|
||||
wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
|
||||
|
||||
studiolight_update_world(wpd, wpd->studio_light, wd);
|
||||
|
||||
copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color);
|
||||
wd->object_outline_color[3] = 1.0f;
|
||||
|
||||
wd->curvature_ridge = 0.5f / max_ff(square_f(wpd->shading.curvature_ridge_factor), 1e-4f);
|
||||
wd->curvature_valley = 0.7f / max_ff(square_f(wpd->shading.curvature_valley_factor), 1e-4f);
|
||||
|
||||
/* Will be NULL when rendering. */
|
||||
if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
|
||||
wpd->world_clip_planes = rv3d->clip;
|
||||
}
|
||||
else {
|
||||
wpd->world_clip_planes = NULL;
|
||||
}
|
||||
|
||||
workbench_world_data_update_shadow_direction_vs(wpd);
|
||||
workbench_world_data_ubo_ensure(scene, wpd);
|
||||
|
||||
/* Cavity settings */
|
||||
{
|
||||
const int ssao_samples = scene->display.matcap_ssao_samples;
|
||||
|
||||
float invproj[4][4];
|
||||
const bool is_persp = DRW_view_is_persp_get(NULL);
|
||||
/* view vectors for the corners of the view frustum.
|
||||
* Can be used to recreate the world space position easily */
|
||||
float viewvecs[3][4] = {
|
||||
{-1.0f, -1.0f, -1.0f, 1.0f},
|
||||
{1.0f, -1.0f, -1.0f, 1.0f},
|
||||
{-1.0f, 1.0f, -1.0f, 1.0f},
|
||||
};
|
||||
int i;
|
||||
const float *size = DRW_viewport_size_get();
|
||||
|
||||
wpd->ssao_params[0] = ssao_samples;
|
||||
wpd->ssao_params[1] = size[0] / 64.0;
|
||||
wpd->ssao_params[2] = size[1] / 64.0;
|
||||
wpd->ssao_params[3] = 0;
|
||||
|
||||
/* distance, factor, factor, attenuation */
|
||||
copy_v4_fl4(wpd->ssao_settings,
|
||||
scene->display.matcap_ssao_distance,
|
||||
wpd->shading.cavity_valley_factor,
|
||||
wpd->shading.cavity_ridge_factor,
|
||||
scene->display.matcap_ssao_attenuation);
|
||||
|
||||
DRW_view_winmat_get(NULL, wpd->winmat, false);
|
||||
DRW_view_winmat_get(NULL, invproj, true);
|
||||
|
||||
/* convert the view vectors to view space */
|
||||
for (i = 0; i < 3; i++) {
|
||||
mul_m4_v4(invproj, viewvecs[i]);
|
||||
/* normalized trick see:
|
||||
* http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
|
||||
mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
|
||||
if (is_persp) {
|
||||
mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
|
||||
}
|
||||
viewvecs[i][3] = 1.0;
|
||||
|
||||
copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
|
||||
}
|
||||
|
||||
/* we need to store the differences */
|
||||
wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
|
||||
wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1];
|
||||
|
||||
/* calculate a depth offset as well */
|
||||
if (!is_persp) {
|
||||
float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
|
||||
mul_m4_v4(invproj, vec_far);
|
||||
mul_v3_fl(vec_far, 1.0f / vec_far[3]);
|
||||
wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
|
||||
}
|
||||
/* Material UBOs. */
|
||||
wpd->material_ubo_data = vldata->material_ubo_data;
|
||||
wpd->material_ubo = vldata->material_ubo;
|
||||
wpd->material_chunk_count = 1;
|
||||
wpd->material_chunk_curr = 0;
|
||||
wpd->material_index = 1;
|
||||
/* Create default material ubo. */
|
||||
wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
|
||||
wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
|
||||
/* Init default material used by vertex color & texture. */
|
||||
workbench_material_ubo_data(
|
||||
wpd, NULL, NULL, &wpd->material_ubo_data_curr[0], V3D_SHADING_MATERIAL_COLOR);
|
||||
}
|
||||
|
||||
wpd->volumes_do = false;
|
||||
BLI_listbase_clear(&wpd->smoke_domains);
|
||||
}
|
||||
|
||||
void workbench_private_data_get_light_direction(float r_light_direction[3])
|
||||
void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
WORKBENCH_UBO_World wd;
|
||||
|
||||
copy_v2_v2(wd.viewport_size, DRW_viewport_size_get());
|
||||
copy_v2_v2(wd.viewport_size_inv, DRW_viewport_invert_size_get());
|
||||
copy_v3_v3(wd.object_outline_color, wpd->shading.object_outline_color);
|
||||
wd.object_outline_color[3] = 1.0f;
|
||||
wd.ui_scale = G_draw.block.sizePixel;
|
||||
wd.matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
|
||||
|
||||
workbench_studiolight_data_update(wpd, &wd);
|
||||
workbench_shadow_data_update(wpd, &wd);
|
||||
workbench_cavity_data_update(wpd, &wd);
|
||||
workbench_viewvecs_update(wd.viewvecs);
|
||||
|
||||
DRW_uniformbuffer_update(wpd->world_ubo, &wd);
|
||||
}
|
||||
|
||||
void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd))
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
|
||||
|
||||
copy_v3_v3(r_light_direction, scene->display.light_direction);
|
||||
SWAP(float, r_light_direction[2], r_light_direction[1]);
|
||||
r_light_direction[2] = -r_light_direction[2];
|
||||
r_light_direction[0] = -r_light_direction[0];
|
||||
}
|
||||
|
||||
void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
|
||||
BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN);
|
||||
|
||||
if (wpd->is_world_ubo_owner) {
|
||||
DRW_UBO_FREE_SAFE(wpd->world_ubo);
|
||||
}
|
||||
else {
|
||||
wpd->world_ubo = NULL;
|
||||
BLI_memblock_iter iter, iter_data;
|
||||
BLI_memblock_iternew(vldata->material_ubo, &iter);
|
||||
BLI_memblock_iternew(vldata->material_ubo_data, &iter_data);
|
||||
WORKBENCH_UBO_Material *matchunk;
|
||||
while ((matchunk = BLI_memblock_iterstep(&iter_data))) {
|
||||
GPUUniformBuffer **ubo = BLI_memblock_iterstep(&iter);
|
||||
BLI_assert(*ubo != NULL);
|
||||
GPU_uniformbuffer_update(*ubo, matchunk);
|
||||
}
|
||||
|
||||
DRW_UBO_FREE_SAFE(wpd->dof_ubo);
|
||||
BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free);
|
||||
BLI_memblock_clear(vldata->material_ubo_data, NULL);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "draw_color_management.h"
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
||||
if (draw_ctx->evil_C != NULL) {
|
||||
struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
|
||||
wpd->is_playback = ED_screen_animation_playing(wm) != NULL;
|
||||
}
|
||||
else {
|
||||
wpd->is_playback = false;
|
||||
}
|
||||
|
||||
if (workbench_is_taa_enabled(wpd)) {
|
||||
psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
|
||||
}
|
||||
else if (workbench_is_fxaa_enabled(wpd)) {
|
||||
psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
|
||||
effect_info->jitter_index = 0;
|
||||
}
|
||||
else {
|
||||
psl->effect_aa_pass = NULL;
|
||||
effect_info->jitter_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd))
|
||||
{
|
||||
DRW_transform_none(tx);
|
||||
}
|
||||
|
||||
void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
if (workbench_is_fxaa_enabled(wpd)) {
|
||||
GPU_framebuffer_bind(fbl->effect_fb);
|
||||
workspace_aa_draw_transform(tx, wpd);
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->effect_aa_pass);
|
||||
}
|
||||
else if (workbench_is_taa_enabled(wpd)) {
|
||||
/*
|
||||
* when drawing the first TAA frame, we transform directly to the
|
||||
* color_only_fb as the TAA shader is just performing a direct copy.
|
||||
* the workbench_taa_draw_screen_end will fill the history buffer
|
||||
* for the other iterations.
|
||||
*/
|
||||
if (effect_info->jitter_index == 1) {
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
workspace_aa_draw_transform(tx, wpd);
|
||||
}
|
||||
else {
|
||||
GPU_framebuffer_bind(fbl->effect_fb);
|
||||
workspace_aa_draw_transform(tx, wpd);
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->effect_aa_pass);
|
||||
}
|
||||
workbench_taa_draw_scene_end(vedata);
|
||||
}
|
||||
else {
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
workspace_aa_draw_transform(tx, wpd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Anti-aliasing:
|
||||
*
|
||||
* We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution.
|
||||
*
|
||||
* If the viewport stays static, the engine ask for multiple redraw and will progressively
|
||||
* converge to a much more accurate image without aliasing.
|
||||
* We call this one TAA (Temporal Anti-Aliasing).
|
||||
*
|
||||
* This is done using an accumulation buffer and a final pass that will output the final color
|
||||
* to the scene buffer. We softly blend between SMAA and TAA to avoid really harsh transitions.
|
||||
*/
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "BLI_jitter_2d.h"
|
||||
|
||||
#include "smaa_textures.h"
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
static struct {
|
||||
bool init;
|
||||
float jitter_5[5][2];
|
||||
float jitter_8[8][2];
|
||||
float jitter_11[11][2];
|
||||
float jitter_16[16][2];
|
||||
float jitter_32[32][2];
|
||||
} e_data = {false};
|
||||
|
||||
static void workbench_taa_jitter_init_order(float (*table)[2], int num)
|
||||
{
|
||||
BLI_jitter_init(table, num);
|
||||
|
||||
/* find closest element to center */
|
||||
int closest_index = 0;
|
||||
float closest_squared_distance = 1.0f;
|
||||
|
||||
for (int index = 0; index < num; index++) {
|
||||
const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]);
|
||||
if (squared_dist < closest_squared_distance) {
|
||||
closest_squared_distance = squared_dist;
|
||||
closest_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
/* move jitter table so that closest sample is in center */
|
||||
for (int index = 0; index < num; index++) {
|
||||
sub_v2_v2(table[index], table[closest_index]);
|
||||
mul_v2_fl(table[index], 2.0f);
|
||||
}
|
||||
|
||||
/* swap center sample to the start of the table */
|
||||
if (closest_index != 0) {
|
||||
swap_v2_v2(table[0], table[closest_index]);
|
||||
}
|
||||
|
||||
/* sort list based on furtest distance with previous */
|
||||
for (int i = 0; i < num - 2; i++) {
|
||||
float f_squared_dist = 0.0;
|
||||
int f_index = i;
|
||||
for (int j = i + 1; j < num; j++) {
|
||||
const float squared_dist = square_f(table[i][0] - table[j][0]) +
|
||||
square_f(table[i][1] - table[j][1]);
|
||||
if (squared_dist > f_squared_dist) {
|
||||
f_squared_dist = squared_dist;
|
||||
f_index = j;
|
||||
}
|
||||
}
|
||||
swap_v2_v2(table[i + 1], table[f_index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_taa_jitter_init(void)
|
||||
{
|
||||
if (e_data.init == false) {
|
||||
e_data.init = true;
|
||||
workbench_taa_jitter_init_order(e_data.jitter_5, 5);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_8, 8);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_11, 11);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_16, 16);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_32, 32);
|
||||
}
|
||||
}
|
||||
|
||||
int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
|
||||
if (wpd->is_navigating || wpd->is_playback) {
|
||||
/* Only draw using SMAA or no AA when navigating. */
|
||||
return min_ii(wpd->preferences->viewport_aa, 1);
|
||||
}
|
||||
else if (DRW_state_is_image_render()) {
|
||||
if (draw_ctx->v3d) {
|
||||
return scene->display.viewport_aa;
|
||||
}
|
||||
else {
|
||||
return scene->display.render_aa;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return wpd->preferences->viewport_aa;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
if (stl && stl->wpd) {
|
||||
stl->wpd->view_updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
DrawEngineType *owner = (DrawEngineType *)&workbench_antialiasing_engine_init;
|
||||
|
||||
wpd->view = NULL;
|
||||
|
||||
/* reset complete drawing when navigating. */
|
||||
if (wpd->taa_sample != 0) {
|
||||
if (wpd->is_navigating) {
|
||||
wpd->taa_sample = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (wpd->view_updated) {
|
||||
wpd->taa_sample = 0;
|
||||
wpd->view_updated = false;
|
||||
}
|
||||
|
||||
{
|
||||
float persmat[4][4];
|
||||
DRW_view_persmat_get(NULL, persmat, false);
|
||||
if (!equals_m4m4(persmat, wpd->last_mat)) {
|
||||
copy_m4_m4(wpd->last_mat, persmat);
|
||||
wpd->taa_sample = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (wpd->taa_sample_len > 0) {
|
||||
workbench_taa_jitter_init();
|
||||
|
||||
DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, DRW_TEX_FILTER);
|
||||
DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
|
||||
|
||||
wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner);
|
||||
wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner);
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->antialiasing_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
|
||||
});
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx),
|
||||
});
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx),
|
||||
});
|
||||
|
||||
/* TODO could be shared for all viewports. */
|
||||
if (txl->smaa_search_tx == NULL) {
|
||||
txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
|
||||
SEARCHTEX_HEIGHT,
|
||||
0,
|
||||
2,
|
||||
searchTexBytes,
|
||||
GPU_R8,
|
||||
GPU_DATA_UNSIGNED_BYTE,
|
||||
0,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
|
||||
AREATEX_HEIGHT,
|
||||
0,
|
||||
2,
|
||||
areaTexBytes,
|
||||
GPU_RG8,
|
||||
GPU_DATA_UNSIGNED_BYTE,
|
||||
0,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
GPU_texture_bind(txl->smaa_search_tx, 0);
|
||||
GPU_texture_filter_mode(txl->smaa_search_tx, true);
|
||||
GPU_texture_unbind(txl->smaa_search_tx);
|
||||
|
||||
GPU_texture_bind(txl->smaa_area_tx, 0);
|
||||
GPU_texture_filter_mode(txl->smaa_area_tx, true);
|
||||
GPU_texture_unbind(txl->smaa_area_tx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Cleanup */
|
||||
DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx);
|
||||
DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx);
|
||||
DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx);
|
||||
DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
DRWShadingGroup *grp = NULL;
|
||||
|
||||
if (wpd->taa_sample_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
|
||||
|
||||
GPUShader *shader = workbench_shader_antialiasing_accumulation_get();
|
||||
grp = DRW_shgroup_create(shader, psl->aa_accum_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
|
||||
const float *size = DRW_viewport_size_get();
|
||||
const float *sizeinv = DRW_viewport_invert_size_get();
|
||||
float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
|
||||
|
||||
{
|
||||
/* Stage 1: Edge detection. */
|
||||
DRW_PASS_CREATE(psl->aa_edge_ps, DRW_STATE_WRITE_COLOR);
|
||||
|
||||
GPUShader *sh = workbench_shader_antialiasing_get(0);
|
||||
grp = DRW_shgroup_create(sh, psl->aa_edge_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
|
||||
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
|
||||
|
||||
DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
/* Stage 2: Blend Weight/Coord. */
|
||||
DRW_PASS_CREATE(psl->aa_weight_ps, DRW_STATE_WRITE_COLOR);
|
||||
|
||||
GPUShader *sh = workbench_shader_antialiasing_get(1);
|
||||
grp = DRW_shgroup_create(sh, psl->aa_weight_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
|
||||
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
|
||||
|
||||
DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
/* Stage 3: Resolve. */
|
||||
DRW_PASS_CREATE(psl->aa_resolve_ps, DRW_STATE_WRITE_COLOR);
|
||||
|
||||
GPUShader *sh = workbench_shader_antialiasing_get(2);
|
||||
grp = DRW_shgroup_create(sh, psl->aa_resolve_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
|
||||
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
|
||||
DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1);
|
||||
DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1);
|
||||
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if render is not cached. */
|
||||
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
|
||||
if (wpd->taa_sample_len == 0) {
|
||||
/* AA disabled. */
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wpd->taa_sample >= wpd->taa_sample_len) {
|
||||
/* TAA accumulation has finish. Just copy the result back */
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
const DRWView *default_view = DRW_view_default_get();
|
||||
float *transform_offset;
|
||||
|
||||
switch (wpd->taa_sample_len) {
|
||||
default:
|
||||
case 5:
|
||||
transform_offset = e_data.jitter_5[min_ii(wpd->taa_sample, 5)];
|
||||
break;
|
||||
case 8:
|
||||
transform_offset = e_data.jitter_8[min_ii(wpd->taa_sample, 8)];
|
||||
break;
|
||||
case 11:
|
||||
transform_offset = e_data.jitter_11[min_ii(wpd->taa_sample, 11)];
|
||||
break;
|
||||
case 16:
|
||||
transform_offset = e_data.jitter_16[min_ii(wpd->taa_sample, 16)];
|
||||
break;
|
||||
case 32:
|
||||
transform_offset = e_data.jitter_32[min_ii(wpd->taa_sample, 32)];
|
||||
break;
|
||||
}
|
||||
|
||||
/* construct new matrices from transform delta */
|
||||
float winmat[4][4], viewmat[4][4], persmat[4][4];
|
||||
DRW_view_winmat_get(default_view, winmat, false);
|
||||
DRW_view_viewmat_get(default_view, viewmat, false);
|
||||
DRW_view_persmat_get(default_view, persmat, false);
|
||||
|
||||
window_translate_m4(winmat,
|
||||
persmat,
|
||||
transform_offset[0] / viewport_size[0],
|
||||
transform_offset[1] / viewport_size[1]);
|
||||
|
||||
if (wpd->view) {
|
||||
/* When rendering just update the view. This avoids recomputing the culling. */
|
||||
DRW_view_update_sub(wpd->view, viewmat, winmat);
|
||||
}
|
||||
else {
|
||||
/* TAA is not making a big change to the matrices.
|
||||
* Reuse the main view culling by creating a subview. */
|
||||
wpd->view = DRW_view_create_sub(default_view, viewmat, winmat);
|
||||
}
|
||||
DRW_view_set_active(wpd->view);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (wpd->taa_sample_len == 0) {
|
||||
/* AA disabled. */
|
||||
/* Just set sample to 1 to avoid rendering indefinitely. */
|
||||
wpd->taa_sample = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already
|
||||
* high. This ensure a smoother transition.
|
||||
* If TAA accumulation is finished, we only blit the result.
|
||||
*/
|
||||
|
||||
if (wpd->taa_sample == 0) {
|
||||
/* In playback mode, we are sure the next redraw will not use the same viewmatrix.
|
||||
* In this case no need to save the depth buffer. */
|
||||
eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0);
|
||||
GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits);
|
||||
}
|
||||
else {
|
||||
/* Accumulate result to the TAA buffer. */
|
||||
GPU_framebuffer_bind(fbl->antialiasing_fb);
|
||||
DRW_draw_pass(psl->aa_accum_ps);
|
||||
/* Copy back the saved depth buffer for correct overlays. */
|
||||
GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
|
||||
}
|
||||
|
||||
if (!DRW_state_is_image_render() || wpd->taa_sample + 1 == wpd->taa_sample_len) {
|
||||
/* After a certain point SMAA is no longer necessary. */
|
||||
wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f);
|
||||
wpd->taa_sample_inv = 1.0f / (wpd->taa_sample + 1);
|
||||
|
||||
if (wpd->smaa_mix_factor > 0.0f) {
|
||||
GPU_framebuffer_bind(fbl->smaa_edge_fb);
|
||||
DRW_draw_pass(psl->aa_edge_ps);
|
||||
|
||||
GPU_framebuffer_bind(fbl->smaa_weight_fb);
|
||||
DRW_draw_pass(psl->aa_weight_ps);
|
||||
}
|
||||
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
DRW_draw_pass(psl->aa_resolve_ps);
|
||||
}
|
||||
|
||||
wpd->taa_sample++;
|
||||
|
||||
if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) {
|
||||
DRW_viewport_request_redraw();
|
||||
}
|
||||
}
|
||||
182
source/blender/draw/engines/workbench/workbench_effect_cavity.c
Normal file
182
source/blender/draw/engines/workbench/workbench_effect_cavity.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Cavity Effect:
|
||||
*
|
||||
* We use Screen Space Ambient Occlusion (SSAO) to enhance geometric details of the surfaces.
|
||||
* We also use a Curvature effect computed only using the surface normals.
|
||||
*
|
||||
* This is done after the opaque pass. It only affects the opaque surfaces.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BLI_rand.h"
|
||||
|
||||
#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
#define JITTER_TEX_SIZE 64
|
||||
#define CAVITY_MAX_SAMPLES 512
|
||||
|
||||
/* Using Hammersley distribution */
|
||||
static float *create_disk_samples(int num_samples, int num_iterations)
|
||||
{
|
||||
const int total_samples = num_samples * num_iterations;
|
||||
const float num_samples_inv = 1.0f / num_samples;
|
||||
/* vec4 to ensure memory alignment. */
|
||||
float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__);
|
||||
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
float it_add = (i / num_samples) * 0.499f;
|
||||
float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
|
||||
double dphi;
|
||||
BLI_hammersley_1d(i, &dphi);
|
||||
|
||||
float phi = (float)dphi * 2.0f * M_PI + it_add;
|
||||
texels[i][0] = cosf(phi);
|
||||
texels[i][1] = sinf(phi);
|
||||
/* This deliberately distribute more samples
|
||||
* at the center of the disk (and thus the shadow). */
|
||||
texels[i][2] = r;
|
||||
}
|
||||
|
||||
return (float *)texels;
|
||||
}
|
||||
|
||||
static struct GPUTexture *create_jitter_texture(int num_samples)
|
||||
{
|
||||
float jitter[64 * 64][4];
|
||||
const float num_samples_inv = 1.0f / num_samples;
|
||||
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
float phi = blue_noise[i][0] * 2.0f * M_PI;
|
||||
/* This rotate the sample per pixels */
|
||||
jitter[i][0] = cosf(phi);
|
||||
jitter[i][1] = sinf(phi);
|
||||
/* This offset the sample along it's direction axis (reduce banding) */
|
||||
float bn = blue_noise[i][1] - 0.5f;
|
||||
CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
|
||||
jitter[i][2] = bn * num_samples_inv;
|
||||
jitter[i][3] = blue_noise[i][1];
|
||||
}
|
||||
|
||||
UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
|
||||
|
||||
return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]);
|
||||
}
|
||||
|
||||
BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd,
|
||||
const Scene *scene)
|
||||
{
|
||||
return min_ii(max_ii(1, wpd->taa_sample_len) * scene->display.matcap_ssao_samples,
|
||||
CAVITY_MAX_SAMPLES);
|
||||
}
|
||||
|
||||
void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
|
||||
{
|
||||
View3DShading *shading = &wpd->shading;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
|
||||
if (CAVITY_ENABLED(wpd)) {
|
||||
int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
|
||||
int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene);
|
||||
int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
|
||||
|
||||
int sample = wpd->taa_sample % max_iter_count;
|
||||
wd->cavity_sample_start = cavity_sample_count_single_iteration * sample;
|
||||
wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1);
|
||||
|
||||
wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start);
|
||||
wd->cavity_jitter_scale = 1.0f / 64.0f;
|
||||
|
||||
wd->cavity_valley_factor = shading->cavity_valley_factor;
|
||||
wd->cavity_ridge_factor = shading->cavity_ridge_factor;
|
||||
wd->cavity_attenuation = scene->display.matcap_ssao_attenuation;
|
||||
wd->cavity_distance = scene->display.matcap_ssao_distance;
|
||||
|
||||
wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f);
|
||||
wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
|
||||
int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
|
||||
int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene);
|
||||
|
||||
if (wpd->vldata->cavity_sample_count != cavity_sample_count) {
|
||||
DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo);
|
||||
DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx);
|
||||
}
|
||||
|
||||
if (wpd->vldata->cavity_sample_ubo == NULL) {
|
||||
float *samples = create_disk_samples(cavity_sample_count_single_iteration,
|
||||
max_ii(1, wpd->taa_sample_len));
|
||||
wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count);
|
||||
/* NOTE: Uniform buffer needs to always be filled to be valid. */
|
||||
wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create(
|
||||
sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples);
|
||||
wpd->vldata->cavity_sample_count = cavity_sample_count;
|
||||
MEM_freeN(samples);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_cavity_cache_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
if (CAVITY_ENABLED(wpd)) {
|
||||
workbench_cavity_samples_ubo_ensure(wpd);
|
||||
|
||||
int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
|
||||
DRW_PASS_CREATE(psl->cavity_ps, state);
|
||||
|
||||
sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
|
||||
|
||||
grp = DRW_shgroup_create(sh, psl->cavity_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
|
||||
DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
|
||||
|
||||
if (SSAO_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
|
||||
DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx);
|
||||
}
|
||||
if (CURVATURE_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
|
||||
}
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
else {
|
||||
psl->cavity_ps = NULL;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,17 @@
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Depth of Field Effect:
|
||||
*
|
||||
* We use a gather approach by sampling a lowres version of the color buffer.
|
||||
* The process can be summarized like this:
|
||||
* - downsample the color buffer using a COC (Circle of Confusion) aware downsample algo.
|
||||
* - do a gather pass using the COC computed in the previous pass.
|
||||
* - do a median filter to reduce noise amount.
|
||||
* - composite on top of main color buffer.
|
||||
*
|
||||
* This is done after all passes and affects every surfaces.
|
||||
*/
|
||||
|
||||
#include "workbench_private.h"
|
||||
@@ -27,24 +38,6 @@
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
|
||||
/* *********** STATIC *********** */
|
||||
static struct {
|
||||
struct GPUShader *effect_dof_prepare_sh;
|
||||
struct GPUShader *effect_dof_downsample_sh;
|
||||
struct GPUShader *effect_dof_flatten_v_sh;
|
||||
struct GPUShader *effect_dof_flatten_h_sh;
|
||||
struct GPUShader *effect_dof_dilate_v_sh;
|
||||
struct GPUShader *effect_dof_dilate_h_sh;
|
||||
struct GPUShader *effect_dof_blur1_sh;
|
||||
struct GPUShader *effect_dof_blur2_sh;
|
||||
struct GPUShader *effect_dof_resolve_sh;
|
||||
} e_data = {NULL};
|
||||
|
||||
/* Shaders */
|
||||
extern char datatoc_workbench_effect_dof_frag_glsl[];
|
||||
|
||||
/* *********** Functions *********** */
|
||||
|
||||
/**
|
||||
* Transform [-1..1] square to unit circle.
|
||||
*/
|
||||
@@ -130,52 +123,40 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
|
||||
DRW_uniformbuffer_update(*ubo, *data);
|
||||
}
|
||||
|
||||
void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
|
||||
void workbench_dof_engine_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
Scene *scene = draw_ctx->scene;
|
||||
Object *camera;
|
||||
|
||||
if (v3d && rv3d) {
|
||||
camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
|
||||
}
|
||||
else {
|
||||
camera = scene->camera;
|
||||
}
|
||||
|
||||
Camera *cam = camera != NULL ? camera->data : NULL;
|
||||
if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) ||
|
||||
((cam->dof.flag & CAM_DOF_ENABLED) == 0)) {
|
||||
wpd->dof_enabled = false;
|
||||
|
||||
/* Cleanup. */
|
||||
DRW_TEXTURE_FREE_SAFE(txl->dof_source_tx);
|
||||
DRW_TEXTURE_FREE_SAFE(txl->coc_halfres_tx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e_data.effect_dof_prepare_sh == NULL) {
|
||||
e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n");
|
||||
|
||||
e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n");
|
||||
|
||||
e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n");
|
||||
|
||||
e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n");
|
||||
|
||||
e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n");
|
||||
|
||||
e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n");
|
||||
|
||||
e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n");
|
||||
|
||||
e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n");
|
||||
|
||||
e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n");
|
||||
}
|
||||
|
||||
const float *full_size = DRW_viewport_size_get();
|
||||
int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)};
|
||||
#if 0
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimisation */
|
||||
/* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */
|
||||
int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
|
||||
int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
|
||||
@@ -186,14 +167,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
|
||||
DRW_texture_ensure_2d(
|
||||
&txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
|
||||
wpd->dof_blur_tx = DRW_texture_pool_query_2d(
|
||||
size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
|
||||
#if 0
|
||||
size[0], size[1], GPU_RGBA16F, &draw_engine_workbench);
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimisation */
|
||||
wpd->coc_temp_tx = DRW_texture_pool_query_2d(
|
||||
shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
|
||||
shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench);
|
||||
wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d(
|
||||
shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
|
||||
shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
|
||||
wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d(
|
||||
shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
|
||||
shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench);
|
||||
#endif
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb,
|
||||
@@ -202,7 +183,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
|
||||
GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx),
|
||||
});
|
||||
#if 0
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimisation */
|
||||
GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
@@ -231,11 +212,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
|
||||
});
|
||||
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
|
||||
/* Parameters */
|
||||
/* TODO UI Options */
|
||||
float fstop = cam->dof.aperture_fstop;
|
||||
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
|
||||
float focus_dist = BKE_camera_object_dof_distance(camera);
|
||||
@@ -263,128 +240,125 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
|
||||
float rotation = cam->dof.aperture_rotation;
|
||||
float ratio = 1.0f / cam->dof.aperture_ratio;
|
||||
|
||||
if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation ||
|
||||
ratio != wpd->dof_ratio) {
|
||||
if (wpd->vldata->dof_sample_ubo == NULL || blades != wpd->dof_blades ||
|
||||
rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) {
|
||||
wpd->dof_blades = blades;
|
||||
wpd->dof_rotation = rotation;
|
||||
wpd->dof_ratio = ratio;
|
||||
workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
|
||||
workbench_dof_setup_samples(
|
||||
&wpd->vldata->dof_sample_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
|
||||
}
|
||||
}
|
||||
|
||||
wpd->dof_enabled = true;
|
||||
}
|
||||
|
||||
void workbench_dof_create_pass(WORKBENCH_Data *vedata,
|
||||
GPUTexture **dof_input,
|
||||
GPUTexture *noise_tex)
|
||||
void workbench_dof_cache_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
|
||||
if (!wpd->dof_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *prepare_sh, *downsample_sh, *blur1_sh, *blur2_sh, *resolve_sh;
|
||||
workbench_shader_depth_of_field_get(
|
||||
&prepare_sh, &downsample_sh, &blur1_sh, &blur2_sh, &resolve_sh);
|
||||
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
|
||||
psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
|
||||
psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
|
||||
DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
|
||||
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
|
||||
psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(prepare_sh, psl->dof_down_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "sceneColorTex", dtxl->color);
|
||||
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
|
||||
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps);
|
||||
psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(downsample_sh, psl->dof_down2_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
#if 0
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimization */
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh,
|
||||
psl->dof_flatten_h_ps);
|
||||
psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(flatten_h_sh, psl->dof_flatten_h_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh,
|
||||
psl->dof_flatten_v_ps);
|
||||
psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(flatten_v_sh, psl->dof_flatten_v_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
|
||||
psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(dilate_v_sh, psl->dof_dilate_v_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
|
||||
psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(dilate_h_sh, psl->dof_dilate_h_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
float offset = stl->effects->jitter_index /
|
||||
(float)workbench_taa_calculate_num_iterations(vedata);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
|
||||
DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo);
|
||||
DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex);
|
||||
psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
/* We reuse the same noise texture. Ensure it is up to date. */
|
||||
workbench_cavity_samples_ubo_ensure(wpd);
|
||||
|
||||
float offset = wpd->taa_sample / wpd->taa_sample_len;
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps);
|
||||
DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo);
|
||||
DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
|
||||
psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(blur2_sh, psl->dof_blur2_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
{
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
|
||||
psl->dof_resolve_ps = DRW_pass_create("DoF Resolve",
|
||||
DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
|
||||
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(resolve_sh, psl->dof_resolve_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
|
||||
DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
|
||||
DRW_shgroup_call(grp, quad, NULL);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_dof_engine_free(void)
|
||||
{
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
|
||||
}
|
||||
|
||||
static void workbench_dof_downsample_level(void *userData, int UNUSED(level))
|
||||
{
|
||||
WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData;
|
||||
@@ -396,7 +370,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (!wpd->dof_enabled) {
|
||||
return;
|
||||
@@ -410,7 +385,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
|
||||
GPU_framebuffer_recursive_downsample(
|
||||
fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl);
|
||||
|
||||
#if 0
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimization */
|
||||
GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
|
||||
DRW_draw_pass(psl->dof_flatten_h_ps);
|
||||
|
||||
@@ -430,7 +405,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
|
||||
GPU_framebuffer_bind(fbl->dof_blur2_fb);
|
||||
DRW_draw_pass(psl->dof_blur2_ps);
|
||||
|
||||
GPU_framebuffer_bind(fbl->color_only_fb);
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->dof_resolve_ps);
|
||||
|
||||
DRW_stats_group_end();
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
#include "workbench_private.h"
|
||||
|
||||
/* *********** STATIC *********** */
|
||||
static struct {
|
||||
struct GPUShader *effect_fxaa_sh;
|
||||
} e_data = {NULL};
|
||||
|
||||
/* Shaders */
|
||||
extern char datatoc_common_fxaa_lib_glsl[];
|
||||
extern char datatoc_common_fullscreen_vert_glsl[];
|
||||
extern char datatoc_workbench_effect_fxaa_frag_glsl[];
|
||||
|
||||
/* *********** Functions *********** */
|
||||
void workbench_fxaa_engine_init(void)
|
||||
{
|
||||
if (e_data.effect_fxaa_sh == NULL) {
|
||||
e_data.effect_fxaa_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
|
||||
NULL,
|
||||
datatoc_workbench_effect_fxaa_frag_glsl,
|
||||
datatoc_common_fxaa_lib_glsl,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx)
|
||||
{
|
||||
DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
|
||||
return pass;
|
||||
}
|
||||
|
||||
void workbench_fxaa_engine_free(void)
|
||||
{
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Outline Effect:
|
||||
*
|
||||
* Simple effect that just samples an object id buffer to detect objects outlines.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
void workbench_outline_cache_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
if (OBJECT_OUTLINE_ENABLED(wpd)) {
|
||||
int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
|
||||
DRW_PASS_CREATE(psl->outline_ps, state);
|
||||
|
||||
sh = workbench_shader_outline_get();
|
||||
|
||||
grp = DRW_shgroup_create(sh, psl->outline_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
|
||||
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
else {
|
||||
psl->outline_ps = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#include "workbench_private.h"
|
||||
#include "BLI_jitter_2d.h"
|
||||
|
||||
static struct {
|
||||
struct GPUShader *effect_taa_sh;
|
||||
float jitter_5[5][2];
|
||||
float jitter_8[8][2];
|
||||
float jitter_11[11][2];
|
||||
float jitter_16[16][2];
|
||||
float jitter_32[32][2];
|
||||
} e_data = {NULL};
|
||||
|
||||
extern char datatoc_workbench_effect_taa_frag_glsl[];
|
||||
|
||||
static void workbench_taa_jitter_init_order(float (*table)[2], int num)
|
||||
{
|
||||
BLI_jitter_init(table, num);
|
||||
|
||||
/* find closest element to center */
|
||||
int closest_index = 0;
|
||||
float closest_squared_distance = 1.0f;
|
||||
|
||||
for (int index = 0; index < num; index++) {
|
||||
const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]);
|
||||
if (squared_dist < closest_squared_distance) {
|
||||
closest_squared_distance = squared_dist;
|
||||
closest_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
/* move jitter table so that closest sample is in center */
|
||||
for (int index = 0; index < num; index++) {
|
||||
sub_v2_v2(table[index], table[closest_index]);
|
||||
mul_v2_fl(table[index], 2.0f);
|
||||
}
|
||||
|
||||
/* swap center sample to the start of the table */
|
||||
if (closest_index != 0) {
|
||||
swap_v2_v2(table[0], table[closest_index]);
|
||||
}
|
||||
|
||||
/* sort list based on furtest distance with previous */
|
||||
for (int i = 0; i < num - 2; i++) {
|
||||
float f_squared_dist = 0.0;
|
||||
int f_index = i;
|
||||
for (int j = i + 1; j < num; j++) {
|
||||
const float squared_dist = square_f(table[i][0] - table[j][0]) +
|
||||
square_f(table[i][1] - table[j][1]);
|
||||
if (squared_dist > f_squared_dist) {
|
||||
f_squared_dist = squared_dist;
|
||||
f_index = j;
|
||||
}
|
||||
}
|
||||
swap_v2_v2(table[i + 1], table[f_index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_taa_jitter_init(void)
|
||||
{
|
||||
workbench_taa_jitter_init_order(e_data.jitter_5, 5);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_8, 8);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_11, 11);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_16, 16);
|
||||
workbench_taa_jitter_init_order(e_data.jitter_32, 32);
|
||||
}
|
||||
|
||||
int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
const Scene *scene = DRW_context_state_get()->scene;
|
||||
int result;
|
||||
if (workbench_is_taa_enabled(wpd)) {
|
||||
if (DRW_state_is_image_render()) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
if (draw_ctx->v3d) {
|
||||
result = scene->display.viewport_aa;
|
||||
}
|
||||
else {
|
||||
result = scene->display.render_aa;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = wpd->preferences->viewport_aa;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* when no TAA is disabled return 1 to render a single sample
|
||||
* see `workbench_render.c` */
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata))
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1;
|
||||
result = MAX2(result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void workbench_taa_engine_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
|
||||
if (e_data.effect_taa_sh == NULL) {
|
||||
e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl,
|
||||
NULL);
|
||||
workbench_taa_jitter_init();
|
||||
}
|
||||
|
||||
effect_info->view = NULL;
|
||||
|
||||
/* reset complete drawing when navigating. */
|
||||
if (effect_info->jitter_index != 0) {
|
||||
if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) {
|
||||
effect_info->jitter_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect_info->view_updated) {
|
||||
effect_info->jitter_index = 0;
|
||||
effect_info->view_updated = false;
|
||||
}
|
||||
|
||||
{
|
||||
float persmat[4][4];
|
||||
DRW_view_persmat_get(NULL, persmat, false);
|
||||
if (!equals_m4m4(persmat, effect_info->last_mat)) {
|
||||
copy_m4_m4(effect_info->last_mat, persmat);
|
||||
effect_info->jitter_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_taa_engine_free(void)
|
||||
{
|
||||
DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh);
|
||||
}
|
||||
|
||||
DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
const WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
|
||||
{
|
||||
const eGPUTextureFormat hist_buffer_format = workbench_color_texture_format(wpd);
|
||||
DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, hist_buffer_format, 0);
|
||||
DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
|
||||
}
|
||||
|
||||
{
|
||||
GPU_framebuffer_ensure_config(&fbl->effect_taa_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
|
||||
});
|
||||
GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
|
||||
});
|
||||
}
|
||||
|
||||
DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR);
|
||||
DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx);
|
||||
DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1);
|
||||
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
const DRWView *default_view = DRW_view_default_get();
|
||||
int num_samples = 8;
|
||||
float(*samples)[2];
|
||||
|
||||
num_samples = workbench_taa_calculate_num_iterations(vedata);
|
||||
switch (num_samples) {
|
||||
default:
|
||||
case 5:
|
||||
samples = e_data.jitter_5;
|
||||
break;
|
||||
case 8:
|
||||
samples = e_data.jitter_8;
|
||||
break;
|
||||
case 11:
|
||||
samples = e_data.jitter_11;
|
||||
break;
|
||||
case 16:
|
||||
samples = e_data.jitter_16;
|
||||
break;
|
||||
case 32:
|
||||
samples = e_data.jitter_32;
|
||||
break;
|
||||
}
|
||||
|
||||
const int jitter_index = effect_info->jitter_index;
|
||||
const float *transform_offset = samples[jitter_index];
|
||||
effect_info->taa_mix_factor = 1.0f / (jitter_index + 1);
|
||||
effect_info->jitter_index = (jitter_index + 1) % num_samples;
|
||||
/* Copy jitter index to Cavity iteration */
|
||||
wpd->ssao_params[3] = effect_info->jitter_index;
|
||||
|
||||
/* construct new matrices from transform delta */
|
||||
float winmat[4][4], viewmat[4][4], persmat[4][4];
|
||||
DRW_view_winmat_get(default_view, winmat, false);
|
||||
DRW_view_viewmat_get(default_view, viewmat, false);
|
||||
DRW_view_persmat_get(default_view, persmat, false);
|
||||
|
||||
window_translate_m4(winmat,
|
||||
persmat,
|
||||
transform_offset[0] / viewport_size[0],
|
||||
transform_offset[1] / viewport_size[1]);
|
||||
|
||||
if (effect_info->view) {
|
||||
/* When rendering just update the view. This avoids recomputing the culling. */
|
||||
DRW_view_update_sub(effect_info->view, viewmat, winmat);
|
||||
}
|
||||
else {
|
||||
/* TAA is not making a big change to the matrices.
|
||||
* Reuse the main view culling by creating a subview. */
|
||||
effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat);
|
||||
}
|
||||
DRW_view_set_active(effect_info->view);
|
||||
}
|
||||
|
||||
void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata)
|
||||
{
|
||||
/*
|
||||
* If first frame then the offset is 0.0 and its depth is the depth buffer to use
|
||||
* for the rest of the draw engines. We store it in a persistent buffer.
|
||||
*
|
||||
* If it is not the first frame we copy the persistent buffer back to the
|
||||
* default depth buffer
|
||||
*/
|
||||
const WORKBENCH_StorageList *stl = vedata->stl;
|
||||
const WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
|
||||
if (effect_info->jitter_index == 1) {
|
||||
GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
|
||||
}
|
||||
else {
|
||||
GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
|
||||
}
|
||||
|
||||
GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT);
|
||||
|
||||
if (!DRW_state_is_image_render()) {
|
||||
DRW_view_set_active(NULL);
|
||||
}
|
||||
|
||||
if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) {
|
||||
DRW_viewport_request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_taa_view_updated(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
if (stl) {
|
||||
WORKBENCH_EffectInfo *effect_info = stl->effects;
|
||||
if (effect_info) {
|
||||
effect_info->view_updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,18 +19,557 @@
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Simple engine for drawing color and/or depth.
|
||||
* When we only need simple flat shaders.
|
||||
* Workbench Engine:
|
||||
*
|
||||
* Optimized engine to draw the working viewport with solid and transparent geometry.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_particle.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
|
||||
|
||||
/* Note: currently unused, we may want to register so we can see this when debugging the view. */
|
||||
void workbench_engine_init(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
|
||||
workbench_shader_library_ensure();
|
||||
|
||||
if (!stl->wpd) {
|
||||
stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
|
||||
stl->wpd->view_updated = true;
|
||||
}
|
||||
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
workbench_private_data_init(wpd);
|
||||
workbench_update_world_ubo(wpd);
|
||||
|
||||
if (txl->dummy_image_tx == NULL) {
|
||||
float fpixel[4] = {1.0f, 0.0f, 1.0f, 1.0f};
|
||||
txl->dummy_image_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, 0, fpixel);
|
||||
}
|
||||
wpd->dummy_image_tx = txl->dummy_image_tx;
|
||||
|
||||
if (OBJECT_ID_PASS_ENABLED(wpd)) {
|
||||
wpd->object_id_tx = DRW_texture_pool_query_fullscreen(GPU_R16UI, &draw_engine_workbench);
|
||||
}
|
||||
else {
|
||||
/* Dont free because it's a pool texture. */
|
||||
wpd->object_id_tx = NULL;
|
||||
}
|
||||
|
||||
workbench_opaque_engine_init(vedata);
|
||||
workbench_transparent_engine_init(vedata);
|
||||
workbench_dof_engine_init(vedata);
|
||||
workbench_antialiasing_engine_init(vedata);
|
||||
workbench_volume_engine_init(vedata);
|
||||
}
|
||||
|
||||
void workbench_cache_init(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
|
||||
workbench_opaque_cache_init(vedata);
|
||||
workbench_transparent_cache_init(vedata);
|
||||
workbench_shadow_cache_init(vedata);
|
||||
workbench_cavity_cache_init(vedata);
|
||||
workbench_outline_cache_init(vedata);
|
||||
workbench_dof_cache_init(vedata);
|
||||
workbench_antialiasing_cache_init(vedata);
|
||||
workbench_volume_cache_init(vedata);
|
||||
}
|
||||
|
||||
/* TODO(fclem) DRW_cache_object_surface_material_get needs a refactor to allow passing NULL
|
||||
* instead of gpumat_array. Avoiding all this boilerplate code. */
|
||||
static struct GPUBatch **workbench_object_surface_material_get(Object *ob)
|
||||
{
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
|
||||
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
|
||||
|
||||
return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
|
||||
}
|
||||
|
||||
static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
eV3DShadingColorType color_type)
|
||||
{
|
||||
const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
|
||||
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
|
||||
BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR);
|
||||
|
||||
if (use_single_drawcall) {
|
||||
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
|
||||
DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol);
|
||||
}
|
||||
else {
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL);
|
||||
}
|
||||
DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
|
||||
const bool use_single_drawcall = imapaint->mode == IMAGEPAINT_MODE_IMAGE;
|
||||
|
||||
if (use_single_drawcall) {
|
||||
struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
|
||||
if (geom) {
|
||||
Image *ima = imapaint->canvas;
|
||||
int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
|
||||
SHD_INTERP_CLOSEST;
|
||||
|
||||
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp);
|
||||
DRW_shgroup_call(grp, geom, ob);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct GPUBatch **geoms = DRW_cache_mesh_surface_texpaint_get(ob);
|
||||
if (geoms) {
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0);
|
||||
DRW_shgroup_call(grp, geoms[i], ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
eV3DShadingColorType color_type,
|
||||
bool *r_transp)
|
||||
{
|
||||
const bool use_tex = ELEM(color_type, V3D_SHADING_TEXTURE_COLOR);
|
||||
const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
|
||||
const bool use_single_drawcall = !ELEM(
|
||||
color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR);
|
||||
|
||||
if (use_single_drawcall) {
|
||||
struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) :
|
||||
DRW_cache_object_surface_get(ob);
|
||||
if (geom) {
|
||||
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp);
|
||||
DRW_shgroup_call(grp, geom, ob);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct GPUBatch **geoms = (use_tex) ? DRW_cache_mesh_surface_texpaint_get(ob) :
|
||||
workbench_object_surface_material_get(ob);
|
||||
if (geoms) {
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp);
|
||||
DRW_shgroup_call(grp, geoms[i], ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
ModifierData *md,
|
||||
eV3DShadingColorType color_type,
|
||||
bool use_texpaint_mode)
|
||||
{
|
||||
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
|
||||
ParticleSettings *part = psys->part;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
|
||||
const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL;
|
||||
Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL;
|
||||
int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
|
||||
SHD_INTERP_CLOSEST;
|
||||
DRWShadingGroup *grp = (use_texpaint_mode) ?
|
||||
workbench_image_hair_setup(wpd, ob, part->omat, ima, NULL, interp) :
|
||||
workbench_material_hair_setup(wpd, ob, part->omat, color_type);
|
||||
|
||||
DRW_shgroup_hair_create_sub(ob, psys, md, grp);
|
||||
}
|
||||
|
||||
/* Decide what colortype to draw the object with.
|
||||
* In some cases it can be overwritten by workbench_material_setup(). */
|
||||
static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
bool *r_sculpt_pbvh,
|
||||
bool *r_texpaint_mode,
|
||||
bool *r_draw_shadow)
|
||||
{
|
||||
eV3DShadingColorType color_type = wpd->shading.color_type;
|
||||
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
|
||||
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const bool is_active = (ob == draw_ctx->obact);
|
||||
const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
|
||||
!DRW_state_is_image_render();
|
||||
const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL);
|
||||
const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE);
|
||||
const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX);
|
||||
|
||||
if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) {
|
||||
color_type = V3D_SHADING_MATERIAL_COLOR;
|
||||
}
|
||||
/* Disable color mode if data layer is unavailable. */
|
||||
if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) {
|
||||
color_type = V3D_SHADING_MATERIAL_COLOR;
|
||||
}
|
||||
if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) {
|
||||
color_type = V3D_SHADING_OBJECT_COLOR;
|
||||
}
|
||||
|
||||
*r_sculpt_pbvh = is_sculpt_pbvh;
|
||||
*r_texpaint_mode = false;
|
||||
|
||||
if (!is_sculpt_pbvh && !is_render) {
|
||||
/* Force texture or vertex mode if object is in paint mode. */
|
||||
if (is_texpaint_mode && me && me->mloopuv) {
|
||||
color_type = V3D_SHADING_TEXTURE_COLOR;
|
||||
*r_texpaint_mode = true;
|
||||
}
|
||||
else if (is_vertpaint_mode && me && me->mloopcol) {
|
||||
color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (r_draw_shadow) {
|
||||
*r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd);
|
||||
/* Currently unsupported in sculpt mode. We could revert to the slow
|
||||
* method in this case but I'm not sure if it's a good idea given that
|
||||
* sculpted meshes are heavy to begin with. */
|
||||
if (is_sculpt_pbvh) {
|
||||
*r_draw_shadow = false;
|
||||
}
|
||||
|
||||
if (is_active && DRW_object_use_hide_faces(ob)) {
|
||||
*r_draw_shadow = false;
|
||||
}
|
||||
}
|
||||
|
||||
return color_type;
|
||||
}
|
||||
|
||||
void workbench_cache_populate(void *ved, Object *ob)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
|
||||
if (!DRW_object_is_renderable(ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->type == OB_MESH && ob->modifiers.first != NULL) {
|
||||
bool use_sculpt_pbvh, use_texpaint_mode;
|
||||
int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, NULL);
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
if (md->type != eModifierType_ParticleSystem) {
|
||||
continue;
|
||||
}
|
||||
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
|
||||
if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
|
||||
continue;
|
||||
}
|
||||
ParticleSettings *part = psys->part;
|
||||
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
|
||||
|
||||
if (draw_as == PART_DRAW_PATH) {
|
||||
workbench_cache_hair_populate(wpd, ob, md, color_type, use_texpaint_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ob->base_flag & BASE_FROM_DUPLI)) {
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
|
||||
if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) {
|
||||
FluidModifierData *fmd = (FluidModifierData *)md;
|
||||
if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
|
||||
workbench_volume_cache_populate(vedata, wpd->scene, ob, md);
|
||||
return; /* Do not draw solid in this case. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
|
||||
bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false;
|
||||
eV3DShadingColorType color_type = workbench_color_type_get(
|
||||
wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow);
|
||||
|
||||
if (use_sculpt_pbvh) {
|
||||
workbench_cache_sculpt_populate(wpd, ob, color_type);
|
||||
}
|
||||
else if (use_texpaint_mode) {
|
||||
workbench_cache_texpaint_populate(wpd, ob);
|
||||
}
|
||||
else {
|
||||
workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat);
|
||||
}
|
||||
|
||||
if (draw_shadow) {
|
||||
workbench_shadow_cache_populate(vedata, ob, has_transp_mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_cache_finish(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
|
||||
/* TODO(fclem) Only do this when really needed. */
|
||||
{
|
||||
/* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
|
||||
DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
|
||||
|
||||
GPU_framebuffer_ensure_config(&dfbl->in_front_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->color),
|
||||
});
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->opaque_infront_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
|
||||
});
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->transp_accum_infront_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
|
||||
});
|
||||
}
|
||||
|
||||
if (wpd->object_id_tx) {
|
||||
GPU_framebuffer_ensure_config(&fbl->id_clear_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
|
||||
});
|
||||
}
|
||||
else {
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(fbl->id_clear_fb);
|
||||
}
|
||||
|
||||
workbench_update_material_ubos(wpd);
|
||||
|
||||
/* TODO don't free reuse next redraw. */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 2; k++) {
|
||||
if (wpd->prepass[i][j][k].material_hash) {
|
||||
BLI_ghash_free(wpd->prepass[i][j][k].material_hash, NULL, NULL);
|
||||
wpd->prepass[i][j][k].material_hash = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Used by viewport rendering & final rendering.
|
||||
* Do one render loop iteration (i.e: One TAA sample). */
|
||||
void workbench_draw_sample(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
float clear_col_with_alpha[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
const bool do_render = workbench_antialiasing_setup(vedata);
|
||||
const bool xray_is_visible = wpd->shading.xray_alpha > 0.0f;
|
||||
const bool do_transparent_infront_pass = !DRW_pass_is_empty(psl->transp_accum_infront_ps);
|
||||
const bool do_transparent_pass = !DRW_pass_is_empty(psl->transp_accum_ps);
|
||||
const bool do_opaque_infront_pass = !DRW_pass_is_empty(psl->opaque_infront_ps);
|
||||
const bool do_opaque_pass = !DRW_pass_is_empty(psl->opaque_ps) || do_opaque_infront_pass;
|
||||
|
||||
if (dfbl->in_front_fb) {
|
||||
GPU_framebuffer_bind(dfbl->in_front_fb);
|
||||
GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
|
||||
}
|
||||
|
||||
if (do_render) {
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
GPU_framebuffer_clear_color_depth_stencil(dfbl->default_fb, wpd->background_color, 1.0f, 0x00);
|
||||
|
||||
if (fbl->id_clear_fb) {
|
||||
GPU_framebuffer_bind(fbl->id_clear_fb);
|
||||
GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
|
||||
}
|
||||
|
||||
if (do_opaque_pass) {
|
||||
GPU_framebuffer_bind(fbl->opaque_fb);
|
||||
DRW_draw_pass(psl->opaque_ps);
|
||||
|
||||
if (psl->shadow_ps[0]) {
|
||||
DRW_draw_pass(psl->shadow_ps[0]);
|
||||
DRW_draw_pass(psl->shadow_ps[1]);
|
||||
}
|
||||
|
||||
if (do_opaque_infront_pass) {
|
||||
GPU_framebuffer_bind(fbl->opaque_infront_fb);
|
||||
DRW_draw_pass(psl->opaque_infront_ps);
|
||||
|
||||
GPU_framebuffer_bind(fbl->opaque_fb);
|
||||
DRW_draw_pass(psl->merge_infront_ps);
|
||||
}
|
||||
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
DRW_draw_pass(psl->composite_ps);
|
||||
|
||||
if (psl->cavity_ps) {
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->cavity_ps);
|
||||
}
|
||||
}
|
||||
|
||||
workbench_volume_draw_pass(vedata);
|
||||
|
||||
if (xray_is_visible) {
|
||||
if (do_transparent_pass) {
|
||||
GPU_framebuffer_bind(fbl->transp_accum_fb);
|
||||
GPU_framebuffer_clear_color(fbl->transp_accum_fb, clear_col_with_alpha);
|
||||
|
||||
DRW_draw_pass(psl->transp_accum_ps);
|
||||
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->transp_resolve_ps);
|
||||
}
|
||||
|
||||
if (do_transparent_infront_pass) {
|
||||
GPU_framebuffer_bind(fbl->transp_accum_infront_fb);
|
||||
GPU_framebuffer_clear_color(fbl->transp_accum_infront_fb, clear_col_with_alpha);
|
||||
|
||||
DRW_draw_pass(psl->transp_accum_infront_ps);
|
||||
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->transp_resolve_ps);
|
||||
}
|
||||
}
|
||||
|
||||
workbench_transparent_draw_depth_pass(vedata);
|
||||
|
||||
if (psl->outline_ps) {
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->outline_ps);
|
||||
}
|
||||
|
||||
workbench_dof_draw_pass(vedata);
|
||||
}
|
||||
|
||||
workbench_antialiasing_draw_pass(vedata);
|
||||
}
|
||||
|
||||
/* Viewport rendering. */
|
||||
static void workbench_draw_scene(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
|
||||
if (DRW_state_is_opengl_render()) {
|
||||
while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
|
||||
workbench_update_world_ubo(wpd);
|
||||
|
||||
workbench_draw_sample(vedata);
|
||||
}
|
||||
}
|
||||
else {
|
||||
workbench_draw_sample(vedata);
|
||||
}
|
||||
|
||||
workbench_draw_finish(vedata);
|
||||
}
|
||||
|
||||
void workbench_draw_finish(void *ved)
|
||||
{
|
||||
WORKBENCH_Data *vedata = ved;
|
||||
workbench_volume_draw_finish(vedata);
|
||||
}
|
||||
|
||||
static void workbench_engine_free(void)
|
||||
{
|
||||
workbench_shader_free();
|
||||
}
|
||||
|
||||
static void workbench_view_update(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *data = vedata;
|
||||
workbench_antialiasing_view_updated(data);
|
||||
}
|
||||
|
||||
static void workbench_id_update(void *UNUSED(vedata), struct ID *id)
|
||||
{
|
||||
if (GS(id->name) == ID_OB) {
|
||||
WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(id,
|
||||
&draw_engine_workbench);
|
||||
if (oed != NULL && oed->dd.recalc != 0) {
|
||||
oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0;
|
||||
oed->dd.recalc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
|
||||
|
||||
DrawEngineType draw_engine_workbench = {
|
||||
NULL,
|
||||
NULL,
|
||||
N_("Workbench"),
|
||||
&workbench_data_size,
|
||||
&workbench_engine_init,
|
||||
&workbench_engine_free,
|
||||
&workbench_cache_init,
|
||||
&workbench_cache_populate,
|
||||
&workbench_cache_finish,
|
||||
&workbench_draw_scene,
|
||||
&workbench_view_update,
|
||||
&workbench_id_update,
|
||||
&workbench_render,
|
||||
};
|
||||
|
||||
RenderEngineType DRW_engine_viewport_workbench_type = {
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -44,7 +583,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
|
||||
NULL,
|
||||
NULL,
|
||||
&workbench_render_update_passes,
|
||||
&draw_engine_workbench_solid,
|
||||
&draw_engine_workbench,
|
||||
{NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#ifndef __WORKBENCH_ENGINE_H__
|
||||
#define __WORKBENCH_ENGINE_H__
|
||||
|
||||
extern DrawEngineType draw_engine_workbench_solid;
|
||||
extern DrawEngineType draw_engine_workbench_transparent;
|
||||
extern RenderEngineType DRW_engine_viewport_workbench_type;
|
||||
|
||||
#endif /* __WORKBENCH_ENGINE_H__ */
|
||||
|
||||
@@ -1,817 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_string_utils.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_particle.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
/* *********** STATIC *********** */
|
||||
|
||||
typedef struct WORKBENCH_FORWARD_Shaders {
|
||||
struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS];
|
||||
struct GPUShader *object_outline_sh;
|
||||
struct GPUShader *object_outline_texture_sh;
|
||||
struct GPUShader *object_outline_hair_sh;
|
||||
} WORKBENCH_FORWARD_Shaders;
|
||||
|
||||
static struct {
|
||||
WORKBENCH_FORWARD_Shaders sh_data[GPU_SHADER_CFG_LEN];
|
||||
|
||||
struct GPUShader *composite_sh_cache[2];
|
||||
|
||||
struct GPUTexture *object_id_tx; /* ref only, not alloced */
|
||||
struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
|
||||
struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
|
||||
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
|
||||
} e_data = {{{{NULL}}}};
|
||||
|
||||
/* Shaders */
|
||||
extern char datatoc_common_hair_lib_glsl[];
|
||||
extern char datatoc_common_view_lib_glsl[];
|
||||
|
||||
extern char datatoc_workbench_forward_composite_frag_glsl[];
|
||||
extern char datatoc_workbench_forward_depth_frag_glsl[];
|
||||
extern char datatoc_workbench_forward_transparent_accum_frag_glsl[];
|
||||
extern char datatoc_workbench_data_lib_glsl[];
|
||||
extern char datatoc_workbench_object_outline_lib_glsl[];
|
||||
extern char datatoc_workbench_curvature_lib_glsl[];
|
||||
extern char datatoc_workbench_prepass_vert_glsl[];
|
||||
extern char datatoc_workbench_common_lib_glsl[];
|
||||
extern char datatoc_workbench_world_light_lib_glsl[];
|
||||
|
||||
/* static functions */
|
||||
static char *workbench_build_forward_vert(bool is_hair)
|
||||
{
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
if (is_hair) {
|
||||
BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
|
||||
}
|
||||
BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
|
||||
|
||||
char *str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *workbench_build_forward_outline_frag(void)
|
||||
{
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl);
|
||||
|
||||
char *str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *workbench_build_forward_transparent_accum_frag(void)
|
||||
{
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
BLI_dynstr_append(ds, datatoc_common_view_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl);
|
||||
|
||||
char *str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *workbench_build_forward_composite_frag(void)
|
||||
{
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
|
||||
BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl);
|
||||
|
||||
char *str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
}
|
||||
|
||||
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
|
||||
WORKBENCH_Data *vedata,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
eV3DShadingColorType color_type,
|
||||
int interp)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
WORKBENCH_MaterialData *material;
|
||||
WORKBENCH_MaterialData material_template;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
/* Solid */
|
||||
workbench_material_update_data(wpd, ob, mat, &material_template, color_type);
|
||||
material_template.color_type = color_type;
|
||||
material_template.ima = ima;
|
||||
material_template.iuser = iuser;
|
||||
material_template.interp = interp;
|
||||
uint hash = workbench_material_get_hash(&material_template, false);
|
||||
|
||||
material = BLI_ghash_lookup(wpd->material_transp_hash, POINTER_FROM_UINT(hash));
|
||||
if (material == NULL) {
|
||||
material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
|
||||
|
||||
/* transparent accum */
|
||||
/* select the correct transparent accum shader */
|
||||
GPUShader *shader = (wpd->shading.color_type == color_type) ?
|
||||
wpd->transparent_accum_sh :
|
||||
wpd->transparent_accum_uniform_sh;
|
||||
const bool is_tiled = (ima && ima->source == IMA_SRC_TILED);
|
||||
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
|
||||
shader = is_tiled ? wpd->transparent_accum_textured_array_sh :
|
||||
wpd->transparent_accum_textured_sh;
|
||||
}
|
||||
|
||||
grp = DRW_shgroup_create(shader, psl->transparent_accum_pass);
|
||||
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha);
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
|
||||
workbench_material_copy(material, &material_template);
|
||||
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
|
||||
BKE_studiolight_ensure_flag(wpd->studio_light,
|
||||
STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
|
||||
STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
|
||||
DRW_shgroup_uniform_texture(
|
||||
grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
|
||||
if (workbench_is_specular_highlight_enabled(wpd)) {
|
||||
DRW_shgroup_uniform_texture(
|
||||
grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
|
||||
}
|
||||
}
|
||||
if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
}
|
||||
if (SHADOW_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_float_copy(grp, "shadowMultiplier", wpd->shadow_multiplier);
|
||||
DRW_shgroup_uniform_float_copy(grp, "shadowShift", wpd->shadow_shift);
|
||||
DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus);
|
||||
}
|
||||
|
||||
workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp);
|
||||
material->shgrp = grp;
|
||||
|
||||
/* Depth */
|
||||
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
|
||||
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh,
|
||||
psl->object_outline_pass);
|
||||
GPUTexture *tex = GPU_texture_from_blender(
|
||||
material->ima, material->iuser, NULL, GL_TEXTURE_2D);
|
||||
DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
|
||||
}
|
||||
else {
|
||||
material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh,
|
||||
psl->object_outline_pass);
|
||||
}
|
||||
if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
|
||||
DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES);
|
||||
}
|
||||
BLI_ghash_insert(wpd->material_transp_hash, POINTER_FROM_UINT(hash), material);
|
||||
}
|
||||
return material;
|
||||
}
|
||||
|
||||
static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override,
|
||||
eGPUShaderConfig sh_cfg)
|
||||
{
|
||||
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
|
||||
int index = workbench_material_get_accum_shader_index(
|
||||
wpd, is_uniform_color, is_hair, is_tiled, color_override);
|
||||
if (sh_data->transparent_accum_sh_cache[index] == NULL) {
|
||||
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
|
||||
char *defines = workbench_material_build_defines(
|
||||
wpd, is_uniform_color, is_hair, is_tiled, color_override);
|
||||
char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
|
||||
char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
|
||||
sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){sh_cfg_data->lib, transparent_accum_vert, NULL},
|
||||
.frag = (const char *[]){transparent_accum_frag, NULL},
|
||||
.defs = (const char *[]){sh_cfg_data->def, defines, NULL},
|
||||
});
|
||||
MEM_freeN(transparent_accum_vert);
|
||||
MEM_freeN(transparent_accum_frag);
|
||||
MEM_freeN(defines);
|
||||
}
|
||||
return sh_data->transparent_accum_sh_cache[index];
|
||||
}
|
||||
|
||||
static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0;
|
||||
if (e_data.composite_sh_cache[index] == NULL) {
|
||||
char *defines = workbench_material_build_defines(
|
||||
wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
|
||||
char *composite_frag = workbench_build_forward_composite_frag();
|
||||
e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
|
||||
MEM_freeN(composite_frag);
|
||||
MEM_freeN(defines);
|
||||
}
|
||||
return e_data.composite_sh_cache[index];
|
||||
}
|
||||
|
||||
void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
|
||||
{
|
||||
wpd->composite_sh = ensure_forward_composite_shaders(wpd);
|
||||
wpd->transparent_accum_sh = ensure_forward_accum_shaders(
|
||||
wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
|
||||
wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders(
|
||||
wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
|
||||
wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders(
|
||||
wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
|
||||
wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders(
|
||||
wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg);
|
||||
wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders(
|
||||
wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
|
||||
wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders(
|
||||
wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg);
|
||||
wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders(
|
||||
wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg);
|
||||
}
|
||||
|
||||
void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg)
|
||||
{
|
||||
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg];
|
||||
|
||||
if (sh_data->object_outline_sh == NULL) {
|
||||
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg];
|
||||
char *defines = workbench_material_build_defines(
|
||||
wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
|
||||
char *defines_texture = workbench_material_build_defines(
|
||||
wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF);
|
||||
char *defines_hair = workbench_material_build_defines(
|
||||
wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF);
|
||||
char *forward_vert = workbench_build_forward_vert(false);
|
||||
char *forward_frag = workbench_build_forward_outline_frag();
|
||||
char *forward_hair_vert = workbench_build_forward_vert(true);
|
||||
|
||||
const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n";
|
||||
|
||||
sh_data->object_outline_sh = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
|
||||
.frag = (const char *[]){forward_frag, NULL},
|
||||
.defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL},
|
||||
});
|
||||
sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL},
|
||||
.frag = (const char *[]){forward_frag, NULL},
|
||||
.defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL},
|
||||
});
|
||||
sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL},
|
||||
.frag = (const char *[]){forward_frag, NULL},
|
||||
.defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL},
|
||||
});
|
||||
|
||||
MEM_freeN(forward_hair_vert);
|
||||
MEM_freeN(forward_vert);
|
||||
MEM_freeN(forward_frag);
|
||||
MEM_freeN(defines);
|
||||
MEM_freeN(defines_texture);
|
||||
MEM_freeN(defines_hair);
|
||||
}
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
void workbench_forward_engine_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
if (!stl->g_data) {
|
||||
/* Alloc transient pointers */
|
||||
stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
|
||||
}
|
||||
if (!stl->effects) {
|
||||
stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
|
||||
workbench_effect_info_init(stl->effects);
|
||||
}
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
workbench_private_data_init(wpd);
|
||||
|
||||
workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
|
||||
|
||||
workbench_volume_engine_init();
|
||||
workbench_fxaa_engine_init();
|
||||
workbench_taa_engine_init(vedata);
|
||||
|
||||
workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg);
|
||||
workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg);
|
||||
|
||||
const float *viewport_size = DRW_viewport_size_get();
|
||||
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
|
||||
const eGPUTextureFormat comp_tex_format = GPU_RGBA16F;
|
||||
|
||||
e_data.object_id_tx = DRW_texture_pool_query_2d(
|
||||
size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent);
|
||||
e_data.transparent_accum_tx = DRW_texture_pool_query_2d(
|
||||
size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent);
|
||||
e_data.transparent_revealage_tx = DRW_texture_pool_query_2d(
|
||||
size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent);
|
||||
e_data.composite_buffer_tx = DRW_texture_pool_query_2d(
|
||||
size[0], size[1], comp_tex_format, &draw_engine_workbench_transparent);
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->object_outline_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
|
||||
GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
|
||||
});
|
||||
GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx),
|
||||
});
|
||||
GPU_framebuffer_ensure_config(&fbl->composite_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
|
||||
});
|
||||
GPU_framebuffer_ensure_config(&fbl->effect_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
|
||||
});
|
||||
|
||||
workbench_volume_cache_init(vedata);
|
||||
|
||||
DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0;
|
||||
DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
|
||||
|
||||
/* Transparency Accum */
|
||||
{
|
||||
int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state;
|
||||
psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
|
||||
}
|
||||
/* Depth */
|
||||
{
|
||||
int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state |
|
||||
clip_state;
|
||||
psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state);
|
||||
}
|
||||
/* Composite */
|
||||
{
|
||||
int state = DRW_STATE_WRITE_COLOR;
|
||||
if (DRW_state_is_scene_render()) {
|
||||
/* Composite the scene over cleared background. */
|
||||
state |= DRW_STATE_BLEND_ALPHA_PREMUL;
|
||||
}
|
||||
psl->composite_pass = DRW_pass_create("Composite", state);
|
||||
|
||||
grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
|
||||
if (OBJECT_ID_PASS_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
|
||||
}
|
||||
DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx);
|
||||
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
|
||||
}
|
||||
|
||||
{
|
||||
workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx);
|
||||
}
|
||||
|
||||
if (wpd->shading.type == OB_WIRE) {
|
||||
wpd->shading.xray_alpha = 0.0f;
|
||||
wpd->shading.xray_alpha_wire = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_forward_engine_free()
|
||||
{
|
||||
for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
|
||||
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_data_index];
|
||||
for (int index = 0; index < MAX_ACCUM_SHADERS; index++) {
|
||||
DRW_SHADER_FREE_SAFE(sh_data->transparent_accum_sh_cache[index]);
|
||||
}
|
||||
DRW_SHADER_FREE_SAFE(sh_data->object_outline_sh);
|
||||
DRW_SHADER_FREE_SAFE(sh_data->object_outline_texture_sh);
|
||||
DRW_SHADER_FREE_SAFE(sh_data->object_outline_hair_sh);
|
||||
}
|
||||
|
||||
for (int index = 0; index < 2; index++) {
|
||||
DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
|
||||
}
|
||||
|
||||
workbench_volume_engine_free();
|
||||
workbench_fxaa_engine_free();
|
||||
workbench_taa_engine_free();
|
||||
workbench_dof_engine_free();
|
||||
}
|
||||
|
||||
void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))
|
||||
{
|
||||
}
|
||||
|
||||
static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
|
||||
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
|
||||
if (md->type != eModifierType_ParticleSystem) {
|
||||
continue;
|
||||
}
|
||||
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
|
||||
if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
|
||||
continue;
|
||||
}
|
||||
ParticleSettings *part = psys->part;
|
||||
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
|
||||
|
||||
if (draw_as == PART_DRAW_PATH) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Material *mat;
|
||||
Image *image;
|
||||
ImageUser *iuser;
|
||||
int interp;
|
||||
workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat);
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, image, ob, false);
|
||||
WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, mat, image, iuser, color_type, interp);
|
||||
|
||||
struct GPUShader *shader = (wpd->shading.color_type == color_type) ?
|
||||
wpd->transparent_accum_hair_sh :
|
||||
wpd->transparent_accum_uniform_hair_sh;
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
|
||||
ob, psys, md, psl->transparent_accum_pass, shader);
|
||||
DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
|
||||
workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp);
|
||||
DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
|
||||
/* Hairs have lots of layer and can rapidly become the most prominent surface.
|
||||
* So lower their alpha artificially. */
|
||||
float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
|
||||
DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
|
||||
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
|
||||
BKE_studiolight_ensure_flag(wpd->studio_light,
|
||||
STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
|
||||
STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
|
||||
DRW_shgroup_uniform_texture(
|
||||
shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture);
|
||||
if (workbench_is_specular_highlight_enabled(wpd)) {
|
||||
DRW_shgroup_uniform_texture(
|
||||
shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture);
|
||||
}
|
||||
}
|
||||
if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) {
|
||||
DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
|
||||
}
|
||||
|
||||
WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||
shgrp = DRW_shgroup_hair_create(
|
||||
ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
||||
Scene *scene = draw_ctx->scene;
|
||||
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
|
||||
!DRW_state_is_image_render();
|
||||
WORKBENCH_MaterialData *material;
|
||||
|
||||
/* Force workbench to render active object textured when in texture paint mode */
|
||||
const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
|
||||
|
||||
/* Single Image mode */
|
||||
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
|
||||
Image *image = imapaint->canvas;
|
||||
int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR :
|
||||
SHD_INTERP_CLOSEST;
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, image, ob, use_sculpt_pbvh);
|
||||
struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, NULL, image, NULL, color_type, interp);
|
||||
|
||||
DRW_shgroup_call(material->shgrp, geom, ob);
|
||||
DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
|
||||
}
|
||||
else {
|
||||
/* IMAGEPAINT_MODE_MATERIAL */
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
if (geom_array != NULL && geom_array[i] != NULL) {
|
||||
Material *mat;
|
||||
Image *image;
|
||||
ImageUser *iuser;
|
||||
int interp;
|
||||
workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, image, ob, use_sculpt_pbvh);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, mat, image, iuser, color_type, interp);
|
||||
|
||||
DRW_shgroup_call(material->shgrp, geom_array[i], ob);
|
||||
DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
||||
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
|
||||
!DRW_state_is_image_render();
|
||||
WORKBENCH_MaterialData *material;
|
||||
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, NULL, ob, use_sculpt_pbvh);
|
||||
struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, NULL, NULL, NULL, color_type, false);
|
||||
DRW_shgroup_call(material->shgrp, geom, ob);
|
||||
DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
|
||||
}
|
||||
|
||||
void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
const bool is_wire = (ob->dt == OB_WIRE);
|
||||
|
||||
if (!DRW_object_is_renderable(ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
workbench_forward_cache_populate_particles(vedata, ob);
|
||||
}
|
||||
|
||||
ModifierData *md;
|
||||
if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
|
||||
(md = modifiers_findByType(ob, eModifierType_Fluid)) &&
|
||||
(modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
|
||||
(((FluidModifierData *)md)->domain != NULL) &&
|
||||
(((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) {
|
||||
workbench_volume_cache_populate(vedata, scene, ob, md);
|
||||
return; /* Do not draw solid in this case. */
|
||||
}
|
||||
|
||||
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
|
||||
return;
|
||||
}
|
||||
if (ob->dt < OB_WIRE) {
|
||||
return;
|
||||
}
|
||||
|
||||
WORKBENCH_MaterialData *material = NULL;
|
||||
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
|
||||
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
|
||||
!DRW_state_is_image_render();
|
||||
const int materials_len = DRW_cache_object_material_count_get(ob);
|
||||
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
|
||||
const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob);
|
||||
const bool use_texture_paint_drawing = !(DRW_state_is_image_render() &&
|
||||
draw_ctx->v3d == NULL) &&
|
||||
(color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) &&
|
||||
me && me->mloopuv;
|
||||
const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() &&
|
||||
draw_ctx->v3d == NULL) &&
|
||||
(color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) &&
|
||||
me && me->mloopcol;
|
||||
|
||||
if (use_texture_paint_drawing) {
|
||||
workbench_forward_cache_populate_texture_paint_mode(vedata, ob);
|
||||
}
|
||||
else if (use_vertex_paint_drawing) {
|
||||
workbench_forward_cache_populate_vertex_paint_mode(vedata, ob);
|
||||
}
|
||||
else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) {
|
||||
struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob);
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
Material *mat;
|
||||
Image *image;
|
||||
ImageUser *iuser;
|
||||
int interp;
|
||||
workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat);
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, image, ob, use_sculpt_pbvh);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, mat, image, iuser, color_type, interp);
|
||||
DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob);
|
||||
DRW_shgroup_call(material->shgrp, geom_array[i], ob);
|
||||
}
|
||||
}
|
||||
else if (ELEM(wpd->shading.color_type,
|
||||
V3D_SHADING_SINGLE_COLOR,
|
||||
V3D_SHADING_OBJECT_COLOR,
|
||||
V3D_SHADING_RANDOM_COLOR,
|
||||
V3D_SHADING_VERTEX_COLOR)) {
|
||||
/* No material split needed */
|
||||
eV3DShadingColorType color_type = workbench_material_determine_color_type(
|
||||
wpd, NULL, ob, use_sculpt_pbvh);
|
||||
|
||||
if (use_sculpt_pbvh) {
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, NULL, NULL, NULL, color_type, 0);
|
||||
bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR);
|
||||
/* TODO(fclem) make this call optional */
|
||||
DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
|
||||
if (!is_wire) {
|
||||
DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ?
|
||||
DRW_cache_mesh_surface_vertpaint_get(ob) :
|
||||
DRW_cache_object_surface_get(ob);
|
||||
if (geom) {
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, NULL, NULL, NULL, color_type, 0);
|
||||
/* TODO(fclem) make this call optional */
|
||||
DRW_shgroup_call(material->shgrp_object_outline, geom, ob);
|
||||
if (!is_wire) {
|
||||
DRW_shgroup_call(material->shgrp, geom, ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Draw material color */
|
||||
if (use_sculpt_pbvh) {
|
||||
struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len);
|
||||
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
struct Material *mat = BKE_object_material_get(ob, i + 1);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
|
||||
shgrps[i] = material->shgrp;
|
||||
}
|
||||
/* TODO(fclem) make this call optional */
|
||||
DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false);
|
||||
if (!is_wire) {
|
||||
DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
|
||||
memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len);
|
||||
|
||||
struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
|
||||
ob, gpumat_array, materials_len);
|
||||
if (mat_geom) {
|
||||
for (int i = 0; i < materials_len; i++) {
|
||||
if (mat_geom[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Material *mat = BKE_object_material_get(ob, i + 1);
|
||||
material = workbench_forward_get_or_create_material_data(
|
||||
vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
|
||||
/* TODO(fclem) make this call optional */
|
||||
DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob);
|
||||
if (!is_wire) {
|
||||
DRW_shgroup_call(material->shgrp, mat_geom[i], ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata))
|
||||
{
|
||||
}
|
||||
|
||||
void workbench_forward_draw_scene(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_FramebufferList *fbl = vedata->fbl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (dfbl->in_front_fb) {
|
||||
/* TODO(fclem) This clear should be done in a global place. */
|
||||
GPU_framebuffer_bind(dfbl->in_front_fb);
|
||||
GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
|
||||
}
|
||||
|
||||
if (workbench_is_taa_enabled(wpd)) {
|
||||
workbench_taa_draw_scene_start(vedata);
|
||||
}
|
||||
|
||||
/* Write Depth + Object ID */
|
||||
const float clear_outline[4] = {0.0f};
|
||||
GPU_framebuffer_bind(fbl->object_outline_fb);
|
||||
GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline);
|
||||
DRW_draw_pass(psl->object_outline_pass);
|
||||
|
||||
if (XRAY_ALPHA(wpd) > 0.0) {
|
||||
const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GPU_framebuffer_bind(fbl->transparent_accum_fb);
|
||||
GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
|
||||
DRW_draw_pass(psl->transparent_accum_pass);
|
||||
}
|
||||
else {
|
||||
/* TODO(fclem): this is unnecessary and takes up perf.
|
||||
* Better change the composite frag shader to not use the tx. */
|
||||
const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
GPU_framebuffer_bind(fbl->transparent_accum_fb);
|
||||
GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
|
||||
}
|
||||
|
||||
/* Composite */
|
||||
GPU_framebuffer_bind(fbl->composite_fb);
|
||||
|
||||
if (DRW_state_is_scene_render()) {
|
||||
float clear_color[4];
|
||||
workbench_clear_color_get(clear_color);
|
||||
GPU_framebuffer_clear_color(fbl->composite_fb, clear_color);
|
||||
}
|
||||
|
||||
DRW_draw_pass(psl->composite_pass);
|
||||
DRW_draw_pass(psl->volume_pass);
|
||||
|
||||
/* Only when clipping is enabled. */
|
||||
if (psl->background_pass) {
|
||||
DRW_draw_pass(psl->background_pass);
|
||||
}
|
||||
|
||||
/* Color correct and Anti aliasing */
|
||||
workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
|
||||
}
|
||||
|
||||
void workbench_forward_draw_finish(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->g_data;
|
||||
|
||||
workbench_private_data_free(wpd);
|
||||
workbench_volume_smoke_textures_free(wpd);
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
#include "BLI_memblock.h"
|
||||
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_node.h"
|
||||
|
||||
@@ -31,310 +33,78 @@
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GPU_uniformbuffer.h"
|
||||
|
||||
#include "ED_uvedit.h"
|
||||
|
||||
#define HSV_SATURATION 0.5
|
||||
#define HSV_VALUE 0.8
|
||||
|
||||
void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
WORKBENCH_MaterialData *data,
|
||||
int color_type)
|
||||
void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
WORKBENCH_UBO_Material *data,
|
||||
eV3DShadingColorType color_type)
|
||||
{
|
||||
data->metallic = 0.0f;
|
||||
data->roughness = 0.632455532f; /* sqrtf(0.4f); */
|
||||
data->alpha = wpd->shading.xray_alpha;
|
||||
float metallic = 0.0f;
|
||||
float roughness = 0.632455532f; /* sqrtf(0.4f); */
|
||||
float alpha = wpd->shading.xray_alpha;
|
||||
|
||||
if (color_type == V3D_SHADING_SINGLE_COLOR) {
|
||||
copy_v3_v3(data->base_color, wpd->shading.single_color);
|
||||
}
|
||||
else if (color_type == V3D_SHADING_ERROR_COLOR) {
|
||||
copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8);
|
||||
}
|
||||
else if (color_type == V3D_SHADING_RANDOM_COLOR) {
|
||||
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
|
||||
if (ob->id.lib) {
|
||||
hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
|
||||
}
|
||||
|
||||
float hue = BLI_hash_int_01(hash);
|
||||
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
|
||||
hsv_to_rgb_v(hsv, data->base_color);
|
||||
}
|
||||
else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) {
|
||||
data->alpha *= ob->color[3];
|
||||
copy_v3_v3(data->base_color, ob->color);
|
||||
}
|
||||
else {
|
||||
/* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */
|
||||
if (mat) {
|
||||
data->alpha *= mat->a;
|
||||
copy_v3_v3(data->base_color, &mat->r);
|
||||
if (workbench_is_specular_highlight_enabled(wpd)) {
|
||||
data->metallic = mat->metallic;
|
||||
data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
|
||||
switch (color_type) {
|
||||
case V3D_SHADING_SINGLE_COLOR:
|
||||
copy_v3_v3(data->base_color, wpd->shading.single_color);
|
||||
break;
|
||||
case V3D_SHADING_RANDOM_COLOR: {
|
||||
uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
|
||||
if (ob->id.lib) {
|
||||
hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
|
||||
}
|
||||
float hue = BLI_hash_int_01(hash);
|
||||
float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
|
||||
hsv_to_rgb_v(hsv, data->base_color);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(data->base_color, 0.8f);
|
||||
}
|
||||
case V3D_SHADING_OBJECT_COLOR:
|
||||
case V3D_SHADING_VERTEX_COLOR:
|
||||
alpha *= ob->color[3];
|
||||
copy_v3_v3(data->base_color, ob->color);
|
||||
break;
|
||||
case V3D_SHADING_MATERIAL_COLOR:
|
||||
case V3D_SHADING_TEXTURE_COLOR:
|
||||
default:
|
||||
if (mat) {
|
||||
alpha *= mat->a;
|
||||
copy_v3_v3(data->base_color, &mat->r);
|
||||
metallic = mat->metallic;
|
||||
roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(data->base_color, 0.8f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic);
|
||||
uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness);
|
||||
uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha);
|
||||
data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic;
|
||||
}
|
||||
|
||||
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override)
|
||||
/* Return correct material or empty default material if slot is empty. */
|
||||
BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
|
||||
{
|
||||
char *str = NULL;
|
||||
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
|
||||
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
|
||||
!is_uniform_color;
|
||||
|
||||
switch (color_override) {
|
||||
case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
|
||||
use_textures = true;
|
||||
use_vertex_colors = false;
|
||||
is_hair = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_VERTEX:
|
||||
use_textures = false;
|
||||
use_vertex_colors = true;
|
||||
is_hair = false;
|
||||
is_tiled = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_OFF:
|
||||
break;
|
||||
Material *ma = BKE_object_material_get(ob, mat_nr);
|
||||
if (ma == NULL) {
|
||||
ma = BKE_material_default_empty();
|
||||
}
|
||||
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n");
|
||||
}
|
||||
if (wpd->shading.flag & V3D_SHADING_SHADOW) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_SHADOW\n");
|
||||
}
|
||||
if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define WB_CAVITY\n");
|
||||
}
|
||||
if (workbench_is_specular_highlight_enabled(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
|
||||
}
|
||||
if (STUDIOLIGHT_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
|
||||
}
|
||||
if (FLAT_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
|
||||
}
|
||||
if (MATCAP_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
|
||||
}
|
||||
if (OBJECT_ID_PASS_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n");
|
||||
}
|
||||
if (workbench_is_matdata_pass_enabled(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n");
|
||||
}
|
||||
if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
|
||||
BLI_dynstr_append(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n");
|
||||
}
|
||||
if (use_vertex_colors) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_VERTEX_COLOR\n");
|
||||
}
|
||||
if (use_textures) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
|
||||
}
|
||||
if (NORMAL_ENCODING_ENABLED()) {
|
||||
BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
|
||||
}
|
||||
if (is_hair) {
|
||||
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
|
||||
}
|
||||
if (use_textures && is_tiled) {
|
||||
BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
|
||||
}
|
||||
|
||||
str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
return ma;
|
||||
}
|
||||
|
||||
uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost)
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
/* WHATCH: Keep in sync with View3DShading.color_type max value. */
|
||||
uchar color_type;
|
||||
uchar diff_r;
|
||||
uchar diff_g;
|
||||
uchar diff_b;
|
||||
|
||||
uchar alpha;
|
||||
uchar ghost;
|
||||
uchar metal;
|
||||
uchar roughness;
|
||||
|
||||
void *ima;
|
||||
};
|
||||
/* HACK to ensure input is 4 uint long. */
|
||||
uint a[4];
|
||||
} input = {.color_type = (uchar)(mat->color_type),
|
||||
.diff_r = (uchar)(mat->base_color[0] * 0xFF),
|
||||
.diff_g = (uchar)(mat->base_color[1] * 0xFF),
|
||||
.diff_b = (uchar)(mat->base_color[2] * 0xFF),
|
||||
|
||||
.alpha = (uint)(mat->alpha * 0xFF),
|
||||
.ghost = (uchar)is_ghost,
|
||||
.metal = (uchar)(mat->metallic * 0xFF),
|
||||
.roughness = (uchar)(mat->roughness * 0xFF),
|
||||
|
||||
.ima = mat->ima};
|
||||
|
||||
BLI_assert(sizeof(input) == sizeof(uint) * 4);
|
||||
|
||||
return BLI_ghashutil_uinthash_v4((uint *)&input);
|
||||
}
|
||||
|
||||
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
/* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */
|
||||
int index = 0;
|
||||
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
|
||||
index = wpd->shading.light;
|
||||
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2);
|
||||
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3);
|
||||
SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4);
|
||||
SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5);
|
||||
SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
|
||||
BLI_assert(index < MAX_COMPOSITE_SHADERS);
|
||||
return index;
|
||||
}
|
||||
|
||||
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override)
|
||||
{
|
||||
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
|
||||
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
|
||||
!is_uniform_color;
|
||||
|
||||
switch (color_override) {
|
||||
case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
|
||||
use_textures = true;
|
||||
use_vertex_colors = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_VERTEX:
|
||||
use_textures = false;
|
||||
use_vertex_colors = true;
|
||||
is_tiled = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */
|
||||
int index = 0;
|
||||
SET_FLAG_FROM_TEST(index, is_hair, 1 << 0);
|
||||
SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1);
|
||||
SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2);
|
||||
SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3);
|
||||
SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4);
|
||||
SET_FLAG_FROM_TEST(index, use_textures, 1 << 5);
|
||||
SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6);
|
||||
SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
|
||||
BLI_assert(index < MAX_PREPASS_SHADERS);
|
||||
return index;
|
||||
}
|
||||
|
||||
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override)
|
||||
{
|
||||
bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color;
|
||||
bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) &&
|
||||
!is_uniform_color;
|
||||
|
||||
switch (color_override) {
|
||||
case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
|
||||
use_textures = true;
|
||||
use_vertex_colors = false;
|
||||
is_hair = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_VERTEX:
|
||||
use_textures = false;
|
||||
use_vertex_colors = true;
|
||||
is_hair = false;
|
||||
is_tiled = false;
|
||||
break;
|
||||
case WORKBENCH_COLOR_OVERRIDE_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */
|
||||
int index = 0;
|
||||
/* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
|
||||
index = wpd->shading.light;
|
||||
SET_FLAG_FROM_TEST(index, use_textures, 1 << 2);
|
||||
SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3);
|
||||
SET_FLAG_FROM_TEST(index, is_hair, 1 << 4);
|
||||
/* 1 bits SHADOWS (only facing factor) */
|
||||
SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5);
|
||||
SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6);
|
||||
SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7);
|
||||
BLI_assert(index < MAX_ACCUM_SHADERS);
|
||||
return index;
|
||||
}
|
||||
|
||||
eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
|
||||
Image *ima,
|
||||
Object *ob,
|
||||
bool use_sculpt_pbvh)
|
||||
{
|
||||
eV3DShadingColorType color_type = wpd->shading.color_type;
|
||||
const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
|
||||
|
||||
if ((color_type == V3D_SHADING_TEXTURE_COLOR) &&
|
||||
(ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) {
|
||||
color_type = V3D_SHADING_MATERIAL_COLOR;
|
||||
}
|
||||
if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) {
|
||||
color_type = V3D_SHADING_OBJECT_COLOR;
|
||||
}
|
||||
|
||||
switch (workbench_object_color_override_get(ob)) {
|
||||
/* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting
|
||||
* no matter the shading color that the user has chosen, when there is no
|
||||
* texture we will render the object with the error color */
|
||||
case WORKBENCH_COLOR_OVERRIDE_TEXTURE:
|
||||
color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR;
|
||||
break;
|
||||
|
||||
/* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting
|
||||
* no matter the shading color that the user has chosen, when there is no
|
||||
* vertex color we will render the object with the error color */
|
||||
case WORKBENCH_COLOR_OVERRIDE_VERTEX:
|
||||
color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
break;
|
||||
|
||||
case WORKBENCH_COLOR_OVERRIDE_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
return color_type;
|
||||
}
|
||||
|
||||
void workbench_material_get_image_and_mat(
|
||||
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat)
|
||||
BLI_INLINE void workbench_material_get_image(
|
||||
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp)
|
||||
{
|
||||
bNode *node;
|
||||
*r_mat = BKE_object_material_get(ob, mat_nr);
|
||||
|
||||
ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL);
|
||||
if (node && *r_image) {
|
||||
switch (node->type) {
|
||||
@@ -358,53 +128,170 @@ void workbench_material_get_image_and_mat(
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
|
||||
DRWShadingGroup *grp,
|
||||
WORKBENCH_MaterialData *material,
|
||||
Object *ob,
|
||||
const bool deferred,
|
||||
const bool is_tiled,
|
||||
const int interp)
|
||||
/* Return true if the current material ubo has changed and needs to be rebind. */
|
||||
BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd,
|
||||
uint32_t id,
|
||||
uint32_t *r_mat_id)
|
||||
{
|
||||
if (deferred && !workbench_is_matdata_pass_enabled(wpd)) {
|
||||
return;
|
||||
bool resource_changed = false;
|
||||
/* Divide in chunks of MAX_MATERIAL. */
|
||||
uint32_t chunk = id >> 12u;
|
||||
*r_mat_id = id & 0xFFFu;
|
||||
/* We need to add a new chunk. */
|
||||
while (chunk >= wpd->material_chunk_count) {
|
||||
wpd->material_chunk_count++;
|
||||
wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data);
|
||||
wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd);
|
||||
wpd->material_chunk_curr = chunk;
|
||||
resource_changed = true;
|
||||
}
|
||||
/* We need to go back to a previous chunk. */
|
||||
if (wpd->material_chunk_curr != chunk) {
|
||||
wpd->material_ubo_data_curr = BLI_memblock_elem_get(wpd->material_ubo_data, 0, chunk);
|
||||
wpd->material_ubo_curr = BLI_memblock_elem_get(wpd->material_ubo, 0, chunk);
|
||||
wpd->material_chunk_curr = chunk;
|
||||
resource_changed = true;
|
||||
}
|
||||
return resource_changed;
|
||||
}
|
||||
|
||||
DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
int mat_nr,
|
||||
eV3DShadingColorType color_type,
|
||||
bool hair,
|
||||
bool *r_transp)
|
||||
{
|
||||
Image *ima = NULL;
|
||||
ImageUser *iuser = NULL;
|
||||
int interp;
|
||||
const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
|
||||
|
||||
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
|
||||
if (ima == NULL) {
|
||||
/* Fallback to material color. */
|
||||
color_type = V3D_SHADING_MATERIAL_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
const bool use_highlight = workbench_is_specular_highlight_enabled(wpd);
|
||||
const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type(
|
||||
wpd, material->ima, ob, false));
|
||||
if (use_texture) {
|
||||
if (is_tiled) {
|
||||
GPUTexture *array_tex = GPU_texture_from_blender(
|
||||
material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY);
|
||||
GPUTexture *data_tex = GPU_texture_from_blender(
|
||||
material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY);
|
||||
DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex);
|
||||
DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex);
|
||||
switch (color_type) {
|
||||
case V3D_SHADING_TEXTURE_COLOR: {
|
||||
return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair);
|
||||
}
|
||||
case V3D_SHADING_MATERIAL_COLOR: {
|
||||
/* For now, we use the same ubo for material and object coloring but with different indices.
|
||||
* This means they are mutually exclusive. */
|
||||
BLI_assert(
|
||||
ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
|
||||
|
||||
Material *ma = workbench_object_material_get(ob, mat_nr);
|
||||
|
||||
const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f;
|
||||
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair];
|
||||
|
||||
if (r_transp && transp) {
|
||||
*r_transp = true;
|
||||
}
|
||||
|
||||
DRWShadingGroup **grp_mat = NULL;
|
||||
/* A hashmap stores material shgroups to pack all similar drawcalls together. */
|
||||
if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) {
|
||||
return *grp_mat;
|
||||
}
|
||||
|
||||
uint32_t mat_id, id = wpd->material_index++;
|
||||
|
||||
workbench_material_chunk_select(wpd, id, &mat_id);
|
||||
workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type);
|
||||
|
||||
DRWShadingGroup *grp = prepass->common_shgrp;
|
||||
*grp_mat = grp = DRW_shgroup_create_sub(grp);
|
||||
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
|
||||
return grp;
|
||||
}
|
||||
case V3D_SHADING_VERTEX_COLOR: {
|
||||
const bool transp = wpd->shading.xray_alpha < 1.0f;
|
||||
DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp;
|
||||
return grp;
|
||||
}
|
||||
default: {
|
||||
/* For now, we use the same ubo for material and object coloring but with different indices.
|
||||
* This means they are mutually exclusive. */
|
||||
BLI_assert(
|
||||
!ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR));
|
||||
|
||||
uint32_t mat_id, id = DRW_object_resource_id_get(ob);
|
||||
|
||||
bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id);
|
||||
workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type);
|
||||
|
||||
const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f;
|
||||
DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp;
|
||||
if (resource_changed) {
|
||||
grp = DRW_shgroup_create_sub(grp);
|
||||
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
|
||||
}
|
||||
if (r_transp && transp) {
|
||||
*r_transp = true;
|
||||
}
|
||||
return grp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */
|
||||
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
int mat_nr,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
int interp,
|
||||
bool hair)
|
||||
{
|
||||
GPUTexture *tex = NULL, *tex_tile_data = NULL;
|
||||
|
||||
if (ima == NULL) {
|
||||
workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp);
|
||||
}
|
||||
|
||||
if (ima) {
|
||||
if (ima->source == IMA_SRC_TILED) {
|
||||
tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D_ARRAY);
|
||||
tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_1D_ARRAY);
|
||||
}
|
||||
else {
|
||||
GPUTexture *tex = GPU_texture_from_blender(
|
||||
material->ima, material->iuser, NULL, GL_TEXTURE_2D);
|
||||
DRW_shgroup_uniform_texture(grp, "image", tex);
|
||||
tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D);
|
||||
}
|
||||
DRW_shgroup_uniform_bool_copy(
|
||||
grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL));
|
||||
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
|
||||
}
|
||||
|
||||
DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1);
|
||||
|
||||
if (use_highlight) {
|
||||
DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
|
||||
if (tex == NULL) {
|
||||
printf("Image not foudn\n");
|
||||
tex = wpd->dummy_image_tx;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
|
||||
const WORKBENCH_MaterialData *source_material)
|
||||
{
|
||||
copy_v3_v3(dest_material->base_color, source_material->base_color);
|
||||
dest_material->metallic = source_material->metallic;
|
||||
dest_material->roughness = source_material->roughness;
|
||||
dest_material->ima = source_material->ima;
|
||||
dest_material->iuser = source_material->iuser;
|
||||
const bool infront = (ob->dtx & OB_DRAWXRAY) != 0;
|
||||
const bool transp = wpd->shading.xray_alpha < 1.0f;
|
||||
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair];
|
||||
|
||||
DRWShadingGroup **grp_tex = NULL;
|
||||
/* A hashmap stores image shgroups to pack all similar drawcalls together. */
|
||||
if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
|
||||
return *grp_tex;
|
||||
}
|
||||
|
||||
DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp;
|
||||
|
||||
*grp_tex = grp = DRW_shgroup_create_sub(grp);
|
||||
if (tex_tile_data) {
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex);
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data);
|
||||
}
|
||||
else {
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex);
|
||||
}
|
||||
DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
|
||||
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
|
||||
return grp;
|
||||
}
|
||||
|
||||
165
source/blender/draw/engines/workbench/workbench_opaque.c
Normal file
165
source/blender/draw/engines/workbench/workbench_opaque.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Opaque Pieline:
|
||||
*
|
||||
* Use deferred shading to render opaque surfaces.
|
||||
* This decouple the shading cost from scene complexity.
|
||||
*
|
||||
* The rendering is broken down in two passes:
|
||||
* - the pre-pass where we render all the surfaces and output material data.
|
||||
* - the composite pass where we compute the final aspect of the pixels.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
void workbench_opaque_engine_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_FramebufferList *fbl = data->fbl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
DrawEngineType *owner = (DrawEngineType *)&workbench_opaque_engine_init;
|
||||
|
||||
/* Reused the same textures format for transparent pipeline to share the textures. */
|
||||
const eGPUTextureFormat col_tex_format = GPU_RGBA16F;
|
||||
const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA16F;
|
||||
|
||||
wpd->material_buffer_tx = DRW_texture_pool_query_fullscreen(col_tex_format, owner);
|
||||
wpd->normal_buffer_tx = DRW_texture_pool_query_fullscreen(nor_tex_format, owner);
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->opaque_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx),
|
||||
});
|
||||
}
|
||||
|
||||
void workbench_opaque_cache_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP);
|
||||
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
|
||||
|
||||
int opaque = 0;
|
||||
for (int infront = 0; infront < 2; infront++) {
|
||||
DRWPass *pass;
|
||||
if (infront) {
|
||||
DRW_PASS_CREATE(psl->opaque_infront_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
pass = psl->opaque_infront_ps;
|
||||
}
|
||||
else {
|
||||
DRW_PASS_CREATE(psl->opaque_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
pass = psl->opaque_ps;
|
||||
}
|
||||
|
||||
for (int hair = 0; hair < 2; hair++) {
|
||||
wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
|
||||
|
||||
sh = workbench_shader_opaque_get(wpd, hair);
|
||||
|
||||
wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
|
||||
|
||||
wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
|
||||
|
||||
sh = workbench_shader_opaque_image_get(wpd, hair, false);
|
||||
|
||||
wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
|
||||
|
||||
sh = workbench_shader_opaque_image_get(wpd, hair, true);
|
||||
|
||||
wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
|
||||
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL;
|
||||
|
||||
DRW_PASS_CREATE(psl->composite_ps, state);
|
||||
|
||||
sh = workbench_shader_composite_get(wpd);
|
||||
|
||||
grp = DRW_shgroup_create(sh, psl->composite_ps);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx);
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
|
||||
DRW_shgroup_stencil_mask(grp, 0x00);
|
||||
|
||||
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
|
||||
BKE_studiolight_ensure_flag(wpd->studio_light,
|
||||
STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
|
||||
STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
|
||||
struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
|
||||
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
|
||||
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
|
||||
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
|
||||
}
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
|
||||
if (SHADOW_ENABLED(wpd)) {
|
||||
grp = DRW_shgroup_create_sub(grp);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", true);
|
||||
DRW_shgroup_state_disable(grp, DRW_STATE_STENCIL_EQUAL);
|
||||
DRW_shgroup_state_enable(grp, DRW_STATE_STENCIL_NEQUAL);
|
||||
DRW_shgroup_stencil_mask(grp, 0x00);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL |
|
||||
DRW_STATE_STENCIL_ALWAYS;
|
||||
|
||||
DRW_PASS_CREATE(psl->merge_infront_ps, state);
|
||||
|
||||
sh = workbench_shader_merge_infront_get(wpd);
|
||||
|
||||
grp = DRW_shgroup_create(sh, psl->merge_infront_ps);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
|
||||
DRW_shgroup_stencil_mask(grp, 0x00);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
}
|
||||
@@ -34,16 +34,14 @@
|
||||
|
||||
#include "workbench_engine.h"
|
||||
|
||||
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
|
||||
#define MAX_COMPOSITE_SHADERS (1 << 7)
|
||||
#define MAX_PREPASS_SHADERS (1 << 8)
|
||||
#define MAX_ACCUM_SHADERS (1 << 8)
|
||||
#define MAX_CAVITY_SHADERS (1 << 3)
|
||||
extern struct DrawEngineType draw_engine_workbench;
|
||||
|
||||
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
|
||||
|
||||
#define MAX_MATERIAL (1 << 12)
|
||||
|
||||
#define DEBUG_SHADOW_VOLUME 0
|
||||
|
||||
#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR)
|
||||
#define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR)
|
||||
#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR)
|
||||
#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
|
||||
#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO)
|
||||
#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP)
|
||||
#define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0)
|
||||
@@ -63,45 +61,24 @@
|
||||
(wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH)))
|
||||
#define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd))
|
||||
#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
|
||||
#define GHOST_ENABLED(psl) \
|
||||
(!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass))
|
||||
#define CULL_BACKFACE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_BACKFACE_CULLING) != 0)
|
||||
#define OIT_ENABLED(wpd) \
|
||||
(ELEM(wpd->shading.color_type, \
|
||||
V3D_SHADING_MATERIAL_COLOR, \
|
||||
V3D_SHADING_OBJECT_COLOR, \
|
||||
V3D_SHADING_TEXTURE_COLOR, \
|
||||
V3D_SHADING_VERTEX_COLOR))
|
||||
|
||||
#define IS_NAVIGATING(wpd) \
|
||||
((DRW_context_state_get()->rv3d) && \
|
||||
(DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)))
|
||||
|
||||
#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
|
||||
#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
|
||||
#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \
|
||||
(MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd))
|
||||
#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \
|
||||
(NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
|
||||
#define NORMAL_ENCODING_ENABLED() (true)
|
||||
#define WORLD_CLIPPING_ENABLED(wpd) (wpd->world_clip_planes != NULL)
|
||||
|
||||
struct RenderEngine;
|
||||
struct RenderLayer;
|
||||
struct rcti;
|
||||
|
||||
typedef struct WORKBENCH_FramebufferList {
|
||||
/* Deferred render buffers */
|
||||
struct GPUFrameBuffer *prepass_fb;
|
||||
struct GPUFrameBuffer *ghost_prepass_fb;
|
||||
struct GPUFrameBuffer *cavity_fb;
|
||||
struct GPUFrameBuffer *composite_fb;
|
||||
struct GPUFrameBuffer *id_clear_fb;
|
||||
struct GPUFrameBuffer *opaque_fb;
|
||||
struct GPUFrameBuffer *opaque_infront_fb;
|
||||
|
||||
struct GPUFrameBuffer *effect_fb;
|
||||
struct GPUFrameBuffer *effect_taa_fb;
|
||||
struct GPUFrameBuffer *depth_buffer_fb;
|
||||
struct GPUFrameBuffer *color_only_fb;
|
||||
struct GPUFrameBuffer *transp_accum_fb;
|
||||
struct GPUFrameBuffer *transp_accum_infront_fb;
|
||||
|
||||
struct GPUFrameBuffer *id_clear_fb;
|
||||
|
||||
struct GPUFrameBuffer *dof_downsample_fb;
|
||||
struct GPUFrameBuffer *dof_coc_tile_h_fb;
|
||||
@@ -110,10 +87,9 @@ typedef struct WORKBENCH_FramebufferList {
|
||||
struct GPUFrameBuffer *dof_blur1_fb;
|
||||
struct GPUFrameBuffer *dof_blur2_fb;
|
||||
|
||||
/* Forward render buffers */
|
||||
struct GPUFrameBuffer *object_outline_fb;
|
||||
struct GPUFrameBuffer *transparent_accum_fb;
|
||||
struct GPUFrameBuffer *transparent_revealage_fb;
|
||||
struct GPUFrameBuffer *antialiasing_fb;
|
||||
struct GPUFrameBuffer *smaa_edge_fb;
|
||||
struct GPUFrameBuffer *smaa_weight_fb;
|
||||
} WORKBENCH_FramebufferList;
|
||||
|
||||
typedef struct WORKBENCH_TextureList {
|
||||
@@ -121,34 +97,35 @@ typedef struct WORKBENCH_TextureList {
|
||||
struct GPUTexture *coc_halfres_tx;
|
||||
struct GPUTexture *history_buffer_tx;
|
||||
struct GPUTexture *depth_buffer_tx;
|
||||
struct GPUTexture *smaa_search_tx;
|
||||
struct GPUTexture *smaa_area_tx;
|
||||
struct GPUTexture *dummy_image_tx;
|
||||
struct GPUTexture *dummy_volume_tx;
|
||||
struct GPUTexture *dummy_coba_tx;
|
||||
} WORKBENCH_TextureList;
|
||||
|
||||
typedef struct WORKBENCH_StorageList {
|
||||
struct WORKBENCH_PrivateData *g_data;
|
||||
struct WORKBENCH_EffectInfo *effects;
|
||||
struct WORKBENCH_PrivateData *wpd;
|
||||
float *dof_ubo_data;
|
||||
} WORKBENCH_StorageList;
|
||||
|
||||
typedef struct WORKBENCH_PassList {
|
||||
/* deferred rendering */
|
||||
struct DRWPass *prepass_pass;
|
||||
struct DRWPass *prepass_hair_pass;
|
||||
struct DRWPass *ghost_prepass_pass;
|
||||
struct DRWPass *ghost_prepass_hair_pass;
|
||||
struct DRWPass *cavity_pass;
|
||||
struct DRWPass *shadow_depth_pass_pass;
|
||||
struct DRWPass *shadow_depth_pass_mani_pass;
|
||||
struct DRWPass *shadow_depth_fail_pass;
|
||||
struct DRWPass *shadow_depth_fail_mani_pass;
|
||||
struct DRWPass *shadow_depth_fail_caps_pass;
|
||||
struct DRWPass *shadow_depth_fail_caps_mani_pass;
|
||||
struct DRWPass *composite_pass;
|
||||
struct DRWPass *composite_shadow_pass;
|
||||
struct DRWPass *oit_composite_pass;
|
||||
struct DRWPass *background_pass;
|
||||
struct DRWPass *background_pass_clip;
|
||||
struct DRWPass *ghost_resolve_pass;
|
||||
struct DRWPass *effect_aa_pass;
|
||||
struct DRWPass *opaque_ps;
|
||||
struct DRWPass *opaque_infront_ps;
|
||||
|
||||
struct DRWPass *transp_resolve_ps;
|
||||
struct DRWPass *transp_accum_ps;
|
||||
struct DRWPass *transp_accum_infront_ps;
|
||||
|
||||
struct DRWPass *shadow_ps[2];
|
||||
|
||||
struct DRWPass *merge_infront_ps;
|
||||
|
||||
struct DRWPass *cavity_ps;
|
||||
struct DRWPass *outline_ps;
|
||||
|
||||
struct DRWPass *composite_ps;
|
||||
|
||||
struct DRWPass *dof_down_ps;
|
||||
struct DRWPass *dof_down2_ps;
|
||||
struct DRWPass *dof_flatten_v_ps;
|
||||
@@ -158,12 +135,13 @@ typedef struct WORKBENCH_PassList {
|
||||
struct DRWPass *dof_blur1_ps;
|
||||
struct DRWPass *dof_blur2_ps;
|
||||
struct DRWPass *dof_resolve_ps;
|
||||
struct DRWPass *volume_pass;
|
||||
|
||||
/* forward rendering */
|
||||
struct DRWPass *transparent_accum_pass;
|
||||
struct DRWPass *object_outline_pass;
|
||||
struct DRWPass *depth_pass;
|
||||
struct DRWPass *volume_ps;
|
||||
|
||||
struct DRWPass *aa_accum_ps;
|
||||
struct DRWPass *aa_edge_ps;
|
||||
struct DRWPass *aa_weight_ps;
|
||||
struct DRWPass *aa_resolve_ps;
|
||||
} WORKBENCH_PassList;
|
||||
|
||||
typedef struct WORKBENCH_Data {
|
||||
@@ -180,84 +158,164 @@ typedef struct WORKBENCH_UBO_Light {
|
||||
float diffuse_color[3], wrapped;
|
||||
} WORKBENCH_UBO_Light;
|
||||
|
||||
typedef struct WORKBENCH_UBO_Material {
|
||||
float base_color[3];
|
||||
/* Packed data into a int. Decoded in the shader. */
|
||||
uint32_t packed_data;
|
||||
} WORKBENCH_UBO_Material;
|
||||
|
||||
typedef struct WORKBENCH_UBO_World {
|
||||
float viewvecs[3][4];
|
||||
float viewport_size[2], viewport_size_inv[2];
|
||||
float object_outline_color[4];
|
||||
float shadow_direction_vs[4];
|
||||
float shadow_focus, shadow_shift, shadow_mul, shadow_add;
|
||||
WORKBENCH_UBO_Light lights[4];
|
||||
float ambient_color[4];
|
||||
int num_lights;
|
||||
int matcap_orientation;
|
||||
|
||||
int cavity_sample_start;
|
||||
int cavity_sample_end;
|
||||
float cavity_sample_count_inv;
|
||||
float cavity_jitter_scale;
|
||||
|
||||
float cavity_valley_factor;
|
||||
float cavity_ridge_factor;
|
||||
float cavity_attenuation;
|
||||
float cavity_distance;
|
||||
|
||||
float curvature_ridge;
|
||||
float curvature_valley;
|
||||
float ui_scale;
|
||||
float _pad0;
|
||||
|
||||
int matcap_orientation;
|
||||
int use_specular; /* Bools are 32bit ints in GLSL. */
|
||||
int _pad1;
|
||||
int _pad2;
|
||||
} WORKBENCH_UBO_World;
|
||||
|
||||
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
|
||||
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Light, 16)
|
||||
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16)
|
||||
|
||||
typedef struct WORKBENCH_Prepass {
|
||||
/** Hash storing shading group for each Material or GPUTexture to reduce state changes. */
|
||||
struct GHash *material_hash;
|
||||
/** First common (non-vcol and non-image colored) shading group to created subgroups. */
|
||||
struct DRWShadingGroup *common_shgrp;
|
||||
/** First Vertex Color shading group to created subgroups. */
|
||||
struct DRWShadingGroup *vcol_shgrp;
|
||||
/** First Image shading group to created subgroups. */
|
||||
struct DRWShadingGroup *image_shgrp;
|
||||
/** First UDIM (tiled image) shading group to created subgroups. */
|
||||
struct DRWShadingGroup *image_tiled_shgrp;
|
||||
} WORKBENCH_Prepass;
|
||||
|
||||
typedef struct WORKBENCH_PrivateData {
|
||||
struct GHash *material_hash;
|
||||
struct GHash *material_transp_hash;
|
||||
struct GPUShader *prepass_sh;
|
||||
struct GPUShader *prepass_hair_sh;
|
||||
struct GPUShader *prepass_uniform_sh;
|
||||
struct GPUShader *prepass_uniform_hair_sh;
|
||||
struct GPUShader *prepass_textured_sh;
|
||||
struct GPUShader *prepass_textured_array_sh;
|
||||
struct GPUShader *prepass_vertex_sh;
|
||||
struct GPUShader *composite_sh;
|
||||
struct GPUShader *background_sh;
|
||||
struct GPUShader *transparent_accum_sh;
|
||||
struct GPUShader *transparent_accum_hair_sh;
|
||||
struct GPUShader *transparent_accum_uniform_sh;
|
||||
struct GPUShader *transparent_accum_uniform_hair_sh;
|
||||
struct GPUShader *transparent_accum_textured_sh;
|
||||
struct GPUShader *transparent_accum_textured_array_sh;
|
||||
struct GPUShader *transparent_accum_vertex_sh;
|
||||
/** ViewLayerData for faster access. */
|
||||
struct WORKBENCH_ViewLayerData *vldata;
|
||||
/** Copy of draw_ctx->sh_cfg for faster access. */
|
||||
eGPUShaderConfig sh_cfg;
|
||||
/** Global clip and cull states. */
|
||||
DRWState clip_state, cull_state;
|
||||
/** Copy of scene->display.shading or v3d->shading for viewport. */
|
||||
View3DShading shading;
|
||||
/** Chosen studiolight or matcap. */
|
||||
StudioLight *studio_light;
|
||||
/** Copy of ctx_draw->scene for faster access. */
|
||||
struct Scene *scene;
|
||||
/** Shorthand version of U global for user preferences. */
|
||||
const UserDef *preferences;
|
||||
/* Does this instance owns the `world_ubo` field.
|
||||
* Normally the field is borrowed from `WORKBENCH_WorldData`. In case that
|
||||
* there is no World attached to the scene the UBO cannot be cached and should
|
||||
* be freed after using. */
|
||||
bool is_world_ubo_owner;
|
||||
/** Copy of context mode for faster access. */
|
||||
eContextObjectMode ctx_mode;
|
||||
/** Shorthand for wpd->vldata->world_ubo. */
|
||||
struct GPUUniformBuffer *world_ubo;
|
||||
struct DRWShadingGroup *shadow_shgrp;
|
||||
struct DRWShadingGroup *depth_shgrp;
|
||||
WORKBENCH_UBO_World world_data;
|
||||
float shadow_multiplier;
|
||||
float shadow_shift;
|
||||
float shadow_focus;
|
||||
float cached_shadow_direction[3];
|
||||
/** Background color to clear the color buffer with. */
|
||||
float background_color[4];
|
||||
|
||||
/* Shadow */
|
||||
/** Previous shadow direction to test if shadow has changed. */
|
||||
float shadow_cached_direction[3];
|
||||
/** Current shadow direction in world space. */
|
||||
float shadow_direction_ws[3];
|
||||
/** Shadow precomputed matrices. */
|
||||
float shadow_mat[4][4];
|
||||
float shadow_inv[4][4];
|
||||
/* Far plane of the view frustum. */
|
||||
/** Far plane of the view frustum. Used for shadow volume extrusion. */
|
||||
float shadow_far_plane[4];
|
||||
/* Near plane corners in shadow space. */
|
||||
float shadow_near_corners[4][3];
|
||||
/* min and max of shadow_near_corners. allow fast test */
|
||||
/** Min and max of shadow_near_corners. Speed up culling test. */
|
||||
float shadow_near_min[3];
|
||||
float shadow_near_max[3];
|
||||
/* This is a parallelogram, so only 2 normal and distance to the edges. */
|
||||
/** This is a parallelogram, so only 2 normal and distance to the edges. */
|
||||
float shadow_near_sides[2][4];
|
||||
/* Shadow shading groups. First array elem is for non-manifold geom and second for manifold. */
|
||||
struct DRWShadingGroup *shadow_pass_grp[2];
|
||||
struct DRWShadingGroup *shadow_fail_grp[2];
|
||||
struct DRWShadingGroup *shadow_fail_caps_grp[2];
|
||||
/** If the shadow has changed direction and ob bboxes needs to be updated. */
|
||||
bool shadow_changed;
|
||||
bool is_playback;
|
||||
|
||||
float (*world_clip_planes)[4];
|
||||
/* Temporal Antialiasing */
|
||||
/** Total number of samples to after which TAA stops accumulating samples. */
|
||||
int taa_sample_len;
|
||||
/** Current TAA sample index in [0..taa_sample_len[ range. */
|
||||
int taa_sample;
|
||||
/** Inverse of taa_sample to divide the accumulation buffer. */
|
||||
float taa_sample_inv;
|
||||
/** If the view has been updated and TAA needs to be reset. */
|
||||
bool view_updated;
|
||||
/** View */
|
||||
struct DRWView *view;
|
||||
/** Last projection matrix to see if view is still valid. */
|
||||
float last_mat[4][4];
|
||||
|
||||
/* Smart Morphological Anti-Aliasing */
|
||||
/** Temp buffers to store edges and weights. */
|
||||
struct GPUTexture *smaa_edge_tx;
|
||||
struct GPUTexture *smaa_weight_tx;
|
||||
/** Weight of the smaa pass. */
|
||||
float smaa_mix_factor;
|
||||
|
||||
/** Opaque pipeline buffers. */
|
||||
struct GPUTexture *material_buffer_tx;
|
||||
struct GPUTexture *composite_buffer_tx;
|
||||
struct GPUTexture *normal_buffer_tx;
|
||||
/** Transparent pipeline buffers. */
|
||||
struct GPUTexture *accum_buffer_tx;
|
||||
struct GPUTexture *reveal_buffer_tx;
|
||||
/** Object IDs buffer for curvature & outline. */
|
||||
struct GPUTexture *object_id_tx;
|
||||
|
||||
/** Prepass infos for each draw types [transparent][infront][hair]. */
|
||||
WORKBENCH_Prepass prepass[2][2][2];
|
||||
|
||||
/* Materials */
|
||||
/** Copy of vldata->material_ubo for faster access. */
|
||||
struct BLI_memblock *material_ubo;
|
||||
/** Copy of vldata->material_ubo_data for faster access. */
|
||||
struct BLI_memblock *material_ubo_data;
|
||||
/** Current material chunk being filled by workbench_material_setup_ex(). */
|
||||
WORKBENCH_UBO_Material *material_ubo_data_curr;
|
||||
struct GPUUniformBuffer *material_ubo_curr;
|
||||
/** Copy of txl->dummy_image_tx for faster access. */
|
||||
struct GPUTexture *dummy_image_tx;
|
||||
/** Total number of used material chunk. */
|
||||
int material_chunk_count;
|
||||
/** Index of current material chunk. */
|
||||
int material_chunk_curr;
|
||||
/** Index of current material inside the material chunk. Only for material coloring mode. */
|
||||
int material_index;
|
||||
|
||||
/* Volumes */
|
||||
bool volumes_do;
|
||||
/** List of smoke domain textures to free after drawing. */
|
||||
ListBase smoke_domains;
|
||||
|
||||
/* Ssao */
|
||||
float winmat[4][4];
|
||||
float viewvecs[3][4];
|
||||
float ssao_params[4];
|
||||
float ssao_settings[4];
|
||||
|
||||
/* Dof */
|
||||
/* Depth of Field */
|
||||
/** Depth of field temp buffers. */
|
||||
struct GPUTexture *dof_blur_tx;
|
||||
struct GPUTexture *coc_temp_tx;
|
||||
struct GPUTexture *coc_tiles_tx[2];
|
||||
struct GPUUniformBuffer *dof_ubo;
|
||||
/** Depth of field parameters. */
|
||||
float dof_aperturesize;
|
||||
float dof_distance;
|
||||
float dof_invsensorsize;
|
||||
@@ -265,37 +323,15 @@ typedef struct WORKBENCH_PrivateData {
|
||||
float dof_blades;
|
||||
float dof_rotation;
|
||||
float dof_ratio;
|
||||
|
||||
/** True if any volume needs to be rendered. */
|
||||
bool volumes_do;
|
||||
/** Convenience boolean. */
|
||||
bool dof_enabled;
|
||||
|
||||
/* Color Management */
|
||||
bool use_color_management;
|
||||
bool use_color_render_settings;
|
||||
bool is_playback;
|
||||
bool is_navigating;
|
||||
} WORKBENCH_PrivateData; /* Transient data */
|
||||
|
||||
typedef struct WORKBENCH_EffectInfo {
|
||||
/** View */
|
||||
struct DRWView *view;
|
||||
/** Last projection matrix to see if view is still valid. */
|
||||
float last_mat[4][4];
|
||||
int jitter_index;
|
||||
float taa_mix_factor;
|
||||
bool view_updated;
|
||||
} WORKBENCH_EffectInfo;
|
||||
|
||||
typedef struct WORKBENCH_MaterialData {
|
||||
float base_color[3], metallic;
|
||||
float roughness, alpha;
|
||||
eV3DShadingColorType color_type;
|
||||
int interp;
|
||||
Image *ima;
|
||||
ImageUser *iuser;
|
||||
|
||||
/* Linked shgroup for drawing */
|
||||
DRWShadingGroup *shgrp;
|
||||
/* forward rendering */
|
||||
DRWShadingGroup *shgrp_object_outline;
|
||||
} WORKBENCH_MaterialData;
|
||||
|
||||
typedef struct WORKBENCH_ObjectData {
|
||||
DrawData dd;
|
||||
|
||||
@@ -307,20 +343,21 @@ typedef struct WORKBENCH_ObjectData {
|
||||
bool shadow_bbox_dirty;
|
||||
} WORKBENCH_ObjectData;
|
||||
|
||||
typedef struct WORKBENCH_WorldData {
|
||||
DrawData dd;
|
||||
/* The cached `GPUUniformBuffer`, that is reused between draw calls. */
|
||||
typedef struct WORKBENCH_ViewLayerData {
|
||||
/** Depth of field sample location array.*/
|
||||
struct GPUUniformBuffer *dof_sample_ubo;
|
||||
/** All constant data used for a render loop.*/
|
||||
struct GPUUniformBuffer *world_ubo;
|
||||
} WORKBENCH_WorldData;
|
||||
|
||||
/* Enumeration containing override options for base color rendering.
|
||||
* This is used to during painting to force the base color to show what you are
|
||||
* painting using the selected lighting model. */
|
||||
typedef enum WORKBENCH_ColorOverride {
|
||||
WORKBENCH_COLOR_OVERRIDE_OFF = 0,
|
||||
WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE,
|
||||
WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX,
|
||||
} WORKBENCH_ColorOverride;
|
||||
/** Cavity sample location array.*/
|
||||
struct GPUUniformBuffer *cavity_sample_ubo;
|
||||
/** Blue noise texture used to randomize the sampling of some effects.*/
|
||||
struct GPUTexture *cavity_jitter_tx;
|
||||
/** Materials ubos allocated in a memblock for easy bookeeping. */
|
||||
struct BLI_memblock *material_ubo;
|
||||
struct BLI_memblock *material_ubo_data;
|
||||
/** Number of samples for which cavity_sample_ubo is valid. */
|
||||
int cavity_sample_count;
|
||||
} WORKBENCH_ViewLayerData;
|
||||
|
||||
/* inline helper functions */
|
||||
BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd)
|
||||
@@ -333,234 +370,129 @@ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *w
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
if (DRW_state_is_image_render()) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
if (draw_ctx->v3d) {
|
||||
return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
else {
|
||||
return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !(IS_NAVIGATING(wpd) || wpd->is_playback) &&
|
||||
wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
}
|
||||
/* workbench_opaque.c */
|
||||
void workbench_opaque_engine_init(WORKBENCH_Data *data);
|
||||
void workbench_opaque_cache_init(WORKBENCH_Data *data);
|
||||
|
||||
BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
if (DRW_state_is_image_render()) {
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
if (draw_ctx->v3d) {
|
||||
return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
else {
|
||||
return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) {
|
||||
return true;
|
||||
}
|
||||
/* workbench_transparent.c */
|
||||
void workbench_transparent_engine_init(WORKBENCH_Data *data);
|
||||
void workbench_transparent_cache_init(WORKBENCH_Data *data);
|
||||
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
|
||||
|
||||
/* when navigating or animation playback use FXAA if scene uses TAA. */
|
||||
return (IS_NAVIGATING(wpd) || wpd->is_playback) &&
|
||||
wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA;
|
||||
}
|
||||
}
|
||||
/* workbench_shadow.c */
|
||||
void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
|
||||
void workbench_shadow_cache_init(WORKBENCH_Data *data);
|
||||
void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat);
|
||||
|
||||
/** Is texture paint mode enabled (globally) */
|
||||
BLI_INLINE bool workbench_is_in_texture_paint_mode(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT;
|
||||
}
|
||||
/* workbench_shader.c */
|
||||
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair);
|
||||
GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled);
|
||||
GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd);
|
||||
GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *wpd);
|
||||
|
||||
/** Is vertex paint mode enabled (globally) */
|
||||
BLI_INLINE bool workbench_is_in_vertex_paint_mode(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT;
|
||||
}
|
||||
GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair);
|
||||
GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
|
||||
bool hair,
|
||||
bool tiled);
|
||||
GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd);
|
||||
|
||||
/* Must the `View3DShading.color_type` be overriden for the given object. */
|
||||
BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
if (ob->type == OB_MESH && (draw_ctx->obact == ob)) {
|
||||
const enum eContextObjectMode mode = CTX_data_mode_enum_ex(
|
||||
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
|
||||
if (mode == CTX_MODE_PAINT_TEXTURE) {
|
||||
return WORKBENCH_COLOR_OVERRIDE_TEXTURE;
|
||||
}
|
||||
else if (mode == CTX_MODE_PAINT_VERTEX) {
|
||||
return WORKBENCH_COLOR_OVERRIDE_VERTEX;
|
||||
}
|
||||
}
|
||||
GPUShader *workbench_shader_shadow_pass_get(bool manifold);
|
||||
GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap);
|
||||
|
||||
return WORKBENCH_COLOR_OVERRIDE_OFF;
|
||||
}
|
||||
GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature);
|
||||
GPUShader *workbench_shader_outline_get(void);
|
||||
|
||||
BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) ||
|
||||
workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode();
|
||||
}
|
||||
GPUShader *workbench_shader_antialiasing_accumulation_get(void);
|
||||
GPUShader *workbench_shader_antialiasing_get(int stage);
|
||||
|
||||
/**
|
||||
* Get the default texture format to be used by the color and history buffers.
|
||||
*
|
||||
* Use GPU_RGBA16F for final renderings and for drawing textures. This
|
||||
* allows displaying HDRI textures. Vertex Colors uses GPU_RGBA16 to resolve
|
||||
* color banding issues (T66100). All other modes use GPU_RGBA8 to reduce
|
||||
* bandwidth and gpu memory.
|
||||
*/
|
||||
BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
eGPUTextureFormat result;
|
||||
if (DRW_state_is_image_render() || workbench_is_in_texture_paint_mode() ||
|
||||
TEXTURE_DRAWING_ENABLED(wpd)) {
|
||||
result = GPU_RGBA16F;
|
||||
}
|
||||
else {
|
||||
result = GPU_RGBA16;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic);
|
||||
|
||||
/* workbench_deferred.c */
|
||||
void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_deferred_engine_free(void);
|
||||
void workbench_deferred_draw_scene(WORKBENCH_Data *vedata);
|
||||
void workbench_deferred_draw_finish(WORKBENCH_Data *vedata);
|
||||
void workbench_deferred_cache_init(WORKBENCH_Data *vedata);
|
||||
void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob);
|
||||
void workbench_deferred_cache_finish(WORKBENCH_Data *vedata);
|
||||
void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
|
||||
GPUShader **downsample_sh,
|
||||
GPUShader **blur1_sh,
|
||||
GPUShader **blur2_sh,
|
||||
GPUShader **resolve_sh);
|
||||
|
||||
/* workbench_forward.c */
|
||||
void workbench_forward_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_forward_engine_free(void);
|
||||
void workbench_forward_draw_scene(WORKBENCH_Data *vedata);
|
||||
void workbench_forward_draw_finish(WORKBENCH_Data *vedata);
|
||||
void workbench_forward_cache_init(WORKBENCH_Data *vedata);
|
||||
void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob);
|
||||
void workbench_forward_cache_finish(WORKBENCH_Data *vedata);
|
||||
void workbench_shader_library_ensure(void);
|
||||
void workbench_shader_free(void);
|
||||
|
||||
/* For OIT in deferred */
|
||||
void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
|
||||
void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg);
|
||||
WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(
|
||||
WORKBENCH_Data *vedata,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
eV3DShadingColorType color_type,
|
||||
int interp);
|
||||
/* workbench_effect_antialiasing.c */
|
||||
int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata);
|
||||
void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata);
|
||||
bool workbench_antialiasing_setup(WORKBENCH_Data *vedata);
|
||||
void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata);
|
||||
|
||||
/* workbench_effect_aa.c */
|
||||
void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx);
|
||||
void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx);
|
||||
|
||||
/* workbench_effect_fxaa.c */
|
||||
void workbench_fxaa_engine_init(void);
|
||||
void workbench_fxaa_engine_free(void);
|
||||
DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx);
|
||||
|
||||
/* workbench_effect_taa.c */
|
||||
void workbench_taa_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_taa_engine_free(void);
|
||||
DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx);
|
||||
void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata);
|
||||
void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
|
||||
void workbench_taa_view_updated(WORKBENCH_Data *vedata);
|
||||
int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
|
||||
int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata);
|
||||
/* workbench_effect_cavity.c */
|
||||
void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
|
||||
void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_cavity_cache_init(WORKBENCH_Data *data);
|
||||
|
||||
/* workbench_effect_outline.c */
|
||||
void workbench_outline_cache_init(WORKBENCH_Data *data);
|
||||
/* workbench_effect_dof.c */
|
||||
void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera);
|
||||
void workbench_dof_engine_free(void);
|
||||
void workbench_dof_create_pass(WORKBENCH_Data *vedata,
|
||||
GPUTexture **dof_input,
|
||||
GPUTexture *noise_tex);
|
||||
void workbench_dof_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_dof_cache_init(WORKBENCH_Data *vedata);
|
||||
void workbench_dof_draw_pass(WORKBENCH_Data *vedata);
|
||||
|
||||
/* workbench_materials.c */
|
||||
eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
|
||||
Image *ima,
|
||||
Object *ob,
|
||||
bool use_sculpt_pbvh);
|
||||
void workbench_material_get_image_and_mat(
|
||||
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat);
|
||||
char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override);
|
||||
void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
WORKBENCH_MaterialData *data,
|
||||
int color_type);
|
||||
uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost);
|
||||
int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd);
|
||||
int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override);
|
||||
int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
|
||||
bool is_uniform_color,
|
||||
bool is_hair,
|
||||
bool is_tiled,
|
||||
const WORKBENCH_ColorOverride color_override);
|
||||
void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
|
||||
DRWShadingGroup *grp,
|
||||
WORKBENCH_MaterialData *material,
|
||||
Object *ob,
|
||||
const bool deferred,
|
||||
const bool is_tiled,
|
||||
const int interp);
|
||||
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
|
||||
const WORKBENCH_MaterialData *source_material);
|
||||
void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
Material *mat,
|
||||
WORKBENCH_UBO_Material *data,
|
||||
eV3DShadingColorType color_type);
|
||||
|
||||
/* workbench_studiolight.c */
|
||||
void studiolight_update_world(WORKBENCH_PrivateData *wpd,
|
||||
StudioLight *sl,
|
||||
WORKBENCH_UBO_World *wd);
|
||||
void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]);
|
||||
bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed);
|
||||
float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed);
|
||||
bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed);
|
||||
DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
int mat_nr,
|
||||
eV3DShadingColorType color_type,
|
||||
bool hair,
|
||||
bool *r_transp);
|
||||
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
int mat_nr,
|
||||
Image *ima,
|
||||
ImageUser *iuser,
|
||||
int interp,
|
||||
bool hair);
|
||||
|
||||
#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \
|
||||
workbench_material_setup_ex(wpd, ob, mat_nr, color_type, false, r_transp)
|
||||
#define workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp) \
|
||||
workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, false)
|
||||
|
||||
#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \
|
||||
workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0)
|
||||
#define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \
|
||||
workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, true)
|
||||
|
||||
/* workbench_data.c */
|
||||
void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info);
|
||||
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_private_data_free(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_private_data_get_light_direction(float r_light_direction[3]);
|
||||
void workbench_clear_color_get(float color[4]);
|
||||
void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd);
|
||||
struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd);
|
||||
|
||||
/* workbench_volume.c */
|
||||
void workbench_volume_engine_init(void);
|
||||
void workbench_volume_engine_free(void);
|
||||
void workbench_volume_engine_init(WORKBENCH_Data *vedata);
|
||||
void workbench_volume_cache_init(WORKBENCH_Data *vedata);
|
||||
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
Scene *scene,
|
||||
Object *ob,
|
||||
struct Scene *UNUSED(scene),
|
||||
struct Object *ob,
|
||||
struct ModifierData *md);
|
||||
void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd);
|
||||
void workbench_volume_draw_pass(WORKBENCH_Data *vedata);
|
||||
void workbench_volume_draw_finish(WORKBENCH_Data *vedata);
|
||||
|
||||
/* workbench_engine.c */
|
||||
void workbench_engine_init(void *ved);
|
||||
void workbench_cache_init(void *ved);
|
||||
void workbench_cache_populate(void *ved, Object *ob);
|
||||
void workbench_cache_finish(void *ved);
|
||||
void workbench_draw_sample(void *ved);
|
||||
void workbench_draw_finish(void *ved);
|
||||
|
||||
/* workbench_render.c */
|
||||
void workbench_render(WORKBENCH_Data *vedata,
|
||||
void workbench_render(void *ved,
|
||||
struct RenderEngine *engine,
|
||||
struct RenderLayer *render_layer,
|
||||
const struct rcti *rect);
|
||||
|
||||
@@ -41,20 +41,12 @@
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
static void workbench_render_deferred_cache(void *vedata,
|
||||
struct Object *ob,
|
||||
struct RenderEngine *UNUSED(engine),
|
||||
struct Depsgraph *UNUSED(depsgraph))
|
||||
static void workbench_render_cache(void *vedata,
|
||||
struct Object *ob,
|
||||
struct RenderEngine *UNUSED(engine),
|
||||
struct Depsgraph *UNUSED(depsgraph))
|
||||
{
|
||||
workbench_deferred_solid_cache_populate(vedata, ob);
|
||||
}
|
||||
|
||||
static void workbench_render_forward_cache(void *vedata,
|
||||
struct Object *ob,
|
||||
struct RenderEngine *UNUSED(engine),
|
||||
struct Depsgraph *UNUSED(depsgraph))
|
||||
{
|
||||
workbench_forward_cache_populate(vedata, ob);
|
||||
workbench_cache_populate(vedata, ob);
|
||||
}
|
||||
|
||||
static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
@@ -171,18 +163,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_render_framebuffers_finish(void)
|
||||
{
|
||||
}
|
||||
|
||||
void workbench_render(WORKBENCH_Data *data,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
|
||||
{
|
||||
WORKBENCH_Data *data = ved;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
Depsgraph *depsgraph = draw_ctx->depsgraph;
|
||||
workbench_render_matrices_init(engine, depsgraph);
|
||||
|
||||
@@ -191,59 +176,31 @@ void workbench_render(WORKBENCH_Data *data,
|
||||
return;
|
||||
}
|
||||
|
||||
const bool deferred = !XRAY_FLAG_ENABLED(&scene->display);
|
||||
workbench_engine_init(data);
|
||||
|
||||
if (deferred) {
|
||||
/* Init engine. */
|
||||
workbench_deferred_engine_init(data);
|
||||
workbench_cache_init(data);
|
||||
DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache);
|
||||
workbench_cache_finish(data);
|
||||
|
||||
/* Init objects. */
|
||||
workbench_deferred_cache_init(data);
|
||||
DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache);
|
||||
workbench_deferred_cache_finish(data);
|
||||
DRW_render_instance_buffer_finish();
|
||||
DRW_render_instance_buffer_finish();
|
||||
|
||||
/* Also we weed to have a correct fbo bound for DRW_hair_update */
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_hair_update();
|
||||
/* Also we weed to have a correct fbo bound for DRW_hair_update */
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
DRW_hair_update();
|
||||
|
||||
/* Draw. */
|
||||
int num_samples = workbench_taa_calculate_num_iterations(data);
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
if (RE_engine_test_break(engine)) {
|
||||
break;
|
||||
}
|
||||
workbench_deferred_draw_scene(data);
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
|
||||
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) {
|
||||
if (RE_engine_test_break(engine)) {
|
||||
break;
|
||||
}
|
||||
|
||||
workbench_deferred_draw_finish(data);
|
||||
workbench_update_world_ubo(wpd);
|
||||
workbench_draw_sample(data);
|
||||
}
|
||||
else {
|
||||
/* Init engine. */
|
||||
workbench_forward_engine_init(data);
|
||||
|
||||
/* Init objects. */
|
||||
workbench_forward_cache_init(data);
|
||||
DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache);
|
||||
workbench_forward_cache_finish(data);
|
||||
DRW_render_instance_buffer_finish();
|
||||
|
||||
/* Also we weed to have a correct fbo bound for DRW_hair_update */
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_hair_update();
|
||||
|
||||
/* Draw. */
|
||||
int num_samples = workbench_taa_calculate_num_iterations(data);
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
if (RE_engine_test_break(engine)) {
|
||||
break;
|
||||
}
|
||||
|
||||
workbench_forward_draw_scene(data);
|
||||
}
|
||||
|
||||
workbench_forward_draw_finish(data);
|
||||
}
|
||||
workbench_draw_finish(data);
|
||||
|
||||
/* Write render output. */
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
@@ -260,8 +217,6 @@ void workbench_render(WORKBENCH_Data *data,
|
||||
rp->rect);
|
||||
|
||||
workbench_render_result_z(render_layer, viewname, rect);
|
||||
|
||||
workbench_render_framebuffers_finish();
|
||||
}
|
||||
|
||||
void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
|
||||
533
source/blender/draw/engines/workbench/workbench_shader.c
Normal file
533
source/blender/draw/engines/workbench/workbench_shader.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
extern char datatoc_common_hair_lib_glsl[];
|
||||
extern char datatoc_common_view_lib_glsl[];
|
||||
extern char datatoc_common_smaa_lib_glsl[];
|
||||
|
||||
extern char datatoc_workbench_prepass_vert_glsl[];
|
||||
extern char datatoc_workbench_prepass_hair_vert_glsl[];
|
||||
extern char datatoc_workbench_prepass_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_effect_cavity_frag_glsl[];
|
||||
extern char datatoc_workbench_effect_outline_frag_glsl[];
|
||||
extern char datatoc_workbench_effect_dof_frag_glsl[];
|
||||
extern char datatoc_workbench_effect_taa_frag_glsl[];
|
||||
extern char datatoc_workbench_effect_smaa_frag_glsl[];
|
||||
extern char datatoc_workbench_effect_smaa_vert_glsl[];
|
||||
|
||||
extern char datatoc_workbench_composite_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_transparent_accum_frag_glsl[];
|
||||
extern char datatoc_workbench_transparent_resolve_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_merge_infront_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_shadow_vert_glsl[];
|
||||
extern char datatoc_workbench_shadow_geom_glsl[];
|
||||
extern char datatoc_workbench_shadow_caps_geom_glsl[];
|
||||
extern char datatoc_workbench_shadow_debug_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_volume_vert_glsl[];
|
||||
extern char datatoc_workbench_volume_frag_glsl[];
|
||||
|
||||
extern char datatoc_workbench_cavity_lib_glsl[];
|
||||
extern char datatoc_workbench_common_lib_glsl[];
|
||||
extern char datatoc_workbench_curvature_lib_glsl[];
|
||||
extern char datatoc_workbench_data_lib_glsl[];
|
||||
extern char datatoc_workbench_image_lib_glsl[];
|
||||
extern char datatoc_workbench_matcap_lib_glsl[];
|
||||
extern char datatoc_workbench_material_lib_glsl[];
|
||||
extern char datatoc_workbench_shader_interface_lib_glsl[];
|
||||
extern char datatoc_workbench_world_light_lib_glsl[];
|
||||
|
||||
extern char datatoc_gpu_shader_depth_only_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
|
||||
|
||||
/* Maximum number of variations. */
|
||||
#define MAX_LIGHTING 3
|
||||
#define MAX_COLOR 3
|
||||
#define MAX_GEOM 2
|
||||
|
||||
enum {
|
||||
VOLUME_SH_SLICE = 0,
|
||||
VOLUME_SH_COBA,
|
||||
VOLUME_SH_CUBIC,
|
||||
};
|
||||
|
||||
#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
|
||||
|
||||
static struct {
|
||||
struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR];
|
||||
struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR];
|
||||
|
||||
struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
|
||||
struct GPUShader *oit_resolve_sh;
|
||||
struct GPUShader *outline_sh;
|
||||
struct GPUShader *merge_infront_sh;
|
||||
|
||||
struct GPUShader *shadow_depth_pass_sh[2];
|
||||
struct GPUShader *shadow_depth_fail_sh[2][2];
|
||||
|
||||
struct GPUShader *cavity_sh[2][2];
|
||||
|
||||
struct GPUShader *dof_prepare_sh;
|
||||
struct GPUShader *dof_downsample_sh;
|
||||
struct GPUShader *dof_blur1_sh;
|
||||
struct GPUShader *dof_blur2_sh;
|
||||
struct GPUShader *dof_resolve_sh;
|
||||
|
||||
struct GPUShader *aa_accum_sh;
|
||||
struct GPUShader *smaa_sh[3];
|
||||
|
||||
struct GPUShader *volume_sh[2][2][2];
|
||||
|
||||
struct DRWShaderLibrary *lib;
|
||||
} e_data = {{{{NULL}}}};
|
||||
|
||||
void workbench_shader_library_ensure(void)
|
||||
{
|
||||
if (e_data.lib == NULL) {
|
||||
e_data.lib = DRW_shader_library_create();
|
||||
/* NOTE: Theses needs to be ordered by dependencies. */
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib);
|
||||
DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib);
|
||||
}
|
||||
}
|
||||
|
||||
static char *workbench_build_defines(
|
||||
WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature)
|
||||
{
|
||||
char *str = NULL;
|
||||
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
|
||||
}
|
||||
else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
|
||||
}
|
||||
else {
|
||||
BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
|
||||
}
|
||||
|
||||
if (NORMAL_ENCODING_ENABLED()) {
|
||||
BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
|
||||
}
|
||||
|
||||
if (textured) {
|
||||
BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
|
||||
}
|
||||
if (tiled) {
|
||||
BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
|
||||
}
|
||||
if (cavity) {
|
||||
BLI_dynstr_append(ds, "#define USE_CAVITY\n");
|
||||
}
|
||||
if (curvature) {
|
||||
BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
|
||||
}
|
||||
|
||||
str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
return str;
|
||||
}
|
||||
|
||||
static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled)
|
||||
{
|
||||
BLI_assert(2 < MAX_COLOR);
|
||||
return (textured) ? (tiled ? 2 : 1) : 0;
|
||||
}
|
||||
|
||||
static GPUShader *workbench_shader_get_ex(
|
||||
WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled)
|
||||
{
|
||||
int color = workbench_color_index(wpd, textured, tiled);
|
||||
int light = wpd->shading.light;
|
||||
BLI_assert(light < MAX_LIGHTING);
|
||||
struct GPUShader **shader =
|
||||
(transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][hair][light][color] :
|
||||
&e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color];
|
||||
|
||||
if (*shader == NULL) {
|
||||
char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
|
||||
|
||||
char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl :
|
||||
datatoc_workbench_prepass_frag_glsl;
|
||||
char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file);
|
||||
|
||||
char *vert_file = hair ? datatoc_workbench_prepass_hair_vert_glsl :
|
||||
datatoc_workbench_prepass_vert_glsl;
|
||||
char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file);
|
||||
|
||||
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg];
|
||||
|
||||
*shader = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL},
|
||||
.frag = (const char *[]){frag_src, NULL},
|
||||
.defs = (const char *[]){sh_cfg_data->def,
|
||||
defines,
|
||||
transp ? "#define TRANSPARENT_MATERIAL\n" :
|
||||
"#define OPAQUE_MATERIAL\n",
|
||||
NULL},
|
||||
});
|
||||
|
||||
MEM_freeN(defines);
|
||||
MEM_freeN(frag_src);
|
||||
MEM_freeN(vert_src);
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair)
|
||||
{
|
||||
return workbench_shader_get_ex(wpd, false, hair, false, false);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled)
|
||||
{
|
||||
return workbench_shader_get_ex(wpd, false, hair, true, tiled);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair)
|
||||
{
|
||||
return workbench_shader_get_ex(wpd, true, hair, false, false);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
|
||||
bool hair,
|
||||
bool tiled)
|
||||
{
|
||||
return workbench_shader_get_ex(wpd, true, hair, true, tiled);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
int light = wpd->shading.light;
|
||||
struct GPUShader **shader = &e_data.opaque_composite_sh[light];
|
||||
BLI_assert(light < MAX_LIGHTING);
|
||||
|
||||
if (*shader == NULL) {
|
||||
char *defines = workbench_build_defines(wpd, false, false, false, false);
|
||||
char *frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_workbench_composite_frag_glsl);
|
||||
|
||||
*shader = DRW_shader_create_fullscreen(frag, defines);
|
||||
|
||||
MEM_freeN(defines);
|
||||
MEM_freeN(frag);
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
|
||||
{
|
||||
if (e_data.merge_infront_sh == NULL) {
|
||||
char *frag = DRW_shader_library_create_shader_string(
|
||||
e_data.lib, datatoc_workbench_merge_infront_frag_glsl);
|
||||
|
||||
e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL);
|
||||
|
||||
MEM_freeN(frag);
|
||||
}
|
||||
return e_data.merge_infront_sh;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
if (e_data.oit_resolve_sh == NULL) {
|
||||
char *defines = workbench_build_defines(wpd, false, false, false, false);
|
||||
|
||||
e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
|
||||
datatoc_workbench_transparent_resolve_frag_glsl, defines);
|
||||
|
||||
MEM_freeN(defines);
|
||||
}
|
||||
return e_data.oit_resolve_sh;
|
||||
}
|
||||
|
||||
static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
|
||||
{
|
||||
struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
|
||||
&e_data.shadow_depth_fail_sh[manifold][cap];
|
||||
|
||||
if (*shader == NULL) {
|
||||
#if DEBUG_SHADOW_VOLUME
|
||||
const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
|
||||
#else
|
||||
const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
|
||||
#endif
|
||||
|
||||
*shader = GPU_shader_create_from_arrays({
|
||||
.vert = (const char *[]){datatoc_common_view_lib_glsl,
|
||||
datatoc_workbench_shadow_vert_glsl,
|
||||
NULL},
|
||||
.geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl :
|
||||
datatoc_workbench_shadow_geom_glsl,
|
||||
NULL},
|
||||
.frag = (const char *[]){shadow_frag, NULL},
|
||||
.defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n",
|
||||
(manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
|
||||
NULL},
|
||||
});
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_shadow_pass_get(bool manifold)
|
||||
{
|
||||
return workbench_shader_shadow_pass_get_ex(true, manifold, false);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
|
||||
{
|
||||
return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
|
||||
{
|
||||
BLI_assert(cavity || curvature);
|
||||
struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
|
||||
|
||||
if (*shader == NULL) {
|
||||
char *defines = workbench_build_defines(NULL, false, false, cavity, curvature);
|
||||
char *frag = DRW_shader_library_create_shader_string(
|
||||
e_data.lib, datatoc_workbench_effect_cavity_frag_glsl);
|
||||
|
||||
*shader = DRW_shader_create_fullscreen(frag, defines);
|
||||
|
||||
MEM_freeN(defines);
|
||||
MEM_freeN(frag);
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_outline_get(void)
|
||||
{
|
||||
if (e_data.outline_sh == NULL) {
|
||||
char *frag = DRW_shader_library_create_shader_string(
|
||||
e_data.lib, datatoc_workbench_effect_outline_frag_glsl);
|
||||
|
||||
e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL);
|
||||
|
||||
MEM_freeN(frag);
|
||||
}
|
||||
return e_data.outline_sh;
|
||||
}
|
||||
|
||||
void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
|
||||
GPUShader **downsample_sh,
|
||||
GPUShader **blur1_sh,
|
||||
GPUShader **blur2_sh,
|
||||
GPUShader **resolve_sh)
|
||||
{
|
||||
if (e_data.dof_prepare_sh == NULL) {
|
||||
e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define PREPARE\n");
|
||||
|
||||
e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define DOWNSAMPLE\n");
|
||||
#if 0 /* TODO(fclem) finish COC min_max optimization */
|
||||
e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define FLATTEN_VERTICAL\n");
|
||||
|
||||
e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define FLATTEN_HORIZONTAL\n");
|
||||
|
||||
e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define DILATE_VERTICAL\n");
|
||||
|
||||
e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define DILATE_HORIZONTAL\n");
|
||||
#endif
|
||||
e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define BLUR1\n");
|
||||
|
||||
e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define BLUR2\n");
|
||||
|
||||
e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
|
||||
"#define RESOLVE\n");
|
||||
}
|
||||
|
||||
*prepare_sh = e_data.dof_prepare_sh;
|
||||
*downsample_sh = e_data.dof_downsample_sh;
|
||||
*blur1_sh = e_data.dof_blur1_sh;
|
||||
*blur2_sh = e_data.dof_blur2_sh;
|
||||
*resolve_sh = e_data.dof_resolve_sh;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_antialiasing_accumulation_get(void)
|
||||
{
|
||||
if (e_data.aa_accum_sh == NULL) {
|
||||
char *frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_workbench_effect_taa_frag_glsl);
|
||||
|
||||
e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL);
|
||||
|
||||
MEM_freeN(frag);
|
||||
}
|
||||
return e_data.aa_accum_sh;
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_antialiasing_get(int stage)
|
||||
{
|
||||
BLI_assert(stage < 3);
|
||||
if (!e_data.smaa_sh[stage]) {
|
||||
char stage_define[32];
|
||||
BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
|
||||
|
||||
e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({
|
||||
.vert =
|
||||
(const char *[]){
|
||||
"#define SMAA_INCLUDE_VS 1\n",
|
||||
"#define SMAA_INCLUDE_PS 0\n",
|
||||
"uniform vec4 viewportMetrics;\n",
|
||||
datatoc_common_smaa_lib_glsl,
|
||||
datatoc_workbench_effect_smaa_vert_glsl,
|
||||
NULL,
|
||||
},
|
||||
.frag =
|
||||
(const char *[]){
|
||||
"#define SMAA_INCLUDE_VS 0\n",
|
||||
"#define SMAA_INCLUDE_PS 1\n",
|
||||
"uniform vec4 viewportMetrics;\n",
|
||||
datatoc_common_smaa_lib_glsl,
|
||||
datatoc_workbench_effect_smaa_frag_glsl,
|
||||
NULL,
|
||||
},
|
||||
.defs =
|
||||
(const char *[]){
|
||||
"#define SMAA_GLSL_3\n",
|
||||
"#define SMAA_RT_METRICS viewportMetrics\n",
|
||||
"#define SMAA_PRESET_HIGH\n",
|
||||
"#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n",
|
||||
"#define SMAA_NO_DISCARD\n",
|
||||
stage_define,
|
||||
NULL,
|
||||
},
|
||||
});
|
||||
}
|
||||
return e_data.smaa_sh[stage];
|
||||
}
|
||||
|
||||
GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic)
|
||||
{
|
||||
GPUShader **shader = &e_data.volume_sh[slice][coba][cubic];
|
||||
|
||||
if (*shader == NULL) {
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
if (slice) {
|
||||
BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
|
||||
}
|
||||
if (coba) {
|
||||
BLI_dynstr_append(ds, "#define USE_COBA\n");
|
||||
}
|
||||
if (cubic) {
|
||||
BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
|
||||
}
|
||||
|
||||
char *defines = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
|
||||
char *vert = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_workbench_volume_vert_glsl);
|
||||
char *frag = DRW_shader_library_create_shader_string(e_data.lib,
|
||||
datatoc_workbench_volume_frag_glsl);
|
||||
|
||||
*shader = DRW_shader_create(vert, NULL, frag, defines);
|
||||
|
||||
MEM_freeN(vert);
|
||||
MEM_freeN(frag);
|
||||
MEM_freeN(defines);
|
||||
}
|
||||
return *shader;
|
||||
}
|
||||
|
||||
void workbench_shader_free(void)
|
||||
{
|
||||
for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.opaque_composite_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.shadow_depth_pass_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.smaa_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.smaa_sh[0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
|
||||
struct GPUShader **sh_array = &e_data.volume_sh[0][0][0];
|
||||
DRW_SHADER_FREE_SAFE(sh_array[j]);
|
||||
}
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.outline_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
|
||||
DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
|
||||
|
||||
DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
|
||||
|
||||
DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
|
||||
}
|
||||
367
source/blender/draw/engines/workbench/workbench_shadow.c
Normal file
367
source/blender/draw/engines/workbench/workbench_shadow.c
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Shadow:
|
||||
*
|
||||
* Use stencil shadow buffer to cast a sharp shadow over opaque surfaces.
|
||||
*
|
||||
* After the main prepass we render shadow volumes using custom depth & stencil states to
|
||||
* set the stencil of shadowed area to anything but 0.
|
||||
*
|
||||
* Then the shading pass will shade the areas with stencil not equal 0 differently.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
static void compute_parallel_lines_nor_and_dist(const float v1[2],
|
||||
const float v2[2],
|
||||
const float v3[2],
|
||||
float r_line[4])
|
||||
{
|
||||
sub_v2_v2v2(r_line, v2, v1);
|
||||
/* Find orthogonal vector. */
|
||||
SWAP(float, r_line[0], r_line[1]);
|
||||
r_line[0] = -r_line[0];
|
||||
/* Edge distances. */
|
||||
r_line[2] = dot_v2v2(r_line, v1);
|
||||
r_line[3] = dot_v2v2(r_line, v3);
|
||||
/* Make sure r_line[2] is the minimum. */
|
||||
if (r_line[2] > r_line[3]) {
|
||||
SWAP(float, r_line[2], r_line[3]);
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_shadow_update(WORKBENCH_PrivateData *wpd)
|
||||
{
|
||||
wpd->shadow_changed = !compare_v3v3(
|
||||
wpd->shadow_cached_direction, wpd->shadow_direction_ws, 1e-5f);
|
||||
|
||||
if (wpd->shadow_changed) {
|
||||
float up[3] = {0.0f, 0.0f, 1.0f};
|
||||
unit_m4(wpd->shadow_mat);
|
||||
|
||||
/* TODO fix singularity. */
|
||||
copy_v3_v3(wpd->shadow_mat[2], wpd->shadow_direction_ws);
|
||||
cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
|
||||
normalize_v3(wpd->shadow_mat[0]);
|
||||
cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
|
||||
|
||||
invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
|
||||
|
||||
copy_v3_v3(wpd->shadow_cached_direction, wpd->shadow_direction_ws);
|
||||
}
|
||||
|
||||
float planes[6][4];
|
||||
DRW_culling_frustum_planes_get(NULL, planes);
|
||||
/* we only need the far plane. */
|
||||
copy_v4_v4(wpd->shadow_far_plane, planes[2]);
|
||||
|
||||
BoundBox frustum_corners;
|
||||
DRW_culling_frustum_corners_get(NULL, &frustum_corners);
|
||||
|
||||
float shadow_near_corners[4][3];
|
||||
mul_v3_mat3_m4v3(shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
|
||||
mul_v3_mat3_m4v3(shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
|
||||
mul_v3_mat3_m4v3(shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
|
||||
mul_v3_mat3_m4v3(shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
|
||||
|
||||
INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, shadow_near_corners[i]);
|
||||
}
|
||||
|
||||
compute_parallel_lines_nor_and_dist(shadow_near_corners[0],
|
||||
shadow_near_corners[1],
|
||||
shadow_near_corners[2],
|
||||
wpd->shadow_near_sides[0]);
|
||||
compute_parallel_lines_nor_and_dist(shadow_near_corners[1],
|
||||
shadow_near_corners[2],
|
||||
shadow_near_corners[0],
|
||||
wpd->shadow_near_sides[1]);
|
||||
}
|
||||
|
||||
void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
const Scene *scene = draw_ctx->scene;
|
||||
|
||||
float view_matrix[4][4];
|
||||
DRW_view_viewmat_get(NULL, view_matrix, false);
|
||||
|
||||
/* Turn the light in a way where it's more user friendly to control. */
|
||||
copy_v3_v3(wpd->shadow_direction_ws, scene->display.light_direction);
|
||||
SWAP(float, wpd->shadow_direction_ws[2], wpd->shadow_direction_ws[1]);
|
||||
wpd->shadow_direction_ws[2] = -wpd->shadow_direction_ws[2];
|
||||
wpd->shadow_direction_ws[0] = -wpd->shadow_direction_ws[0];
|
||||
|
||||
/* Shadow direction. */
|
||||
mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->shadow_direction_ws);
|
||||
|
||||
/* Clamp to avoid overshadowing and shading errors. */
|
||||
float focus = clamp_f(scene->display.shadow_focus, 0.0001f, 0.99999f);
|
||||
wd->shadow_shift = scene->display.shadow_shift;
|
||||
wd->shadow_focus = 1.0f - focus * (1.0f - wd->shadow_shift);
|
||||
|
||||
if (SHADOW_ENABLED(wpd)) {
|
||||
wd->shadow_mul = wpd->shading.shadow_intensity;
|
||||
wd->shadow_add = 1.0f - wd->shadow_mul;
|
||||
}
|
||||
else {
|
||||
wd->shadow_mul = 0.0f;
|
||||
wd->shadow_add = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_shadow_cache_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
if (SHADOW_ENABLED(wpd)) {
|
||||
workbench_shadow_update(wpd);
|
||||
|
||||
#if DEBUG_SHADOW_VOLUME
|
||||
DRWState depth_pass_state = DRW_STATE_DEPTH_LESS;
|
||||
DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL;
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL;
|
||||
#else
|
||||
DRWState depth_pass_state = DRW_STATE_WRITE_STENCIL_SHADOW_PASS;
|
||||
DRWState depth_fail_state = DRW_STATE_WRITE_STENCIL_SHADOW_FAIL;
|
||||
DRWState state = DRW_STATE_DEPTH_LESS | DRW_STATE_STENCIL_ALWAYS;
|
||||
#endif
|
||||
|
||||
/* TODO(fclem) Merge into one pass with subpasses. */
|
||||
DRW_PASS_CREATE(psl->shadow_ps[0], state | depth_pass_state);
|
||||
DRW_PASS_CREATE(psl->shadow_ps[1], state | depth_fail_state);
|
||||
|
||||
/* Stencil Shadow passes. */
|
||||
for (int manifold = 0; manifold < 2; manifold++) {
|
||||
sh = workbench_shader_shadow_pass_get(manifold);
|
||||
wpd->shadow_pass_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[0]);
|
||||
DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */
|
||||
|
||||
sh = workbench_shader_shadow_fail_get(manifold, false);
|
||||
wpd->shadow_fail_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]);
|
||||
DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */
|
||||
|
||||
sh = workbench_shader_shadow_fail_get(manifold, true);
|
||||
wpd->shadow_fail_caps_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
psl->shadow_ps[0] = NULL;
|
||||
psl->shadow_ps[1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
if (oed->shadow_bbox_dirty || wpd->shadow_changed) {
|
||||
float tmp_mat[4][4];
|
||||
mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
|
||||
|
||||
/* Get AABB in shadow space. */
|
||||
INIT_MINMAX(oed->shadow_min, oed->shadow_max);
|
||||
|
||||
/* From object space to shadow space */
|
||||
BoundBox *bbox = BKE_object_boundbox_get(ob);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float corner[3];
|
||||
mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
|
||||
minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
|
||||
}
|
||||
oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
|
||||
/* Extend towards infinity. */
|
||||
oed->shadow_max[2] += 1e4f;
|
||||
|
||||
/* Get extended AABB in world space. */
|
||||
BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
|
||||
}
|
||||
oed->shadow_bbox_dirty = false;
|
||||
}
|
||||
|
||||
return &oed->shadow_bbox;
|
||||
}
|
||||
|
||||
static bool workbench_shadow_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
|
||||
const DRWView *default_view = DRW_view_default_get();
|
||||
return DRW_culling_box_test(default_view, shadow_bbox);
|
||||
}
|
||||
|
||||
static float workbench_shadow_object_shadow_distance(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
|
||||
|
||||
int corners[4] = {0, 3, 4, 7};
|
||||
float dist = 1e4f, dist_isect;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
|
||||
wpd->shadow_cached_direction,
|
||||
wpd->shadow_far_plane,
|
||||
&dist_isect,
|
||||
true)) {
|
||||
if (dist_isect < dist) {
|
||||
dist = dist_isect;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* All rays are parallels. If one fails, the other will too. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return max_ii(dist - oed->shadow_depth, 0);
|
||||
}
|
||||
|
||||
static bool workbench_shadow_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
/* Just to be sure the min, max are updated. */
|
||||
workbench_shadow_object_shadow_bbox_get(wpd, ob, oed);
|
||||
/* Test if near plane is in front of the shadow. */
|
||||
if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Separation Axis Theorem test */
|
||||
|
||||
/* Test bbox sides first (faster) */
|
||||
if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
|
||||
(oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
|
||||
(oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
|
||||
(oed->shadow_max[1] < wpd->shadow_near_min[1])) {
|
||||
return false;
|
||||
}
|
||||
/* Test projected near rectangle sides */
|
||||
const float pts[4][2] = {
|
||||
{oed->shadow_min[0], oed->shadow_min[1]},
|
||||
{oed->shadow_min[0], oed->shadow_max[1]},
|
||||
{oed->shadow_max[0], oed->shadow_min[1]},
|
||||
{oed->shadow_max[0], oed->shadow_max[1]},
|
||||
};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
float min_dst = FLT_MAX, max_dst = -FLT_MAX;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
|
||||
/* Do min max */
|
||||
if (min_dst > dst) {
|
||||
min_dst = dst;
|
||||
}
|
||||
if (max_dst < dst) {
|
||||
max_dst = dst;
|
||||
}
|
||||
}
|
||||
|
||||
if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* No separation axis found. Both shape intersect. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void workbench_init_object_data(DrawData *dd)
|
||||
{
|
||||
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
|
||||
data->shadow_bbox_dirty = true;
|
||||
}
|
||||
|
||||
void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat)
|
||||
{
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
|
||||
bool is_manifold;
|
||||
struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold);
|
||||
if (geom_shadow == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
|
||||
&ob->id,
|
||||
&draw_engine_workbench,
|
||||
sizeof(WORKBENCH_ObjectData),
|
||||
&workbench_init_object_data,
|
||||
NULL);
|
||||
|
||||
if (workbench_shadow_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
|
||||
mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->shadow_direction_ws);
|
||||
|
||||
DRWShadingGroup *grp;
|
||||
bool use_shadow_pass_technique = !workbench_shadow_camera_in_object_shadow(
|
||||
wpd, ob, engine_object_data);
|
||||
|
||||
/* Shadow pass technique needs object to be have all its surface opaque. */
|
||||
if (has_transp_mat) {
|
||||
use_shadow_pass_technique = false;
|
||||
}
|
||||
|
||||
if (use_shadow_pass_technique) {
|
||||
grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]);
|
||||
DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
|
||||
DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f);
|
||||
DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
|
||||
#if DEBUG_SHADOW_VOLUME
|
||||
DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
float extrude_distance = workbench_shadow_object_shadow_distance(
|
||||
wpd, ob, engine_object_data);
|
||||
|
||||
/* TODO(fclem): only use caps if they are in the view frustum. */
|
||||
const bool need_caps = true;
|
||||
if (need_caps) {
|
||||
grp = DRW_shgroup_create_sub(wpd->shadow_fail_caps_grp[is_manifold]);
|
||||
DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
|
||||
DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
|
||||
DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob);
|
||||
}
|
||||
|
||||
grp = DRW_shgroup_create_sub(wpd->shadow_fail_grp[is_manifold]);
|
||||
DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
|
||||
DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
|
||||
DRW_shgroup_call_no_cull(grp, geom_shadow, ob);
|
||||
#if DEBUG_SHADOW_VOLUME
|
||||
DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2016, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
#include "BKE_studiolight.h"
|
||||
|
||||
#include "workbench_private.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
void studiolight_update_world(WORKBENCH_PrivateData *wpd,
|
||||
StudioLight *studiolight,
|
||||
WORKBENCH_UBO_World *wd)
|
||||
{
|
||||
float view_matrix[4][4], rot_matrix[4][4];
|
||||
DRW_view_viewmat_get(NULL, view_matrix, false);
|
||||
|
||||
if (USE_WORLD_ORIENTATION(wpd)) {
|
||||
axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
|
||||
mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
|
||||
swap_v3_v3(rot_matrix[2], rot_matrix[1]);
|
||||
negate_v3(rot_matrix[2]);
|
||||
}
|
||||
else {
|
||||
unit_m4(rot_matrix);
|
||||
}
|
||||
|
||||
if (U.edit_studio_light) {
|
||||
studiolight = BKE_studiolight_studio_edit_get();
|
||||
}
|
||||
|
||||
/* Studio Lights. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WORKBENCH_UBO_Light *light = &wd->lights[i];
|
||||
|
||||
SolidLight *sl = &studiolight->light[i];
|
||||
if (sl->flag) {
|
||||
copy_v3_v3(light->light_direction, sl->vec);
|
||||
mul_mat3_m4_v3(rot_matrix, light->light_direction);
|
||||
/* We should predivide the power by PI but that makes the lights really dim. */
|
||||
copy_v3_v3(light->specular_color, sl->spec);
|
||||
copy_v3_v3(light->diffuse_color, sl->col);
|
||||
light->wrapped = sl->smooth;
|
||||
}
|
||||
else {
|
||||
copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
|
||||
copy_v3_fl(light->specular_color, 0.0f);
|
||||
copy_v3_fl(light->diffuse_color, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
|
||||
}
|
||||
|
||||
static void compute_parallel_lines_nor_and_dist(const float v1[2],
|
||||
const float v2[2],
|
||||
const float v3[2],
|
||||
float r_line[4])
|
||||
{
|
||||
sub_v2_v2v2(r_line, v2, v1);
|
||||
/* Find orthogonal vector. */
|
||||
SWAP(float, r_line[0], r_line[1]);
|
||||
r_line[0] = -r_line[0];
|
||||
/* Edge distances. */
|
||||
r_line[2] = dot_v2v2(r_line, v1);
|
||||
r_line[3] = dot_v2v2(r_line, v3);
|
||||
/* Make sure r_line[2] is the minimum. */
|
||||
if (r_line[2] > r_line[3]) {
|
||||
SWAP(float, r_line[2], r_line[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
|
||||
{
|
||||
wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
|
||||
|
||||
if (wpd->shadow_changed) {
|
||||
float up[3] = {0.0f, 0.0f, 1.0f};
|
||||
unit_m4(wpd->shadow_mat);
|
||||
|
||||
/* TODO fix singularity. */
|
||||
copy_v3_v3(wpd->shadow_mat[2], light_direction);
|
||||
cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
|
||||
normalize_v3(wpd->shadow_mat[0]);
|
||||
cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
|
||||
|
||||
invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
|
||||
|
||||
copy_v3_v3(wpd->cached_shadow_direction, light_direction);
|
||||
}
|
||||
|
||||
float planes[6][4];
|
||||
DRW_culling_frustum_planes_get(NULL, planes);
|
||||
/* we only need the far plane. */
|
||||
copy_v4_v4(wpd->shadow_far_plane, planes[2]);
|
||||
|
||||
BoundBox frustum_corners;
|
||||
DRW_culling_frustum_corners_get(NULL, &frustum_corners);
|
||||
|
||||
mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
|
||||
mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
|
||||
mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
|
||||
mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
|
||||
|
||||
INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
|
||||
}
|
||||
|
||||
compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0],
|
||||
wpd->shadow_near_corners[1],
|
||||
wpd->shadow_near_corners[2],
|
||||
wpd->shadow_near_sides[0]);
|
||||
compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1],
|
||||
wpd->shadow_near_corners[2],
|
||||
wpd->shadow_near_corners[0],
|
||||
wpd->shadow_near_sides[1]);
|
||||
}
|
||||
|
||||
static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) {
|
||||
float tmp_mat[4][4];
|
||||
mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
|
||||
|
||||
/* Get AABB in shadow space. */
|
||||
INIT_MINMAX(oed->shadow_min, oed->shadow_max);
|
||||
|
||||
/* From object space to shadow space */
|
||||
BoundBox *bbox = BKE_object_boundbox_get(ob);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float corner[3];
|
||||
mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
|
||||
minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
|
||||
}
|
||||
oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
|
||||
/* Extend towards infinity. */
|
||||
oed->shadow_max[2] += 1e4f;
|
||||
|
||||
/* Get extended AABB in world space. */
|
||||
BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
|
||||
}
|
||||
oed->shadow_bbox_dirty = false;
|
||||
}
|
||||
|
||||
return &oed->shadow_bbox;
|
||||
}
|
||||
|
||||
bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
|
||||
const DRWView *default_view = DRW_view_default_get();
|
||||
return DRW_culling_box_test(default_view, shadow_bbox);
|
||||
}
|
||||
|
||||
float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
|
||||
|
||||
int corners[4] = {0, 3, 4, 7};
|
||||
float dist = 1e4f, dist_isect;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
|
||||
wpd->cached_shadow_direction,
|
||||
wpd->shadow_far_plane,
|
||||
&dist_isect,
|
||||
true)) {
|
||||
if (dist_isect < dist) {
|
||||
dist = dist_isect;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* All rays are parallels. If one fails, the other will too. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return max_ii(dist - oed->shadow_depth, 0);
|
||||
}
|
||||
|
||||
bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd,
|
||||
Object *ob,
|
||||
WORKBENCH_ObjectData *oed)
|
||||
{
|
||||
/* Just to be sure the min, max are updated. */
|
||||
studiolight_object_shadow_bbox_get(wpd, ob, oed);
|
||||
|
||||
/* Test if near plane is in front of the shadow. */
|
||||
if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Separation Axis Theorem test */
|
||||
|
||||
/* Test bbox sides first (faster) */
|
||||
if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
|
||||
(oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
|
||||
(oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
|
||||
(oed->shadow_max[1] < wpd->shadow_near_min[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Test projected near rectangle sides */
|
||||
const float pts[4][2] = {
|
||||
{oed->shadow_min[0], oed->shadow_min[1]},
|
||||
{oed->shadow_min[0], oed->shadow_max[1]},
|
||||
{oed->shadow_max[0], oed->shadow_min[1]},
|
||||
{oed->shadow_max[0], oed->shadow_max[1]},
|
||||
};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
float min_dst = FLT_MAX, max_dst = -FLT_MAX;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
|
||||
/* Do min max */
|
||||
if (min_dst > dst) {
|
||||
min_dst = dst;
|
||||
}
|
||||
if (max_dst < dst) {
|
||||
max_dst = dst;
|
||||
}
|
||||
}
|
||||
|
||||
if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* No separation axis found. Both shape intersect. */
|
||||
return true;
|
||||
}
|
||||
180
source/blender/draw/engines/workbench/workbench_transparent.c
Normal file
180
source/blender/draw/engines/workbench/workbench_transparent.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2020, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Transparent Pieline:
|
||||
*
|
||||
* Use Weight Blended Order Independant Transparency to render transparent surfaces.
|
||||
*
|
||||
* The rendering is broken down in two passes:
|
||||
* - the accumulation pass where we render all the surfaces and accumulate all the weights.
|
||||
* - the resolve pass where we divide the accumulated infos by the weights.
|
||||
*
|
||||
* An additional rerender of the transparent surfaces is sometime done in order to have their
|
||||
* correct depth and object ids correctly written.
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "GPU_extensions.h"
|
||||
|
||||
#include "workbench_engine.h"
|
||||
#include "workbench_private.h"
|
||||
|
||||
void workbench_transparent_engine_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_FramebufferList *fbl = data->fbl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
DrawEngineType *owner = (DrawEngineType *)&workbench_transparent_engine_init;
|
||||
|
||||
/* Reuse same format as opaque pipeline to reuse the textures. */
|
||||
/* Note: Floating point texture is required for the reveal_tex as it is used for
|
||||
* the alpha accumulation component (see accumulation shader for more explanation). */
|
||||
const eGPUTextureFormat accum_tex_format = GPU_RGBA16F;
|
||||
const eGPUTextureFormat reveal_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA32F;
|
||||
|
||||
wpd->accum_buffer_tx = DRW_texture_pool_query_fullscreen(accum_tex_format, owner);
|
||||
wpd->reveal_buffer_tx = DRW_texture_pool_query_fullscreen(reveal_tex_format, owner);
|
||||
|
||||
GPU_framebuffer_ensure_config(&fbl->transp_accum_fb,
|
||||
{
|
||||
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx),
|
||||
});
|
||||
}
|
||||
|
||||
static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
|
||||
DRWShadingGroup *grp)
|
||||
{
|
||||
DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
|
||||
|
||||
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
|
||||
BKE_studiolight_ensure_flag(wpd->studio_light,
|
||||
STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE |
|
||||
STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE);
|
||||
struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture;
|
||||
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
|
||||
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
|
||||
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
|
||||
DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_transparent_cache_init(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
{
|
||||
int transp = 1;
|
||||
for (int infront = 0; infront < 2; infront++) {
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_OIT;
|
||||
|
||||
DRWPass *pass;
|
||||
if (infront) {
|
||||
DRW_PASS_CREATE(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
pass = psl->transp_accum_infront_ps;
|
||||
}
|
||||
else {
|
||||
DRW_PASS_CREATE(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
pass = psl->transp_accum_ps;
|
||||
}
|
||||
|
||||
for (int hair = 0; hair < 2; hair++) {
|
||||
wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
|
||||
|
||||
sh = workbench_shader_transparent_get(wpd, hair);
|
||||
|
||||
wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
|
||||
workbench_transparent_lighting_uniforms(wpd, grp);
|
||||
|
||||
wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
|
||||
|
||||
sh = workbench_shader_transparent_image_get(wpd, hair, false);
|
||||
|
||||
wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
|
||||
workbench_transparent_lighting_uniforms(wpd, grp);
|
||||
|
||||
sh = workbench_shader_transparent_image_get(wpd, hair, true);
|
||||
|
||||
wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
|
||||
DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
|
||||
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
|
||||
workbench_transparent_lighting_uniforms(wpd, grp);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
|
||||
|
||||
DRW_PASS_CREATE(psl->transp_resolve_ps, state);
|
||||
|
||||
sh = workbench_shader_transparent_resolve_get(wpd);
|
||||
|
||||
grp = DRW_shgroup_create(sh, psl->transp_resolve_ps);
|
||||
DRW_shgroup_uniform_texture(grp, "transparentAccum", wpd->accum_buffer_tx);
|
||||
DRW_shgroup_uniform_texture(grp, "transparentRevealage", wpd->reveal_buffer_tx);
|
||||
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Redraw the transparent passes but with depth test
|
||||
* to output correct outline IDs and depth. */
|
||||
void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data)
|
||||
{
|
||||
WORKBENCH_PrivateData *wpd = data->stl->wpd;
|
||||
WORKBENCH_FramebufferList *fbl = data->fbl;
|
||||
WORKBENCH_PassList *psl = data->psl;
|
||||
|
||||
const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f;
|
||||
const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass;
|
||||
|
||||
if (do_transparent_depth_pass) {
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
|
||||
|
||||
if (!DRW_pass_is_empty(psl->transp_accum_ps)) {
|
||||
GPU_framebuffer_bind(fbl->opaque_fb);
|
||||
/* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
|
||||
DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
DRW_draw_pass(psl->transp_accum_ps);
|
||||
}
|
||||
|
||||
if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) {
|
||||
GPU_framebuffer_bind(fbl->opaque_infront_fb);
|
||||
/* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */
|
||||
DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state);
|
||||
DRW_draw_pass(psl->transp_accum_infront_ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,87 +35,23 @@
|
||||
|
||||
#include "GPU_draw.h"
|
||||
|
||||
enum {
|
||||
VOLUME_SH_SLICE = 0,
|
||||
VOLUME_SH_COBA,
|
||||
VOLUME_SH_CUBIC,
|
||||
};
|
||||
|
||||
#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
|
||||
|
||||
static struct {
|
||||
struct GPUShader *volume_sh[VOLUME_SH_MAX];
|
||||
struct GPUShader *volume_coba_sh;
|
||||
struct GPUTexture *dummy_tex;
|
||||
struct GPUTexture *dummy_coba_tex;
|
||||
} e_data = {{NULL}};
|
||||
|
||||
extern char datatoc_workbench_volume_vert_glsl[];
|
||||
extern char datatoc_workbench_volume_frag_glsl[];
|
||||
extern char datatoc_common_view_lib_glsl[];
|
||||
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
|
||||
|
||||
static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
|
||||
void workbench_volume_engine_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
int id = 0;
|
||||
id += (slice) ? (1 << VOLUME_SH_SLICE) : 0;
|
||||
id += (coba) ? (1 << VOLUME_SH_COBA) : 0;
|
||||
id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
|
||||
if (!e_data.volume_sh[id]) {
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
|
||||
if (slice) {
|
||||
BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
|
||||
}
|
||||
if (coba) {
|
||||
BLI_dynstr_append(ds, "#define USE_COBA\n");
|
||||
}
|
||||
if (cubic) {
|
||||
BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
|
||||
}
|
||||
|
||||
char *defines = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
|
||||
char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl,
|
||||
datatoc_gpu_shader_common_obinfos_lib_glsl);
|
||||
|
||||
e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl,
|
||||
NULL,
|
||||
datatoc_workbench_volume_frag_glsl,
|
||||
libs,
|
||||
defines);
|
||||
|
||||
MEM_freeN(libs);
|
||||
MEM_freeN(defines);
|
||||
}
|
||||
|
||||
return e_data.volume_sh[id];
|
||||
}
|
||||
|
||||
void workbench_volume_engine_init(void)
|
||||
{
|
||||
if (!e_data.dummy_tex) {
|
||||
if (txl->dummy_volume_tx == NULL) {
|
||||
float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
e_data.dummy_tex = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
|
||||
e_data.dummy_coba_tex = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
|
||||
txl->dummy_volume_tx = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL);
|
||||
txl->dummy_coba_tx = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_volume_engine_free(void)
|
||||
{
|
||||
for (int i = 0; i < VOLUME_SH_MAX; i++) {
|
||||
DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
|
||||
}
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
|
||||
}
|
||||
|
||||
void workbench_volume_cache_init(WORKBENCH_Data *vedata)
|
||||
{
|
||||
vedata->psl->volume_pass = DRW_pass_create(
|
||||
vedata->psl->volume_ps = DRW_pass_create(
|
||||
"Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
|
||||
|
||||
vedata->stl->wpd->volumes_do = false;
|
||||
}
|
||||
|
||||
void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
@@ -125,8 +61,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
{
|
||||
FluidModifierData *mmd = (FluidModifierData *)md;
|
||||
FluidDomainSettings *mds = mmd->domain;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
|
||||
WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
WORKBENCH_TextureList *txl = vedata->txl;
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
DRWShadingGroup *grp = NULL;
|
||||
|
||||
@@ -154,7 +90,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED &&
|
||||
mds->axis_slice_method == AXIS_SLICE_SINGLE);
|
||||
const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC);
|
||||
GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp);
|
||||
|
||||
GPUShader *sh = workbench_shader_volume_get(use_slice, mds->use_coba, cubic_interp);
|
||||
|
||||
if (use_slice) {
|
||||
float invviewmat[4][4];
|
||||
@@ -168,7 +105,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
/* 0.05f to achieve somewhat the same opacity as the full view. */
|
||||
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
|
||||
|
||||
grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
|
||||
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
|
||||
DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth);
|
||||
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
|
||||
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
|
||||
@@ -176,7 +113,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
}
|
||||
else {
|
||||
double noise_ofs;
|
||||
BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs);
|
||||
BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
|
||||
float dim[3], step_length, max_slice;
|
||||
float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]};
|
||||
mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel));
|
||||
@@ -186,8 +123,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
mul_v3_v3(dim, slice_ct);
|
||||
step_length = len_v3(dim);
|
||||
|
||||
grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
|
||||
DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
|
||||
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
|
||||
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
|
||||
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
|
||||
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
|
||||
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
|
||||
@@ -206,9 +143,9 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density);
|
||||
DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow);
|
||||
DRW_shgroup_uniform_texture(
|
||||
grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex);
|
||||
grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : txl->dummy_volume_tx);
|
||||
DRW_shgroup_uniform_texture(
|
||||
grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex);
|
||||
grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : txl->dummy_coba_tx);
|
||||
DRW_shgroup_uniform_vec3(
|
||||
grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1);
|
||||
}
|
||||
@@ -225,8 +162,22 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata,
|
||||
BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd));
|
||||
}
|
||||
|
||||
void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
|
||||
void workbench_volume_draw_pass(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PassList *psl = vedata->psl;
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (wpd->volumes_do) {
|
||||
GPU_framebuffer_bind(dfbl->color_only_fb);
|
||||
DRW_draw_pass(psl->volume_ps);
|
||||
}
|
||||
}
|
||||
|
||||
void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
|
||||
{
|
||||
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
|
||||
|
||||
/* Free Smoke Textures after rendering */
|
||||
/* XXX This is a waste of processing and GPU bandwidth if nothing
|
||||
* is updated. But the problem is since Textures are stored in the
|
||||
@@ -238,4 +189,4 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
|
||||
GPU_free_smoke(mmd);
|
||||
}
|
||||
BLI_freelistN(&wpd->smoke_domains);
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@ typedef struct DRWPass DRWPass;
|
||||
typedef struct DRWShadingGroup DRWShadingGroup;
|
||||
typedef struct DRWUniform DRWUniform;
|
||||
typedef struct DRWView DRWView;
|
||||
typedef struct DRWShaderLibrary DRWShaderLibrary;
|
||||
|
||||
/* TODO Put it somewhere else? */
|
||||
typedef struct BoundSphere {
|
||||
@@ -148,6 +149,8 @@ struct GPUTexture *DRW_texture_pool_query_2d(int w,
|
||||
int h,
|
||||
eGPUTextureFormat format,
|
||||
DrawEngineType *engine_type);
|
||||
struct GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
|
||||
DrawEngineType *engine_type);
|
||||
|
||||
struct GPUTexture *DRW_texture_create_1d(int w,
|
||||
eGPUTextureFormat format,
|
||||
@@ -246,6 +249,24 @@ void DRW_shader_free(struct GPUShader *shader);
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
DRWShaderLibrary *DRW_shader_library_create(void);
|
||||
|
||||
/* Warning: Each library must be added after all its dependencies. */
|
||||
void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name);
|
||||
#define DRW_SHADER_LIB_ADD(lib, lib_name) \
|
||||
DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl")
|
||||
|
||||
char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code);
|
||||
|
||||
void DRW_shader_library_free(DRWShaderLibrary *lib);
|
||||
#define DRW_SHADER_LIB_FREE_SAFE(lib) \
|
||||
do { \
|
||||
if (lib != NULL) { \
|
||||
DRW_shader_library_free(lib); \
|
||||
lib = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Batches */
|
||||
|
||||
typedef enum {
|
||||
@@ -403,6 +424,9 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint
|
||||
DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \
|
||||
} while (0)
|
||||
|
||||
/* Can only be called during iter phase. */
|
||||
uint32_t DRW_object_resource_id_get(Object *UNUSED(ob));
|
||||
|
||||
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
|
||||
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
|
||||
|
||||
@@ -414,7 +438,7 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
|
||||
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
|
||||
uint write_mask,
|
||||
uint reference,
|
||||
uint comp_mask);
|
||||
uint compare_mask);
|
||||
/* TODO remove this function. Obsolete version. mask is actually reference value. */
|
||||
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
|
||||
|
||||
|
||||
@@ -177,6 +177,11 @@ struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object,
|
||||
struct DRWPass *hair_pass,
|
||||
struct GPUShader *shader);
|
||||
|
||||
struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
|
||||
struct ParticleSystem *psys,
|
||||
struct ModifierData *md,
|
||||
struct DRWShadingGroup *shgrp);
|
||||
|
||||
struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object,
|
||||
struct ParticleSystem *psys,
|
||||
struct ModifierData *md,
|
||||
|
||||
@@ -108,6 +108,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
|
||||
ParticleSystem *psys,
|
||||
ModifierData *md,
|
||||
DRWPass *hair_pass,
|
||||
DRWShadingGroup *shgrp_parent,
|
||||
struct GPUMaterial *gpu_mat,
|
||||
GPUShader *gpu_shader)
|
||||
{
|
||||
@@ -127,7 +128,10 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
|
||||
object, psys, md, &hair_cache, subdiv, thickness_res);
|
||||
|
||||
DRWShadingGroup *shgrp;
|
||||
if (gpu_mat) {
|
||||
if (shgrp_parent) {
|
||||
shgrp = DRW_shgroup_create_sub(shgrp_parent);
|
||||
}
|
||||
else if (gpu_mat) {
|
||||
shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass);
|
||||
}
|
||||
else if (gpu_shader) {
|
||||
@@ -151,6 +155,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix issue with certain driver not drawing anything if there is no texture bound to
|
||||
* "ac", "au", "u" or "c". */
|
||||
if (hair_cache->num_uv_layers == 0) {
|
||||
DRW_shgroup_uniform_texture(shgrp, "u", hair_cache->final[subdiv].proc_tex);
|
||||
DRW_shgroup_uniform_texture(shgrp, "au", hair_cache->final[subdiv].proc_tex);
|
||||
}
|
||||
if (hair_cache->num_col_layers == 0) {
|
||||
DRW_shgroup_uniform_texture(shgrp, "c", hair_cache->final[subdiv].proc_tex);
|
||||
DRW_shgroup_uniform_texture(shgrp, "ac", hair_cache->final[subdiv].proc_tex);
|
||||
}
|
||||
|
||||
if ((dupli_parent != NULL) && (dupli_object != NULL)) {
|
||||
if (dupli_object->type & OB_DUPLICOLLECTION) {
|
||||
copy_m4_m4(dupli_mat, dupli_parent->obmat);
|
||||
@@ -220,7 +235,15 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
|
||||
DRWShadingGroup *DRW_shgroup_hair_create(
|
||||
Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader)
|
||||
{
|
||||
return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader);
|
||||
return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader);
|
||||
}
|
||||
|
||||
DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
|
||||
ParticleSystem *psys,
|
||||
ModifierData *md,
|
||||
DRWShadingGroup *shgrp)
|
||||
{
|
||||
return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL);
|
||||
}
|
||||
|
||||
DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
|
||||
@@ -229,7 +252,7 @@ DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
|
||||
DRWPass *hair_pass,
|
||||
struct GPUMaterial *material)
|
||||
{
|
||||
return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL);
|
||||
return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL);
|
||||
}
|
||||
|
||||
void DRW_hair_update(void)
|
||||
|
||||
@@ -1118,45 +1118,23 @@ static void use_drw_engine(DrawEngineType *engine)
|
||||
BLI_addtail(&DST.enabled_engines, ld);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use for external render engines.
|
||||
*/
|
||||
static void drw_engines_enable_external(void)
|
||||
{
|
||||
use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
|
||||
}
|
||||
|
||||
/* TODO revisit this when proper layering is implemented */
|
||||
/* Gather all draw engines needed and store them in DST.enabled_engines
|
||||
* That also define the rendering order of engines */
|
||||
static void drw_engines_enable_from_engine(RenderEngineType *engine_type,
|
||||
eDrawType drawtype,
|
||||
bool use_xray)
|
||||
static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype)
|
||||
{
|
||||
switch (drawtype) {
|
||||
case OB_WIRE:
|
||||
use_drw_engine(&draw_engine_workbench_transparent);
|
||||
break;
|
||||
|
||||
case OB_SOLID:
|
||||
if (use_xray) {
|
||||
use_drw_engine(&draw_engine_workbench_transparent);
|
||||
}
|
||||
else {
|
||||
use_drw_engine(&draw_engine_workbench_solid);
|
||||
}
|
||||
use_drw_engine(DRW_engine_viewport_workbench_type.draw_engine);
|
||||
break;
|
||||
|
||||
case OB_MATERIAL:
|
||||
case OB_RENDER:
|
||||
default:
|
||||
/* TODO layers */
|
||||
if (engine_type->draw_engine != NULL) {
|
||||
use_drw_engine(engine_type->draw_engine);
|
||||
}
|
||||
|
||||
if ((engine_type->flag & RE_INTERNAL) == 0) {
|
||||
drw_engines_enable_external();
|
||||
else if ((engine_type->flag & RE_INTERNAL) == 0) {
|
||||
use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1182,7 +1160,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
|
||||
const eDrawType drawtype = v3d->shading.type;
|
||||
const bool use_xray = XRAY_ENABLED(v3d);
|
||||
|
||||
drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
|
||||
drw_engines_enable_from_engine(engine_type, drawtype);
|
||||
if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
|
||||
use_drw_engine(&draw_engine_gpencil_type);
|
||||
}
|
||||
@@ -1608,6 +1586,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
|
||||
GPU_blend(true);
|
||||
}
|
||||
|
||||
GPU_matrix_identity_set();
|
||||
GPU_matrix_identity_projection_set();
|
||||
|
||||
GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management);
|
||||
|
||||
if (draw_background) {
|
||||
@@ -2646,9 +2627,6 @@ void DRW_engines_register(void)
|
||||
RE_engines_register(&DRW_engine_viewport_eevee_type);
|
||||
RE_engines_register(&DRW_engine_viewport_workbench_type);
|
||||
|
||||
DRW_engine_register(&draw_engine_workbench_solid);
|
||||
DRW_engine_register(&draw_engine_workbench_transparent);
|
||||
|
||||
DRW_engine_register(&draw_engine_gpencil_type);
|
||||
|
||||
DRW_engine_register(&draw_engine_overlay_type);
|
||||
|
||||
@@ -562,6 +562,16 @@ static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob)
|
||||
return handle;
|
||||
}
|
||||
|
||||
uint32_t DRW_object_resource_id_get(Object *UNUSED(ob))
|
||||
{
|
||||
DRWResourceHandle handle = DST.ob_handle;
|
||||
if (handle == 0) {
|
||||
/* Handle not yet allocated. Return next handle. */
|
||||
handle = DST.resource_handle;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup,
|
||||
float (*obmat)[4],
|
||||
Object *ob)
|
||||
@@ -693,14 +703,14 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf,
|
||||
static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup,
|
||||
uint write_mask,
|
||||
uint reference,
|
||||
uint comp_mask)
|
||||
uint compare_mask)
|
||||
{
|
||||
BLI_assert(write_mask <= 0xFF);
|
||||
BLI_assert(reference <= 0xFF);
|
||||
BLI_assert(comp_mask <= 0xFF);
|
||||
BLI_assert(compare_mask <= 0xFF);
|
||||
DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
|
||||
cmd->write_mask = write_mask;
|
||||
cmd->comp_mask = comp_mask;
|
||||
cmd->comp_mask = compare_mask;
|
||||
cmd->ref = reference;
|
||||
}
|
||||
|
||||
@@ -1341,9 +1351,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
|
||||
void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
|
||||
uint write_mask,
|
||||
uint reference,
|
||||
uint comp_mask)
|
||||
uint compare_mask)
|
||||
{
|
||||
drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask);
|
||||
drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask);
|
||||
}
|
||||
|
||||
/* TODO remove this function. */
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "DNA_world_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string_utils.h"
|
||||
#include "BLI_threads.h"
|
||||
@@ -282,6 +283,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \{ */
|
||||
|
||||
GPUShader *DRW_shader_create(const char *vert,
|
||||
const char *geom,
|
||||
const char *frag,
|
||||
@@ -468,3 +471,129 @@ void DRW_shader_free(GPUShader *shader)
|
||||
{
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Shader Library
|
||||
*
|
||||
* Simple include system for glsl files.
|
||||
*
|
||||
* Usage: Create a DRWShaderLibrary and add the library in the right order.
|
||||
* You can have nested dependencies but each new library needs to have all its dependencies already
|
||||
* added to the DRWShaderLibrary.
|
||||
* Finally you can use DRW_shader_library_create_shader_string to get a shader string that also
|
||||
* contains the needed libraries for this shader.
|
||||
* \{ */
|
||||
|
||||
/* 32 because we use a 32bit bitmap. */
|
||||
#define MAX_LIB 32
|
||||
#define MAX_LIB_NAME 64
|
||||
#define MAX_LIB_DEPS 8
|
||||
|
||||
struct DRWShaderLibrary {
|
||||
char *libs[MAX_LIB];
|
||||
char libs_name[MAX_LIB][MAX_LIB_NAME];
|
||||
uint32_t libs_deps[MAX_LIB];
|
||||
};
|
||||
|
||||
DRWShaderLibrary *DRW_shader_library_create(void)
|
||||
{
|
||||
return MEM_callocN(sizeof(DRWShaderLibrary), "DRWShaderLibrary");
|
||||
}
|
||||
|
||||
void DRW_shader_library_free(DRWShaderLibrary *lib)
|
||||
{
|
||||
MEM_SAFE_FREE(lib);
|
||||
}
|
||||
|
||||
static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name)
|
||||
{
|
||||
for (int i = 0; i < MAX_LIB; i++) {
|
||||
if (lib->libs[i]) {
|
||||
if (!strncmp(lib->libs_name[i], name, strlen(lib->libs_name[i]))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return bitmap of dependencies. */
|
||||
static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code)
|
||||
{
|
||||
/* Search dependencies. */
|
||||
uint32_t deps = 0;
|
||||
char *haystack = lib_code;
|
||||
while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) {
|
||||
haystack += 16;
|
||||
int dep = drw_shader_library_search(lib, haystack);
|
||||
if (dep == -1) {
|
||||
printf(
|
||||
"Error: Dependency not found.\n"
|
||||
"This might be due to bad lib ordering.\n");
|
||||
BLI_assert(0);
|
||||
}
|
||||
else {
|
||||
deps |= 1u << (uint32_t)dep;
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name)
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < MAX_LIB; i++) {
|
||||
if (lib->libs[i] == NULL) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > -1) {
|
||||
lib->libs[index] = lib_code;
|
||||
BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME);
|
||||
}
|
||||
else {
|
||||
printf("Error: Too many libraries. Cannot add %s.\n", lib_name);
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code);
|
||||
}
|
||||
|
||||
/* Return an allocN'ed string containing the shader code with its dependencies prepended.
|
||||
* Caller must free the string with MEM_freeN after use. */
|
||||
char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code)
|
||||
{
|
||||
uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
|
||||
|
||||
DynStr *ds = BLI_dynstr_new();
|
||||
/* Add all dependencies recursively. */
|
||||
for (int i = MAX_LIB - 1; i > -1; i--) {
|
||||
if (lib->libs[i] && (deps & (1u << (uint32_t)i))) {
|
||||
deps |= lib->libs_deps[i];
|
||||
}
|
||||
}
|
||||
/* Concatenate all needed libs into one string. */
|
||||
for (int i = 0; i < MAX_LIB; i++) {
|
||||
if (deps & 1u) {
|
||||
BLI_dynstr_append(ds, lib->libs[i]);
|
||||
}
|
||||
deps = deps >> 1;
|
||||
}
|
||||
|
||||
BLI_dynstr_append(ds, shader_code);
|
||||
|
||||
char *str = BLI_dynstr_get_cstring(ds);
|
||||
BLI_dynstr_free(ds);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -134,6 +134,13 @@ GPUTexture *DRW_texture_pool_query_2d(int w,
|
||||
return tex;
|
||||
}
|
||||
|
||||
GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format,
|
||||
DrawEngineType *engine_type)
|
||||
{
|
||||
const float *size = DRW_viewport_size_get();
|
||||
return DRW_texture_pool_query_2d((int)size[0], (int)size[1], format, engine_type);
|
||||
}
|
||||
|
||||
void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex,
|
||||
eGPUTextureFormat format,
|
||||
DRWTextureFlag flags)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
/* Need to be included after common_view_lib.glsl for resource_id. */
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
#ifndef GPU_OBINFOS_UBO
|
||||
#define GPU_OBINFOS_UBO
|
||||
# define GPU_OBINFOS_UBO
|
||||
struct ObjectInfos {
|
||||
vec4 drw_OrcoTexCoFactors[2];
|
||||
vec4 drw_ObjectColor;
|
||||
@@ -13,7 +14,7 @@ layout(std140) uniform infoBlock
|
||||
/* DRW_RESOURCE_CHUNK_LEN = 512 */
|
||||
ObjectInfos drw_infos[512];
|
||||
};
|
||||
#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
|
||||
#define ObjectInfo (drw_infos[resource_id].drw_Infos)
|
||||
#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
|
||||
# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
|
||||
# define ObjectInfo (drw_infos[resource_id].drw_Infos)
|
||||
# define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
|
||||
#endif
|
||||
|
||||
@@ -43,10 +43,6 @@ typedef enum eV3DShadingColorType {
|
||||
V3D_SHADING_TEXTURE_COLOR = 3,
|
||||
V3D_SHADING_OBJECT_COLOR = 4,
|
||||
V3D_SHADING_VERTEX_COLOR = 5,
|
||||
|
||||
/* Is used to display the object using the error color. For example when in
|
||||
* solid texture paint mode without any textures configured */
|
||||
V3D_SHADING_ERROR_COLOR = 999,
|
||||
} eV3DShadingColorType;
|
||||
|
||||
/** #View3DShading.background_type */
|
||||
|
||||
Reference in New Issue
Block a user