Blender  V2.93
workbench_effect_cavity.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2020, Blender Foundation.
17  */
18 
30 #include "DRW_render.h"
31 
32 #include "BLI_rand.h"
33 
34 #include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
35 
36 #include "workbench_engine.h"
37 #include "workbench_private.h"
38 
39 #define JITTER_TEX_SIZE 64
40 #define CAVITY_MAX_SAMPLES 512
41 
42 /* Using Hammersley distribution */
43 static float *create_disk_samples(int num_samples, int num_iterations)
44 {
45  BLI_assert(num_samples * num_iterations <= CAVITY_MAX_SAMPLES);
46  const int total_samples = num_samples * num_iterations;
47  const float num_samples_inv = 1.0f / num_samples;
48  /* vec4 to ensure memory alignment. */
49  float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__);
50  for (int i = 0; i < total_samples; i++) {
51  float it_add = (i / num_samples) * 0.499f;
52  float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
53  double dphi;
54  BLI_hammersley_1d(i, &dphi);
55 
56  float phi = (float)dphi * 2.0f * M_PI + it_add;
57  texels[i][0] = cosf(phi);
58  texels[i][1] = sinf(phi);
59  /* This deliberately distribute more samples
60  * at the center of the disk (and thus the shadow). */
61  texels[i][2] = r;
62  }
63 
64  return (float *)texels;
65 }
66 
67 static struct GPUTexture *create_jitter_texture(int num_samples)
68 {
69  float jitter[64 * 64][4];
70  const float num_samples_inv = 1.0f / num_samples;
71 
72  for (int i = 0; i < 64 * 64; i++) {
73  float phi = blue_noise[i][0] * 2.0f * M_PI;
74  /* This rotate the sample per pixels */
75  jitter[i][0] = cosf(phi);
76  jitter[i][1] = sinf(phi);
77  /* This offset the sample along its direction axis (reduce banding) */
78  float bn = blue_noise[i][1] - 0.5f;
79  CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
80  jitter[i][2] = bn * num_samples_inv;
81  jitter[i][3] = blue_noise[i][1];
82  }
83 
85 
86  return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]);
87 }
88 
90  const Scene *scene)
91 {
94 }
95 
97 {
98  View3DShading *shading = &wpd->shading;
99  const DRWContextState *draw_ctx = DRW_context_state_get();
100  Scene *scene = draw_ctx->scene;
101 
102  if (CAVITY_ENABLED(wpd)) {
103  int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
104  int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene);
105  const int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
106 
107  int sample = wpd->taa_sample % max_iter_count;
108  wd->cavity_sample_start = cavity_sample_count_single_iteration * sample;
109  wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1);
110 
112  wd->cavity_jitter_scale = 1.0f / 64.0f;
113 
118 
119  wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f);
120  wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f);
121  }
122 }
123 
125 {
126  const DRWContextState *draw_ctx = DRW_context_state_get();
127  Scene *scene = draw_ctx->scene;
128 
129  int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
130  int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene);
131  const int max_iter_count = max_ii(1, cavity_sample_count / cavity_sample_count_single_iteration);
132 
133  if (wpd->vldata->cavity_sample_count != cavity_sample_count) {
136  }
137 
138  if (wpd->vldata->cavity_sample_ubo == NULL) {
139  float *samples = create_disk_samples(cavity_sample_count_single_iteration, max_iter_count);
140  wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count);
141  /* NOTE: Uniform buffer needs to always be filled to be valid. */
143  sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples, "wb_CavitySamples");
144  wpd->vldata->cavity_sample_count = cavity_sample_count;
145  MEM_freeN(samples);
146  }
147 }
148 
150 {
151  WORKBENCH_PassList *psl = data->psl;
152  WORKBENCH_PrivateData *wpd = data->stl->wpd;
154  struct GPUShader *sh;
155  DRWShadingGroup *grp;
156 
157  if (CAVITY_ENABLED(wpd)) {
159 
162 
164 
165  grp = DRW_shgroup_create(sh, psl->cavity_ps);
166  DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
167  DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
168  DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
169 
170  if (SSAO_ENABLED(wpd)) {
171  DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
172  DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx);
173  }
174  if (CURVATURE_ENABLED(wpd)) {
175  DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
176  }
178  }
179  else {
180  psl->cavity_ps = NULL;
181  }
182 }
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE float square_f(float a)
#define M_PI
Definition: BLI_math_base.h:38
Random number functions.
void BLI_hammersley_1d(unsigned int n, double *r)
Definition: rand.cc:365
#define UNUSED_VARS(...)
@ DRW_TEX_WRAP
Definition: DRW_render.h:140
@ DRW_STATE_WRITE_COLOR
Definition: DRW_render.h:315
@ DRW_STATE_BLEND_MUL
Definition: DRW_render.h:345
#define DRW_UBO_FREE_SAFE(ubo)
Definition: DRW_render.h:188
#define DRW_PASS_CREATE(pass, state)
Definition: DRW_render.h:593
#define DRW_TEXTURE_FREE_SAFE(tex)
Definition: DRW_render.h:180
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
struct GPUShader GPUShader
Definition: GPU_shader.h:33
struct GPUTexture GPUTexture
Definition: GPU_texture.h:33
@ GPU_RGBA16F
Definition: GPU_texture.h:94
GPUUniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
Group RGB to Bright Vector Camera CLAMP
Scene scene
const DRWContextState * DRW_context_state_get(void)
DefaultTextureList * DRW_viewport_texture_list_get(void)
Definition: draw_manager.c:702
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuf *ubo)
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob, uint tri_count)
DRWShadingGroup * DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
GPUTexture * DRW_texture_create_2d(int w, int h, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
const float blue_noise[64 *64][4]
Definition: eevee_lut.c:3507
const float btdf_split_sum_ggx[16][64 *64 *2]
Definition: eevee_lut.c:6585
const float bsdf_split_sum_ggx[64 *64 *2]
Definition: eevee_lut.c:5558
const float ltc_mag_ggx[64 *64 *2]
Definition: eevee_lut.c:2077
const float ltc_disk_integral[64 *64]
Definition: eevee_lut.c:2991
const float ltc_mat_ggx[64 *64 *4]
Definition: eevee_lut.c:26
#define sinf(x)
#define cosf(x)
#define fmodf(x, y)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong state[N]
static void sample(SocketReader *reader, int x, int y, float color[4])
struct Scene * scene
Definition: DRW_render.h:745
struct GPUTexture * depth
float matcap_ssao_distance
float matcap_ssao_attenuation
struct SceneDisplay display
float curvature_ridge_factor
float cavity_valley_factor
float curvature_valley_factor
struct DRWPass * cavity_ps
struct GPUUniformBuf * world_ubo
struct GPUTexture * object_id_tx
struct GPUTexture * normal_buffer_tx
struct WORKBENCH_ViewLayerData * vldata
struct GPUUniformBuf * cavity_sample_ubo
struct GPUTexture * cavity_jitter_tx
void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd)
void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd, const Scene *scene)
void workbench_cavity_cache_init(WORKBENCH_Data *data)
static float * create_disk_samples(int num_samples, int num_iterations)
static struct GPUTexture * create_jitter_texture(int num_samples)
#define CAVITY_MAX_SAMPLES
#define CURVATURE_ENABLED(wpd)
GPUShader * workbench_shader_cavity_get(bool cavity, bool curvature)
#define CAVITY_ENABLED(wpd)
#define SSAO_ENABLED(wpd)