1
1

Compare commits

...

19 Commits

Author SHA1 Message Date
bd6567b262 Workbench: Refactor: Antialiasing 2020-03-03 17:35:30 +01:00
91dfe40ef0 Workbench: Refactor: Add Dof Support 2020-03-03 16:45:13 +01:00
c8407006aa Overlay: Fix wireframe after shadow refactor 2020-03-03 02:37:22 +01:00
a102b7ebe5 Workbench: Refactor: Add outline support 2020-03-03 02:29:05 +01:00
aae2e1326f Workbench: Refactor: Add cavity support 2020-03-03 01:42:31 +01:00
606f1d80b3 Workbench: Refactor: Add Shadow support 2020-03-02 15:16:18 +01:00
f426e71e09 Workbench: Refactor: Add hair support + tweak the randomness of hairs color 2020-03-01 22:03:24 +01:00
62a7ac8f17 Workbench: Refactor: Add Infront support 2020-03-01 14:26:56 +01:00
73de98e6e0 Workbench: Refactor: Add transparent (xray) support 2020-03-01 13:41:39 +01:00
d36e63f8db Workbench: Refactor: Only allocate id buffer if needed 2020-02-29 23:53:29 +01:00
e34ce36ea4 Workbench: Refactor: Add specular toggle support 2020-02-29 18:29:13 +01:00
76a7ea0b71 Workbench: Refactor: Add matcap support 2020-02-29 18:28:58 +01:00
46f8367eac Workbench: Refactor: Add support for Flat shading 2020-02-29 17:22:04 +01:00
5759e2d6c4 Workbench: Refactor: Add support for texpaint & vertpaint 2020-02-29 16:42:47 +01:00
e6e740f317 Workbench: Refactor: Support Material data 2020-02-28 20:40:49 +01:00
b6e083358e BLI_memblock: Allow to use BLI_memblock_elem_get using only elem index 2020-02-28 17:29:48 +01:00
1e58e68c1a DRW: Manager: Expose resource handle getter 2020-02-28 17:28:58 +01:00
1545c37cdb Workbench: Refactor: Code reorganization 2020-02-28 02:38:47 +01:00
616545b5cf DRW: Shader: Add shader library manager
This new object makes it easier to resolve shader code dependency.
2020-02-27 15:06:27 +01:00
54 changed files with 3610 additions and 855 deletions

View File

@@ -182,10 +182,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;
}

View File

@@ -101,14 +101,20 @@ set(SRC
engines/workbench/workbench_data.c
engines/workbench/workbench_deferred.c
engines/workbench/workbench_effect_aa.c
engines/workbench/workbench_effect_cavity.c
engines/workbench/workbench_effect_dof.c
engines/workbench/workbench_effect_fxaa.c
engines/workbench/workbench_effect_outline.c
engines/workbench/workbench_effect_taa.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_shader.c
engines/workbench/workbench_shadow.c
engines/workbench/workbench_studiolight.c
engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
engines/external/external_engine.c
engines/gpencil/gpencil_cache_utils.c
@@ -246,24 +252,37 @@ 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_composite_frag.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_outline_frag.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_fxaa_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_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_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_object_outline_lib.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_prepass_hair_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.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_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_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_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)

View File

@@ -373,9 +373,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)});

View File

@@ -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) {

View File

@@ -28,7 +28,7 @@ layout(std140) uniform samples_block
#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)
vec3 view_space_from_depth(in vec2 uvcoords, in float depth)
{
if (WinMatrix[3][3] == 0.0) {
/* Perspective */
@@ -63,7 +63,7 @@ void main()
#ifdef USE_CAVITY
float depth = texelFetch(depthBuffer, texel, 0).x;
vec3 position = get_view_space_from_depth(screenco, depth);
vec3 position = 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);

View File

@@ -1,77 +1,86 @@
#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 */
if (depth == 1.0) {
return;
}
/* take the normalized ray direction here */
vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
vec3 position = view_space_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_space_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 +91,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;
}

View File

@@ -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_space_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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -5,12 +5,37 @@ 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;
int matcap_orientation;
};
#define viewport_size_inv viewport_size.zw
layout(std140) uniform world_block
{
WorldData world_data;
};

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,14 @@
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);
}

View File

@@ -0,0 +1,14 @@
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);
}

View File

@@ -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);
}

View File

@@ -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
}

View File

@@ -0,0 +1,32 @@
#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;
uniform bool useSpecularMatcap = false;
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(useSpecularMatcap);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -0,0 +1,90 @@
#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));
float metallic, roughness;
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);
packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
object_id = int((uint(resource_id) + 1u) & 0xFFu);
}

View File

@@ -1,110 +1,36 @@
#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));
float metallic, roughness;
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = ac.rgb;
}
packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
object_id = int((uint(resource_id) + 1u) & 0xFFu);
}

View File

@@ -0,0 +1,16 @@
#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;
flat float packed_rough_metal;
flat int object_id;
};

View File

@@ -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;
}

View File

