Compare commits
19 Commits
tmp-gltext
...
tmp-workbe
Author | SHA1 | Date | |
---|---|---|---|
bd6567b262 | |||
91dfe40ef0 | |||
c8407006aa | |||
a102b7ebe5 | |||
aae2e1326f | |||
606f1d80b3 | |||
f426e71e09 | |||
62a7ac8f17 | |||
73de98e6e0 | |||
d36e63f8db | |||
e34ce36ea4 | |||
76a7ea0b71 | |||
46f8367eac | |||
5759e2d6c4 | |||
e6e740f317 | |||
b6e083358e | |||
1e58e68c1a | |||
1545c37cdb | |||
616545b5cf |
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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)});
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,44 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
|
||||
|
||||
uniform sampler2D materialBuffer;
|
||||
uniform sampler2D normalBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
|
||||
vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix);
|
||||
vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st));
|
||||
vec4 mat_data = texture(materialBuffer, uvcoordsvar.st);
|
||||
|
||||
vec3 base_color = mat_data.rgb;
|
||||
|
||||
float roughness, metallic;
|
||||
workbench_float_pair_decode(mat_data.a, roughness, metallic);
|
||||
|
||||
#ifdef V3D_LIGHTING_MATCAP
|
||||
/* When using matcaps, mat_data.a is the backface sign. */
|
||||
N = (mat_data.a > 0.0) ? N : -N;
|
||||
|
||||
fragColor.rgb = get_matcap_lighting(base_color, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_STUDIO
|
||||
fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I);
|
||||
#endif
|
||||
|
||||
#ifdef V3D_LIGHTING_FLAT
|
||||
fragColor.rgb = base_color;
|
||||
#endif
|
||||
|
||||
fragColor.rgb *= get_shadow(N);
|
||||
|
||||
fragColor.a = 1.0;
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
#ifndef CURVATURE_OFFSET
|
||||
# define CURVATURE_OFFSET 1
|
||||
#endif
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
float curvature_soft_clamp(float curvature, float control)
|
||||
{
|
||||
@@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control)
|
||||
return 0.25 / control;
|
||||
}
|
||||
|
||||
float calculate_curvature(
|
||||
usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley)
|
||||
void curvature_compute(vec2 uv,
|
||||
usampler2D objectIdBuffer,
|
||||
sampler2D normalBuffer,
|
||||
out float curvature)
|
||||
{
|
||||
uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r;
|
||||
uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r;
|
||||
uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r;
|
||||
uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r;
|
||||
curvature = 0.0;
|
||||
|
||||
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
|
||||
uint object_up = texture(objectIdBuffer, uv + offset.zy).r;
|
||||
uint object_down = texture(objectIdBuffer, uv - offset.zy).r;
|
||||
uint object_right = texture(objectIdBuffer, uv + offset.xz).r;
|
||||
uint object_left = texture(objectIdBuffer, uv - offset.xz).r;
|
||||
|
||||
/* Remove object outlines. */
|
||||
if ((object_up != object_down) || (object_right != object_left)) {
|
||||
return 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg;
|
||||
vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg;
|
||||
vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg;
|
||||
vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg;
|
||||
float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g;
|
||||
float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g;
|
||||
float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r;
|
||||
float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r;
|
||||
|
||||
normal_up = workbench_normal_decode(normal_up).rg;
|
||||
normal_down = workbench_normal_decode(normal_down).rg;
|
||||
normal_left = workbench_normal_decode(normal_left).rg;
|
||||
normal_right = workbench_normal_decode(normal_right).rg;
|
||||
|
||||
float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r));
|
||||
float normal_diff = (normal_up - normal_down) + (normal_right - normal_left);
|
||||
|
||||
if (normal_diff < 0) {
|
||||
return -2.0 * curvature_soft_clamp(-normal_diff, valley);
|
||||
curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley);
|
||||
}
|
||||
else {
|
||||
curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge);
|
||||
}
|
||||
|
||||
return 2.0 * curvature_soft_clamp(normal_diff, ridge);
|
||||
}
|
||||
|
@@ -5,12 +5,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;
|
||||
};
|
||||
|
@@ -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;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
|
||||
|
||||
uniform usampler2D objectIdBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
|
||||
vec2 uv = uvcoordsvar.st;
|
||||
|
||||
uint center_id = texture(objectIdBuffer, uv).r;
|
||||
uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r,
|
||||
texture(objectIdBuffer, uv - offset.zy).r,
|
||||
texture(objectIdBuffer, uv + offset.xz).r,
|
||||
texture(objectIdBuffer, uv - offset.xz).r);
|
||||
|
||||
float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25));
|
||||
|
||||
fragColor = world_data.object_outline_color * outline_opacity;
|
||||
}
|
@@ -0,0 +1,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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -0,0 +1,83 @@
|
||||
|
||||
/* TODO(fclem) deduplicate code. */
|
||||
bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
|
||||
{
|
||||
vec2 tile_pos = floor(co.xy);
|
||||
|
||||
if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10)
|
||||
return false;
|
||||
|
||||
float tile = 10.0 * tile_pos.y + tile_pos.x;
|
||||
if (tile >= textureSize(map, 0).x)
|
||||
return false;
|
||||
|
||||
/* Fetch tile information. */
|
||||
float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x;
|
||||
if (tile_layer < 0.0)
|
||||
return false;
|
||||
|
||||
vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0);
|
||||
|
||||
co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(image, 0).xy);
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
|
||||
return texture(image, uv);
|
||||
}
|
||||
|
||||
vec4 workbench_sample_texture_array(sampler2DArray tile_array,
|
||||
sampler1DArray tile_data,
|
||||
vec2 coord,
|
||||
bool nearest_sampling)
|
||||
{
|
||||
vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
|
||||
|
||||
vec3 uv = vec3(coord, 0);
|
||||
if (!node_tex_tile_lookup(uv, tile_array, tile_data))
|
||||
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
/* TODO(fclem) We could do the same with sampler objects.
|
||||
* But this is a quick workaround instead of messing with the GPUTexture itself. */
|
||||
uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
|
||||
return texture(tile_array, uv);
|
||||
}
|
||||
|
||||
uniform sampler2DArray imageTileArray;
|
||||
uniform sampler1DArray imageTileData;
|
||||
uniform sampler2D imageTexture;
|
||||
|
||||
uniform float imageTransparencyCutoff = 0.1;
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremult;
|
||||
|
||||
vec3 workbench_image_color(vec2 uvs)
|
||||
{
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest);
|
||||
# else
|
||||
vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest);
|
||||
# endif
|
||||
|
||||
/* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
|
||||
if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) {
|
||||
color.rgb /= color.a;
|
||||
}
|
||||
|
||||
# ifdef GPU_FRAGMENT_SHADER
|
||||
if (color.a < imageTransparencyCutoff) {
|
||||
discard;
|
||||
}
|
||||
# endif
|
||||
|
||||
return color.rgb;
|
||||
#else
|
||||
return vec3(1.0);
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,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);
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
|
||||
layout(std140) uniform material_block
|
||||
{
|
||||
vec4 mat_data[4096];
|
||||
};
|
||||
|
||||
/* If set to -1, the resource handle is used instead. */
|
||||
uniform int materialIndex;
|
||||
|
||||
void workbench_material_data_get(
|
||||
int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
|
||||
{
|
||||
handle = (materialIndex != -1) ? materialIndex : handle;
|
||||
vec4 data = mat_data[uint(handle) & 0xFFFu];
|
||||
color = data.rgb;
|
||||
|
||||
uint encoded_data = floatBitsToUint(data.w);
|
||||
alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0);
|
||||
roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0);
|
||||
metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0);
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
|
||||
uniform sampler2D depthBuffer;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(depthBuffer, uvcoordsvar.st).r;
|
||||
/* Discard background pixels. */
|
||||
if (depth == 1.0) {
|
||||
discard;
|
||||
}
|
||||
/* Make this fragment occlude any fragment that will try to
|
||||
* render over it in the normal passes. */
|
||||
gl_FragDepth = 0.0;
|
||||
}
|
@@ -1,92 +1,29 @@
|
||||
|
||||
uniform vec4 materialColorAndMetal;
|
||||
uniform float materialRoughness;
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
|
||||
|
||||
#ifdef TEXTURE_IMAGE_ARRAY
|
||||
uniform sampler2DArray image_tile_array;
|
||||
uniform sampler1DArray image_tile_data;
|
||||
#else
|
||||
uniform sampler2D image;
|
||||
#endif
|
||||
uniform float ImageTransparencyCutoff = 0.1;
|
||||
uniform bool imageNearest;
|
||||
uniform bool imagePremultiplied;
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
in vec3 normal_viewport;
|
||||
#endif
|
||||
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
in vec2 uv_interp;
|
||||
#endif
|
||||
#ifdef V3D_SHADING_VERTEX_COLOR
|
||||
in vec3 vertexColor;
|
||||
#endif
|
||||
|
||||
#ifdef HAIR_SHADER
|
||||
flat in float hair_rand;
|
||||
#endif
|
||||
|
||||
#ifdef MATDATA_PASS_ENABLED
|
||||
layout(location = 0) out vec4 materialData;
|
||||
#endif
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
layout(location = 1) out uint objectId;
|
||||
#endif
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
layout(location = 2) out WB_Normal normalViewport;
|
||||
#endif
|
||||
layout(location = 1) out WB_Normal normalData;
|
||||
layout(location = 2) out uint objectId;
|
||||
|
||||
uniform bool useMatcap = false;
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef MATDATA_PASS_ENABLED
|
||||
float metallic, roughness;
|
||||
vec4 color;
|
||||
normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
|
||||
|
||||
# if defined(V3D_SHADING_TEXTURE_COLOR)
|
||||
# ifdef TEXTURE_IMAGE_ARRAY
|
||||
color = workbench_sample_texture_array(
|
||||
image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied);
|
||||
# else
|
||||
color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied);
|
||||
# endif
|
||||
if (color.a < ImageTransparencyCutoff) {
|
||||
discard;
|
||||
materialData = vec4(color_interp, packed_rough_metal);
|
||||
|
||||
objectId = uint(object_id);
|
||||
|
||||
if (useMatcap) {
|
||||
/* For matcaps, save front facing in alpha channel. */
|
||||
materialData.a = float(gl_FrontFacing);
|
||||
}
|
||||
# elif defined(V3D_SHADING_VERTEX_COLOR)
|
||||
color.rgb = vertexColor;
|
||||
# else
|
||||
color.rgb = materialColorAndMetal.rgb;
|
||||
# endif
|
||||
|
||||
# ifdef V3D_LIGHTING_MATCAP
|
||||
/* Encode front facing in metallic channel. */
|
||||
metallic = float(gl_FrontFacing);
|
||||
roughness = 0.0;
|
||||
# else
|
||||
metallic = materialColorAndMetal.a;
|
||||
roughness = materialRoughness;
|
||||
# endif
|
||||
|
||||
# ifdef HAIR_SHADER
|
||||
/* Add some variation to the hairs to avoid uniform look. */
|
||||
float hair_variation = hair_rand * 0.1;
|
||||
color = clamp(color - hair_variation, 0.0, 1.0);
|
||||
metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0);
|
||||
roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0);
|
||||
# endif
|
||||
|
||||
materialData.rgb = color.rgb;
|
||||
materialData.a = workbench_float_pair_encode(roughness, metallic);
|
||||
#endif /* MATDATA_PASS_ENABLED */
|
||||
|
||||
#ifdef OBJECT_ID_PASS_ENABLED
|
||||
objectId = uint(resource_id + 1) & 0xFFu;
|
||||
#endif
|
||||
|
||||
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
|
||||
vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
|
||||
n = normalize(n);
|
||||
normalViewport = workbench_normal_encode(n);
|
||||
#ifdef V3D_SHADING_TEXTURE_COLOR
|
||||
materialData.rgb = workbench_image_color(uv_interp);
|
||||
#endif
|
||||
}
|
||||
|
@@ -0,0 +1,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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
@@ -1,15 +1,19 @@
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 materialData;
|
||||
layout(location = 1) out vec4 normalData;
|
||||
layout(location = 2) out uint objectId;
|
||||
|
||||
void main()
|
||||
{
|
||||
const float intensity = 0.25;
|
||||
const float a = 0.25;
|
||||
#ifdef SHADOW_PASS
|
||||
fragColor = vec4(
|
||||
(gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0);
|
||||
materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0);
|
||||
#else
|
||||
fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) :
|
||||
vec3(-intensity, -intensity, intensity),
|
||||
1.0);
|
||||
materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a);
|
||||
#endif
|
||||
materialData.a = 0.0;
|
||||
normalData = vec4(0.0);
|
||||
objectId = 0u;
|
||||
}
|
||||
|
@@ -0,0 +1,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, 122–141, 2013
|
||||
*/
|
||||
float calculate_transparent_weight(void)
|
||||
{
|
||||
float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix);
|
||||
#if 0
|
||||
/* Eq 10 : Good for surfaces with varying opacity (like particles) */
|
||||
float a = min(1.0, alpha * 10.0) + 0.01;
|
||||
float b = -gl_FragCoord.z * 0.95 + 1.0;
|
||||
float w = a * a * a * 3e2 * b * b * b;
|
||||
#else
|
||||
/* Eq 7 put more emphasis on surfaces closer to the view. */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
|
||||
// float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
|
||||
/* Same as eq 7, but optimized. */
|
||||
float a = abs(z) / 5.0;
|
||||
float b = abs(z) / 200.0;
|
||||
b *= b;
|
||||
float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
|
||||
#endif
|
||||
return clamp(w, 1e-2, 3e2);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
/* 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);
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
|
||||
uniform sampler2D transparentAccum;
|
||||
uniform sampler2D transparentRevealage;
|
||||
|
||||
in vec4 uvcoordsvar;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
/* Based on :
|
||||
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
|
||||
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Revealage is actually stored in transparentAccum alpha channel.
|
||||
* This is a workaround to older hardware not having separate blend equation per render target.
|
||||
*/
|
||||
vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
|
||||
float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
|
||||
float trans_reveal = trans_accum.a;
|
||||
|
||||
/* Listing 4 */
|
||||
fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4);
|
||||
fragColor.a = 1.0 - trans_reveal;
|
||||
}
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
@@ -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,
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
162
source/blender/draw/engines/workbench/workbench_effect_cavity.c
Normal file
162
source/blender/draw/engines/workbench/workbench_effect_cavity.c
Normal 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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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:
|
||||
|
@@ -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},
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
{
|
||||
|
166
source/blender/draw/engines/workbench/workbench_opaque.c
Normal file
166
source/blender/draw/engines/workbench/workbench_opaque.c
Normal 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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
463
source/blender/draw/engines/workbench/workbench_shader.c
Normal file
463
source/blender/draw/engines/workbench/workbench_shader.c
Normal 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);
|
||||
}
|
137
source/blender/draw/engines/workbench/workbench_shadow.c
Normal file
137
source/blender/draw/engines/workbench/workbench_shadow.c
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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];
|
||||
|
147
source/blender/draw/engines/workbench/workbench_transparent.c
Normal file
147
source/blender/draw/engines/workbench/workbench_transparent.c
Normal 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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user