@@ -0,0 +1,88 @@
#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;
/* 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, 122141, 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()
{
/* TODO Remove this. */
float roughness, metallic;
workbench_float_pair_decode(packed_rough_metal, roughness, metallic);
/* 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);
}

View File

@@ -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, 122141, 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;
}

View File

@@ -41,7 +41,7 @@ float get_view_z_from_depth(float depth)
}
}
vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
vec3 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);
@@ -208,8 +208,8 @@ 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_space_from_depth(screen_uv, depth_end);
vec3 vs_ray_ori = view_space_from_depth(screen_uv, 0.0);
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);

View File

@@ -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,21 @@ 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)
uniform bool useSpecularLighting = false;
vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
{
vec3 specular_color, diffuse_color;
if (useSpecularLighting) {
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 +65,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 (useSpecularLighting) {
/* 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 +121,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;
}

View File

@@ -31,13 +31,13 @@
/* Functions */
static void workbench_transparent_engine_init(void *vedata)
static void workbench_transparent_engine_init_old(void *vedata)
{
WORKBENCH_Data *data = vedata;
workbench_forward_engine_init(data);
}
static void workbench_transparent_cache_init(void *vedata)
static void workbench_transparent_cache_init_old(void *vedata)
{
WORKBENCH_Data *data = vedata;
@@ -85,9 +85,9 @@ DrawEngineType draw_engine_workbench_transparent = {
NULL,
N_("Workbench"),
&workbench_data_size,
&workbench_transparent_engine_init,
&workbench_transparent_engine_init_old,
&workbench_transparent_engine_free,
&workbench_transparent_cache_init,
&workbench_transparent_cache_init_old,
&workbench_transparent_cache_populate,
&workbench_transparent_cache_finish,
&workbench_transparent_draw_scene,

View File

@@ -22,86 +22,146 @@
#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_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage;
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);
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_private_data_get_light_direction(float r_light_direction[3])
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
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];
}
static void workbench_shadow_world_data_update(WORKBENCH_PrivateData *wpd)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene = draw_ctx->scene;
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_private_data_get_light_direction(light_direction);
workbench_private_data_get_light_direction(wpd->light_direction_ws);
/* Shadow direction. */
mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction);
mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->light_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;
}
}
/* \} */
static void workbench_viewvecs_update(float r_viewvecs[3][4])
{
float invproj[4][4];
const bool is_persp = DRW_view_is_persp_get(NULL);
DRW_view_winmat_get(NULL, invproj, true);
/* 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;
}
/* 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_clear_color_get(float color[4])
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -130,26 +190,51 @@ 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;
WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
View3D *v3d = draw_ctx->v3d;
RegionView3D *rv3d = draw_ctx->rv3d;
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;
}
wpd->ctx_mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
wpd->preferences = &U;
wpd->sh_cfg = draw_ctx->sh_cfg;
wpd->vldata = vldata;
wpd->taa_sample_len = workbench_aa_sample_count_get(wpd);
wpd->world_ubo = vldata->world_ubo;
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);
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
wpd->shading = scene->display.shading;
wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
wpd->use_color_render_settings = true;
}
else {
wpd->shading = v3d->shading;
wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
wpd->use_color_render_settings = false;
if (XRAY_ENABLED(v3d)) {
wpd->shading.xray_alpha = XRAY_ALPHA(v3d);
}
else {
wpd->shading.xray_alpha = 1.0f;
}
}
wpd->use_color_management = BKE_scene_check_color_management_enabled(scene);
if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
}
@@ -162,34 +247,26 @@ 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);
/* 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);
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;
wd->curvature_ridge = 0.5f / max_ff(SQUARE(wpd->shading.curvature_ridge_factor), 1e-4f);
wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f);
workbench_shadow_world_data_update(wpd);
workbench_cavity_data_update(wpd);
workbench_viewvecs_update(wpd->world_data.viewvecs);
/* 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);
DRW_uniformbuffer_update(wpd->world_ubo, &wpd->world_data);
/* Cavity settings */
{
@@ -253,22 +330,27 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
BLI_listbase_clear(&wpd->smoke_domains);
}
void workbench_private_data_get_light_direction(float r_light_direction[3])
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];
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);
}
BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free);
BLI_memblock_clear(vldata->material_ubo_data, NULL);
}
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);
}

View File

@@ -192,7 +192,7 @@ static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_
return str;
}
static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
static GPUShader *workbench__cavity_shader_get(bool cavity, bool curvature)
{
const bool high_dpi = (U.pixelsize > 1.5f);
int index = 0;
@@ -334,12 +334,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
}
/* Functions */
static void workbench_init_object_data(DrawData *dd)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
data->shadow_bbox_dirty = true;
}
static void workbench_init_oit_framebuffer(WORKBENCH_FramebufferList *fbl,
DefaultTextureList *dtxl)
{
@@ -364,17 +358,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
WORKBENCH_PassList *psl = vedata->psl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
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;
}
if (!stl->g_data) {
/* Alloc transient pointers */
@@ -462,7 +446,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
wpd->shading.xray_alpha = 1.0f;
workbench_dof_engine_init(vedata, camera);
workbench_dof_engine_init(vedata);
if (OIT_ENABLED(wpd)) {
if (e_data.oit_resolve_sh == NULL) {
@@ -508,7 +492,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
size[0], size[1], GPU_R16, &draw_engine_workbench_solid);
}
GPU_framebuffer_ensure_config(&fbl->prepass_fb,
GPU_framebuffer_ensure_config(&fbl->opaque_fb,
{
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
@@ -553,7 +537,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
{
/* AO Samples Tex */
int num_iterations = workbench_taa_calculate_num_iterations(vedata);
int num_iterations = workbench_taa_calculate_num_iterations(vedata->stl->wpd);
const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples;
const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500);
@@ -593,16 +577,16 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
}
{
workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
workbench_aa_cache_init(vedata);
}
{
workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx);
workbench_dof_cache_init(vedata);
}
if (CAVITY_ENABLED(wpd)) {
int state = DRW_STATE_WRITE_COLOR;
GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
GPUShader *shader = workbench__cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
psl->cavity_pass = DRW_pass_create("Cavity", state);
DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass);
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
@@ -659,7 +643,6 @@ void workbench_deferred_engine_free(void)
workbench_volume_engine_free();
workbench_fxaa_engine_free();
workbench_taa_engine_free();
workbench_dof_engine_free();
}
static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
@@ -732,7 +715,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
/* Deferred Mix Pass */
{
workbench_private_data_get_light_direction(e_data.display.light_direction);
studiolight_update_light(wpd, e_data.display.light_direction);
studiolight_update_light(wpd);
if (SHADOW_ENABLED(wpd)) {
psl->composite_pass = DRW_pass_create(
@@ -1161,11 +1144,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
else {
WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
&ob->id,
&draw_engine_workbench_solid,
sizeof(WORKBENCH_ObjectData),
&workbench_init_object_data,
NULL);
&ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), NULL, NULL);
if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
@@ -1286,8 +1265,8 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
}
GPU_framebuffer_bind(fbl->prepass_fb);
GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_col, clear_depth, clear_stencil);
GPU_framebuffer_bind(fbl->opaque_fb);
GPU_framebuffer_clear(fbl->opaque_fb, clear_bits, clear_col, clear_depth, clear_stencil);
DRW_draw_pass(psl->prepass_pass);
DRW_draw_pass(psl->prepass_hair_pass);
@@ -1396,7 +1375,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
}
workbench_dof_draw_pass(vedata);
workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
workbench_aa_draw_pass(vedata);
}
void workbench_deferred_draw_finish(WORKBENCH_Data *vedata)

View File

@@ -13,7 +13,7 @@
* 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.
* Copyright 2020, Blender Foundation.
*/
/** \file
@@ -22,80 +22,318 @@
#include "ED_screen.h"
#include "draw_color_management.h"
#include "BLI_jitter_2d.h"
#include "smaa_textures.h"
#include "workbench_private.h"
void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
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)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PrivateData *wpd = stl->g_data;
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(table[index][0]) + SQUARE(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(table[i][0] - table[j][0]) +
SQUARE(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) {
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);
}
}
BLI_INLINE bool workbench_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;
}
}
int workbench_aa_sample_count_get(WORKBENCH_PrivateData *wpd)
{
const Scene *scene = DRW_context_state_get()->scene;
if (workbench_taa_enabled(wpd)) {
if (DRW_state_is_image_render()) {
const DRWContextState *draw_ctx = DRW_context_state_get();
if (draw_ctx->v3d) {
return scene->display.viewport_aa;
}
else {
return scene->display.render_aa;
}
}
else {
return wpd->preferences->viewport_aa;
}
}
else {
/* when no TAA is disabled return 0 to render a single sample
* see `workbench_render.c` */
return 0;
}
}
void workbench_aa_engine_init(WORKBENCH_Data *vedata)
{
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
DrawEngineType *owner = (DrawEngineType *)&workbench_aa_engine_init;
if (wpd->taa_sample_len > 0) {
workbench_taa_jitter_init();
DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, 0);
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_aa_cache_init(WORKBENCH_Data *vedata)
{
WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_EffectInfo *effect_info = stl->effects;
const DRWContextState *draw_ctx = DRW_context_state_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
DRWShadingGroup *grp = NULL;
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 (wpd->taa_sample_len > 0) {
return;
}
if (workbench_is_taa_enabled(wpd)) {
psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
{
DRW_PASS_CREATE(psl->aa_accum_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
GPUShader *shader = workbench_shader_antialiasing_accumulation_get();
grp = DRW_shgroup_create(shader, psl->aa_accum_pass);
DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
else if (workbench_is_fxaa_enabled(wpd)) {
psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
effect_info->jitter_index = 0;
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_pass, DRW_STATE_WRITE_COLOR);
GPUShader *sh = workbench_shader_antialiasing_get(0);
grp = DRW_shgroup_create(sh, psl->aa_edge_pass);
DRW_shgroup_uniform_texture(grp, "colorTex", dtxl->color);
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);
}
else {
psl->effect_aa_pass = NULL;
effect_info->jitter_index = 0;
{
/* Stage 2: Blend Weight/Coord. */
DRW_PASS_CREATE(psl->aa_weight_pass, DRW_STATE_WRITE_COLOR);
GPUShader *sh = workbench_shader_antialiasing_get(1);
grp = DRW_shgroup_create(sh, psl->aa_weight_pass);
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_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
GPUShader *sh = workbench_shader_antialiasing_get(2);
grp = DRW_shgroup_create(sh, psl->aa_resolve_pass);
DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx);
DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx);
DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1);
DRW_shgroup_uniform_float_copy(grp, "invTaaSampleCount", wpd->taa_sample_inv);
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
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)
void workbench_aa_draw_pass(WORKBENCH_Data *vedata)
{
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);
if (wpd->taa_sample_len == 0) {
/* AA disabled. */
return;
}
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);
/* 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;
/**
* 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 == 1) {
/* 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 {
GPU_framebuffer_bind(dfbl->color_only_fb);
workspace_aa_draw_transform(tx, wpd);
else if (wpd->taa_sample < wpd->taa_sample_len) {
/* Accumulate result to the TAA buffer. */
GPU_framebuffer_bind(fbl->antialiasing_fb);
DRW_draw_pass(psl->aa_accum_pass);
}
if (wpd->taa_sample == wpd->taa_sample_len) {
/* TAA accumulation has finish. Just copy the result back */
eGPUFrameBufferBits bits = GPU_COLOR_BIT | GPU_DEPTH_BIT;
GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, bits);
return;
}
else if (wpd->taa_sample > 1) {
/* Copy back the saved depth buffer for correct overlays. */
GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
}
if (wpd->smaa_mix_factor > 0.0f) {
GPU_framebuffer_bind(fbl->smaa_edge_fb);
DRW_draw_pass(psl->aa_edge_pass);
GPU_framebuffer_bind(fbl->smaa_weight_fb);
DRW_draw_pass(psl->aa_weight_pass);
}
GPU_framebuffer_bind(dfbl->default_fb);
DRW_draw_pass(psl->aa_resolve_pass);
if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) {
DRW_viewport_request_redraw();
}
}

View File

@@ -0,0 +1,162 @@
/*
* 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_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
/* 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_mallocN(sizeof(float[4]) * total_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]);
}
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 = MIN2(wpd->taa_sample_len * cavity_sample_count_single_iteration, 512);
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,
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]) * 512, samples);
wpd->vldata->cavity_sample_count = cavity_sample_count;
MEM_freeN(samples);
}
}
void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd)
{
WORKBENCH_UBO_World *wd = &wpd->world_data;
View3DShading *shading = &wpd->shading;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
wd->cavity_sample_start = cavity_sample_count_single_iteration * wpd->taa_sample;
wd->cavity_sample_end = min_ff(wd->cavity_sample_start + cavity_sample_count_single_iteration,
wpd->vldata->cavity_sample_count);
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(shading->curvature_ridge_factor), 1e-4f);
wd->curvature_valley = 0.7f / max_ff(SQUARE(shading->curvature_valley_factor), 1e-4f);
}
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_pass, state);
sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
grp = DRW_shgroup_create(sh, psl->cavity_pass);
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_pass = NULL;
}
}

View File

@@ -27,24 +27,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.
*/
@@ -129,52 +111,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,7 +156,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
&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
#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);
wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d(
@@ -201,7 +171,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,
@@ -230,11 +200,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);
@@ -262,128 +228,126 @@ 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;
WORKBENCH_PrivateData *wpd = stl->wpd;
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
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;
@@ -395,7 +359,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;
@@ -409,7 +374,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);
@@ -429,7 +394,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();

View File

@@ -0,0 +1,51 @@
/*
* 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 "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_pass, state);
sh = workbench_shader_outline_get();
grp = DRW_shgroup_create(sh, psl->outline_pass);
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_pass = NULL;
}
}

View File

@@ -21,6 +21,7 @@
*/
#include "workbench_private.h"
#include "BLI_jitter_2d.h"
static struct {
@@ -86,10 +87,8 @@ static void workbench_taa_jitter_init(void)
workbench_taa_jitter_init_order(e_data.jitter_32, 32);
}
int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
int workbench_taa_calculate_num_iterations(WORKBENCH_PrivateData *wpd)
{
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)) {
@@ -211,7 +210,7 @@ void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
int num_samples = 8;
float(*samples)[2];
num_samples = workbench_taa_calculate_num_iterations(vedata);
num_samples = workbench_taa_calculate_num_iterations(vedata->stl->wpd);
switch (num_samples) {
default:
case 5:

View File

@@ -19,18 +19,503 @@
/** \file
* \ingroup draw_engine
*
* Simple engine for drawing color and/or depth.
* When we only need simple flat shaders.
* 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. */
static 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__);
}
if (!stl->effects) {
stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
workbench_effect_info_init(stl->effects);
}
WORKBENCH_PrivateData *wpd = stl->wpd;
workbench_private_data_init(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 {
DRW_TEXTURE_FREE_SAFE(wpd->object_id_tx);
}
workbench_opaque_engine_init(vedata);
workbench_transparent_engine_init(vedata);
workbench_dof_engine_init(vedata);
workbench_aa_engine_init(vedata);
// workbench_volume_engine_init();
// workbench_fxaa_engine_init();
// workbench_taa_engine_init(vedata);
}
static 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_aa_cache_init(vedata);
// workbench_aa_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, int 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,
int 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,
int 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 int workbench_color_type_get(WORKBENCH_PrivateData *wpd,
Object *ob,
bool *r_sculpt_pbvh,
bool *r_texpaint_mode,
bool *r_draw_shadow)
{
int 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;
}
static 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);
}
}
}
/* TODO volume */
// 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;
int 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);
}
}
}
static 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;
}
}
}
}
}
static void workbench_draw_scene(void *ved)
{
WORKBENCH_Data *vedata = ved;
WORKBENCH_FramebufferList *fbl = vedata->fbl;
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};
if (fbl->id_clear_fb) {
GPU_framebuffer_bind(fbl->id_clear_fb);
GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col);
}
{
GPU_framebuffer_bind(dfbl->in_front_fb);
GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
}
GPU_framebuffer_bind(dfbl->color_only_fb);
GPU_framebuffer_clear_color(dfbl->color_only_fb, clear_col);
{
GPU_framebuffer_bind(fbl->opaque_fb);
GPU_framebuffer_clear_stencil(fbl->opaque_fb, 0x00);
DRW_draw_pass(psl->opaque_pass);
if (psl->shadow_pass[0]) {
DRW_draw_pass(psl->shadow_pass[0]);
DRW_draw_pass(psl->shadow_pass[1]);
}
{
GPU_framebuffer_bind(fbl->opaque_infront_fb);
DRW_draw_pass(psl->opaque_infront_pass);
GPU_framebuffer_bind(fbl->opaque_fb);
DRW_draw_pass(psl->merge_infront_pass);
}
GPU_framebuffer_bind(dfbl->default_fb);
DRW_draw_pass(psl->composite_pass);
if (psl->cavity_pass) {
GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(psl->cavity_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_pass);
GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(psl->transp_resolve_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_pass);
GPU_framebuffer_bind(dfbl->color_only_fb);
DRW_draw_pass(psl->transp_resolve_pass);
}
}
if (psl->outline_pass) {
DRW_draw_pass(psl->outline_pass);
}
workbench_dof_draw_pass(vedata);
workbench_aa_draw_pass(vedata);
}
static void workbench_engine_free(void)
{
workbench_shader_free();
}
static void workbench_view_update(void *UNUSED(ved))
{
}
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_solid);
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,
NULL,
};
RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
@@ -44,7 +529,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
NULL,
NULL,
&workbench_render_update_passes,
&draw_engine_workbench_solid,
&draw_engine_workbench,
{NULL, NULL, NULL},
};

View File

@@ -428,7 +428,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata)
}
{
workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx);
workbench_aa_cache_init(vedata);
}
if (wpd->shading.type == OB_WIRE) {
@@ -456,7 +456,6 @@ void workbench_forward_engine_free()
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))
@@ -797,7 +796,7 @@ void workbench_forward_draw_scene(WORKBENCH_Data *vedata)
}
/* Color correct and Anti aliasing */
workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
workbench_aa_draw_pass(vedata);
}
void workbench_forward_draw_finish(WORKBENCH_Data *vedata)

View File

@@ -22,6 +22,8 @@
#include "workbench_private.h"
#include "BLI_memblock.h"
#include "BKE_image.h"
#include "BKE_node.h"
@@ -31,6 +33,8 @@
#include "DNA_node_types.h"
#include "DNA_mesh_types.h"
#include "GPU_uniformbuffer.h"
#include "ED_uvedit.h"
#define HSV_SATURATION 0.5
@@ -49,9 +53,6 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
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) {
@@ -82,6 +83,56 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd,
}
}
void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd,
Object *ob,
Material *mat,
WORKBENCH_UBO_Material *data,
int color_type)
{
float metallic = 0.0f;
float roughness = 0.632455532f; /* sqrtf(0.4f); */
float alpha = wpd->shading.xray_alpha;
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;
}
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,
@@ -209,7 +260,7 @@ int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd)
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);
// BLI_assert(index < MAX_COMPOSITE_SHADERS);
return index;
}
@@ -292,49 +343,21 @@ int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd,
return index;
}
int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd,
Image *ima,
Object *ob,
bool use_sculpt_pbvh)
/* Return correct material or empty default material if slot is empty. */
BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
{
int 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;
Material *ma = BKE_object_material_get(ob, mat_nr);
if (ma == NULL) {
ma = BKE_material_default_empty();
}
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;
return ma;
}
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,6 +381,17 @@ void workbench_material_get_image_and_mat(
}
}
/* TODO remove */
void workbench_material_get_image_and_mat(
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat)
{
*r_mat = workbench_object_material_get(ob, mat_nr);
if (r_image) {
workbench_material_get_image(ob, mat_nr, r_image, r_iuser, r_interp);
}
}
void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp,
WORKBENCH_MaterialData *material,
@@ -399,6 +433,176 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
}
}
/* TODO remove */
int workbench_material_determine_color_type(WORKBENCH_PrivateData *UNUSED(wpd),
Image *UNUSED(ima),
Object *UNUSED(ob),
bool UNUSED(use_sculpt_pbvh))
{
return 0;
}
/* Return true if the current material ubo has changed and needs to be rebind. */
static bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd, uint32_t id)
{
bool resource_changed = false;
/* Divide in chunks of MAX_MATERIAL. */
uint32_t chunk = id >> 12u;
/* 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, int 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;
}
}
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 id = wpd->material_index++;
workbench_material_chunk_select(wpd, id);
workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[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", id & 0xFFFu);
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 id = DRW_object_resource_id_get(ob);
bool resource_changed = workbench_material_chunk_select(wpd, id);
workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[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 {
tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D);
}
}
if (tex == NULL) {
printf("Image not foudn\n");
tex = wpd->dummy_image_tx;
}
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;
}
void workbench_material_copy(WORKBENCH_MaterialData *dest_material,
const WORKBENCH_MaterialData *source_material)
{

View File

@@ -0,0 +1,166 @@
/*
* 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 "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;
const DRWContextState *draw_ctx = DRW_context_state_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
RegionView3D *rv3d = draw_ctx->rv3d;
View3D *v3d = draw_ctx->v3d;
struct GPUShader *sh;
DRWShadingGroup *grp;
const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP);
{
DRWState clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
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_pass, state | cull_state | clip_state);
pass = psl->opaque_infront_pass;
}
else {
DRW_PASS_CREATE(psl->opaque_pass, state | cull_state | clip_state);
pass = psl->opaque_pass;
}
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_pass, state);
sh = workbench_shader_composite_get(wpd);
grp = DRW_shgroup_create(sh, psl->composite_pass);
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);
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
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;
spec_tx = use_spec ? spec_tx : diff_tx;
DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
DRW_shgroup_uniform_bool_copy(grp, "useSpecularMatcap", use_spec);
}
else if (STUDIOLIGHT_TYPE_STUDIO_ENABLED(wpd)) {
DRW_shgroup_uniform_bool_copy(grp, "useSpecularLighting", use_spec);
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
if (true) {
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_pass, state);
sh = workbench_shader_merge_infront_get(wpd);
grp = DRW_shgroup_create(sh, psl->merge_infront_pass);
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);
}
}

View File

@@ -34,11 +34,17 @@
#include "workbench_engine.h"
extern struct DrawEngineType draw_engine_workbench;
#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
#define MAX_COMPOSITE_SHADERS (1 << 7)
/* TODO put them in workbench_shader.c */
#define MAX_COMPOSITE_SHADERS 3
#define MAX_PREPASS_SHADERS (1 << 8)
#define MAX_ACCUM_SHADERS (1 << 8)
#define MAX_CAVITY_SHADERS (1 << 3)
#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)
@@ -84,7 +90,8 @@
#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)
/* TODO remove */
#define WORLD_CLIPPING_ENABLED(wpd) (false)
struct RenderEngine;
struct RenderLayer;
@@ -92,7 +99,8 @@ struct rcti;
typedef struct WORKBENCH_FramebufferList {
/* Deferred render buffers */
struct GPUFrameBuffer *prepass_fb;
struct GPUFrameBuffer *opaque_fb;
struct GPUFrameBuffer *opaque_infront_fb;
struct GPUFrameBuffer *ghost_prepass_fb;
struct GPUFrameBuffer *cavity_fb;
struct GPUFrameBuffer *composite_fb;
@@ -110,10 +118,18 @@ typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *dof_blur1_fb;
struct GPUFrameBuffer *dof_blur2_fb;
struct GPUFrameBuffer *antialiasing_fb;
struct GPUFrameBuffer *smaa_edge_fb;
struct GPUFrameBuffer *smaa_weight_fb;
/* Forward render buffers */
struct GPUFrameBuffer *object_outline_fb;
struct GPUFrameBuffer *transparent_accum_fb;
struct GPUFrameBuffer *transparent_revealage_fb;
struct GPUFrameBuffer *transp_accum_fb;
struct GPUFrameBuffer *transp_accum_infront_fb;
struct GPUFrameBuffer *transp_reveal_fb;
} WORKBENCH_FramebufferList;
typedef struct WORKBENCH_TextureList {
@@ -121,21 +137,30 @@ typedef struct WORKBENCH_TextureList {
struct GPUTexture *coc_halfres_tx;
struct GPUTexture *history_buffer_tx;
struct GPUTexture *depth_buffer_tx;
struct GPUTexture *dummy_image_tx;
struct GPUTexture *smaa_search_tx;
struct GPUTexture *smaa_area_tx;
} WORKBENCH_TextureList;
typedef struct WORKBENCH_StorageList {
struct WORKBENCH_PrivateData *g_data;
struct WORKBENCH_PrivateData *wpd;
struct WORKBENCH_EffectInfo *effects;
float *dof_ubo_data;
} WORKBENCH_StorageList;
typedef struct WORKBENCH_PassList {
/* deferred rendering */
struct DRWPass *opaque_pass;
struct DRWPass *opaque_infront_pass;
struct DRWPass *shadow_pass[2];
struct DRWPass *merge_infront_pass;
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 *outline_pass;
struct DRWPass *shadow_depth_pass_pass;
struct DRWPass *shadow_depth_pass_mani_pass;
struct DRWPass *shadow_depth_fail_pass;
@@ -160,7 +185,15 @@ typedef struct WORKBENCH_PassList {
struct DRWPass *dof_resolve_ps;
struct DRWPass *volume_pass;
struct DRWPass *aa_accum_pass;
struct DRWPass *aa_edge_pass;
struct DRWPass *aa_weight_pass;
struct DRWPass *aa_resolve_pass;
/* forward rendering */
struct DRWPass *transp_resolve_pass;
struct DRWPass *transp_accum_pass;
struct DRWPass *transp_accum_infront_pass;
struct DRWPass *transparent_accum_pass;
struct DRWPass *object_outline_pass;
struct DRWPass *depth_pass;
@@ -180,17 +213,48 @@ 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;
int matcap_orientation;
} 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 {
struct GHash *material_hash;
struct DRWShadingGroup *common_shgrp;
struct DRWShadingGroup *vcol_shgrp;
struct DRWShadingGroup *image_shgrp;
struct DRWShadingGroup *image_tiled_shgrp;
} WORKBENCH_Prepass;
typedef struct WORKBENCH_PrivateData {
struct GHash *material_hash;
@@ -211,7 +275,11 @@ typedef struct WORKBENCH_PrivateData {
struct GPUShader *transparent_accum_textured_sh;
struct GPUShader *transparent_accum_textured_array_sh;
struct GPUShader *transparent_accum_vertex_sh;
struct WORKBENCH_ViewLayerData *vldata;
View3DShading shading;
eContextObjectMode ctx_mode;
StudioLight *studio_light;
const UserDef *preferences;
/* Does this instance owns the `world_ubo` field.
@@ -241,7 +309,47 @@ typedef struct WORKBENCH_PrivateData {
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;
/* Smart Morphological Anti-Aliasing */
struct GPUTexture *smaa_edge_tx;
struct GPUTexture *smaa_weight_tx;
/** Weight of the smaa pass. */
float smaa_mix_factor;
/* Opaque pipeline */
struct GPUTexture *object_id_tx;
struct GPUTexture *material_buffer_tx;
struct GPUTexture *composite_buffer_tx;
struct GPUTexture *normal_buffer_tx;
/* Transparent pipeline */
struct GPUTexture *accum_buffer_tx;
struct GPUTexture *reveal_buffer_tx;
WORKBENCH_Prepass prepass[2][2][2];
/* Materials */
struct BLI_memblock *material_ubo;
struct BLI_memblock *material_ubo_data;
WORKBENCH_UBO_Material *material_ubo_data_curr;
struct GPUUniformBuffer *material_ubo_curr;
struct GPUTexture *dummy_image_tx;
int material_chunk_count;
int material_chunk_curr;
int material_index;
/* Shadow */
struct DRWShadingGroup *shadow_pass_grp[2];
struct DRWShadingGroup *shadow_fail_grp[2];
struct DRWShadingGroup *shadow_fail_caps_grp[2];
float light_direction_ws[3];
/* Volumes */
bool volumes_do;
@@ -267,9 +375,7 @@ typedef struct WORKBENCH_PrivateData {
float dof_ratio;
bool dof_enabled;
/* Color Management */
bool use_color_management;
bool use_color_render_settings;
eGPUShaderConfig sh_cfg;
} WORKBENCH_PrivateData; /* Transient data */
typedef struct WORKBENCH_EffectInfo {
@@ -307,11 +413,15 @@ 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 {
struct GPUUniformBuffer *dof_sample_ubo;
struct GPUUniformBuffer *world_ubo;
} WORKBENCH_WorldData;
struct GPUUniformBuffer *cavity_sample_ubo;
struct GPUTexture *cavity_jitter_tx;
struct BLI_memblock *material_ubo;
struct BLI_memblock *material_ubo_data;
int cavity_sample_count;
} WORKBENCH_ViewLayerData;
/* Enumeration containing override options for base color rendering.
* This is used to during painting to force the base color to show what you are
@@ -431,6 +541,48 @@ BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_Priv
return result;
}
/* workbench_opaque.c */
void workbench_opaque_engine_init(WORKBENCH_Data *data);
void workbench_opaque_cache_init(WORKBENCH_Data *data);
/* workbench_transparent.c */
void workbench_transparent_engine_init(WORKBENCH_Data *data);
void workbench_transparent_cache_init(WORKBENCH_Data *data);
/* workbench_shadow.c */
void workbench_shadow_cache_init(WORKBENCH_Data *data);
void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat);
/* 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);
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);
GPUShader *workbench_shader_shadow_pass_get(bool manifold);
GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap);
GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature);
GPUShader *workbench_shader_outline_get(void);
GPUShader *workbench_shader_antialiasing_accumulation_get(void);
GPUShader *workbench_shader_antialiasing_get(int stage);
void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
GPUShader **downsample_sh,
GPUShader **blur1_sh,
GPUShader **blur2_sh,
GPUShader **resolve_sh);
void workbench_shader_library_ensure(void);
void workbench_shader_free(void);
/* workbench_deferred.c */
void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
void workbench_deferred_engine_free(void);
@@ -461,8 +613,10 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_
int interp);
/* workbench_effect_aa.c */
void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx);
void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx);
int workbench_aa_sample_count_get(WORKBENCH_PrivateData *wpd);
void workbench_aa_engine_init(WORKBENCH_Data *vedata);
void workbench_aa_cache_init(WORKBENCH_Data *vedata);
void workbench_aa_draw_pass(WORKBENCH_Data *vedata);
/* workbench_effect_fxaa.c */
void workbench_fxaa_engine_init(void);
@@ -476,15 +630,20 @@ DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_bu
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_taa_calculate_num_iterations(WORKBENCH_PrivateData *wpd);
int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata);
/* workbench_effect_cavity.c */
void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd);
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 */
@@ -526,11 +685,37 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd,
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,
int color_type);
DRWShadingGroup *workbench_material_setup_ex(
WORKBENCH_PrivateData *wpd, Object *ob, int mat_nr, int 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_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]);
void studiolight_update_light(WORKBENCH_PrivateData *wpd);
bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd,
Object *ob,
WORKBENCH_ObjectData *oed);
@@ -547,6 +732,8 @@ 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_material_ubos(WORKBENCH_PrivateData *wpd);
struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd);
/* workbench_volume.c */
void workbench_volume_engine_init(void);

View File

@@ -154,7 +154,7 @@ void workbench_render(WORKBENCH_Data *data,
DRW_hair_update();
/* Draw. */
int num_samples = workbench_taa_calculate_num_iterations(data);
int num_samples = workbench_taa_calculate_num_iterations(data->stl->wpd);
for (int sample = 0; sample < num_samples; sample++) {
if (RE_engine_test_break(engine)) {
break;
@@ -179,7 +179,7 @@ void workbench_render(WORKBENCH_Data *data,
DRW_hair_update();
/* Draw. */
int num_samples = workbench_taa_calculate_num_iterations(data);
int num_samples = workbench_taa_calculate_num_iterations(data->stl->wpd);
for (int sample = 0; sample < num_samples; sample++) {
if (RE_engine_test_break(engine)) {
break;

View File

@@ -0,0 +1,463 @@
/*
* 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_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_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_object_outline_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[];
/* Maximum number of variations. */
#define MAX_LIGHTING 3
#define MAX_COLOR 3
#define MAX_GEOM 2
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[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();
DRW_SHADER_LIB_ADD(e_data.lib, common_smaa_lib);
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, 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_object_outline_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, 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)
{
if (e_data.smaa_sh[stage] == NULL) {
char *frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_workbench_effect_smaa_frag_glsl);
e_data.smaa_sh[stage] = 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_FAIL\n",
(manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
(manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
NULL},
});
= DRW_shader_create_fullscreen(frag, NULL);
MEM_freeN(frag);
}
return e_data.smaa_sh[stage];
}
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]);
}
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);
}

View File

@@ -0,0 +1,137 @@
/*
* 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 "workbench_engine.h"
#include "workbench_private.h"
void workbench_shadow_cache_init(WORKBENCH_Data *data)
{
WORKBENCH_PassList *psl = data->psl;
WORKBENCH_PrivateData *wpd = data->stl->wpd;
struct GPUShader *sh;
DRWShadingGroup *grp;
studiolight_update_light(wpd);
if (SHADOW_ENABLED(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_pass[0], state | depth_pass_state);
DRW_PASS_CREATE(psl->shadow_pass[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_pass[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_pass[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_pass[1]);
}
}
else {
psl->shadow_pass[0] = NULL;
psl->shadow_pass[1] = NULL;
}
}
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 (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->light_direction_ws);
DRWShadingGroup *grp;
bool use_shadow_pass_technique = !studiolight_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 = studiolight_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
}
}
}

View File

@@ -52,8 +52,8 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
for (int i = 0; i < 4; i++) {
WORKBENCH_UBO_Light *light = &wd->lights[i];
SolidLight *sl = &studiolight->light[i];
if (sl->flag) {
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. */
@@ -68,7 +68,12 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd,
}
}
copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
if (studiolight) {
copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
}
else {
copy_v3_fl(wd->ambient_color, 1.0f);
}
}
static void compute_parallel_lines_nor_and_dist(const float v1[2],
@@ -89,23 +94,24 @@ static void compute_parallel_lines_nor_and_dist(const float v1[2],
}
}
void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
void studiolight_update_light(WORKBENCH_PrivateData *wpd)
{
wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
wpd->shadow_changed = !compare_v3v3(
wpd->cached_shadow_direction, wpd->light_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], light_direction);
copy_v3_v3(wpd->shadow_mat[2], wpd->light_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->cached_shadow_direction, light_direction);
copy_v3_v3(wpd->cached_shadow_direction, wpd->light_direction_ws);
}
float planes[6][4];

View File

@@ -0,0 +1,147 @@
/*
* 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 "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)
{
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
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;
spec_tx = use_spec ? spec_tx : diff_tx;
DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
DRW_shgroup_uniform_bool_copy(grp, "useSpecularMatcap", use_spec);
}
else if (STUDIOLIGHT_TYPE_STUDIO_ENABLED(wpd)) {
DRW_shgroup_uniform_bool_copy(grp, "useSpecularLighting", use_spec);
}
}
void workbench_transparent_cache_init(WORKBENCH_Data *data)
{
WORKBENCH_PassList *psl = data->psl;
WORKBENCH_PrivateData *wpd = data->stl->wpd;
const DRWContextState *draw_ctx = DRW_context_state_get();
RegionView3D *rv3d = draw_ctx->rv3d;
View3D *v3d = draw_ctx->v3d;
struct GPUShader *sh;
DRWShadingGroup *grp;
{
DRWState clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
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_pass, state | cull_state | clip_state);
pass = psl->transp_accum_infront_pass;
}
else {
DRW_PASS_CREATE(psl->transp_accum_pass, state | cull_state | clip_state);
pass = psl->transp_accum_pass;
}
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_pass, state);
sh = workbench_shader_transparent_resolve_get(wpd);
grp = DRW_shgroup_create(sh, psl->transp_resolve_pass);
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);
}
}

View File

@@ -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,
@@ -244,6 +247,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 {
@@ -400,6 +421,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);
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);

View File

@@ -175,6 +175,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,

View File

@@ -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) {
@@ -220,7 +224,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 +241,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)

View File

@@ -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,
int drawtype,
bool use_xray)
static void drw_engines_enable_from_engine(RenderEngineType *engine_type, int 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;
}
@@ -1180,9 +1158,8 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
{
View3D *v3d = DST.draw_ctx.v3d;
const int 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) {
use_drw_engine(&draw_engine_gpencil_type);
}

View File

@@ -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)

View File

@@ -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,
@@ -464,3 +467,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;
}
/** \} */

View File

@@ -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)

View File

@@ -455,10 +455,6 @@ enum {
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,
};
/** #View3DShading.background_type */