PointCloud: Initial rendering support for Workbench

Also includes outline overlays. Removes the temp overlay drawing

We make the geometry follow camera like billboards this uses less
geometry. Currently we use half octahedron for now. Goal would be
to use icospheres.

This patch also optimize the case when pointcloud has uniform radius.
However we should premultiply the radius prop by the default radius
beforehand to avoid a multiplication on CPU.

Using geometry instead of pseudo raytraced spheres is more scalable as
we can render as low as 1 or 2 triangle to a full half sphere and can
integrate easily in the render pipeline using a low amount of code.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D8301
This commit is contained in:
Clément Foucault 2020-07-15 20:10:45 +02:00
parent d4d810f817
commit 058514aa0a
Notes: blender-bot 2023-02-14 11:08:33 +01:00
Referenced by issue #87150, Points’ appearance in orthographic mode
24 changed files with 401 additions and 252 deletions

View File

@ -143,7 +143,6 @@ set(SRC
engines/overlay/overlay_outline.c
engines/overlay/overlay_paint.c
engines/overlay/overlay_particle.c
engines/overlay/overlay_pointcloud.c
engines/overlay/overlay_sculpt.c
engines/overlay/overlay_shader.c
engines/overlay/overlay_wireframe.c
@ -270,6 +269,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
@ -284,6 +284,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
@ -385,8 +386,6 @@ data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/pointcloud_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/pointcloud_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/sculpt_mask_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)

View File

@ -182,7 +182,6 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_motion_path_cache_init(vedata);
OVERLAY_outline_cache_init(vedata);
OVERLAY_particle_cache_init(vedata);
OVERLAY_pointcloud_cache_init(vedata);
OVERLAY_wireframe_cache_init(vedata);
}
@ -403,12 +402,6 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OVERLAY_particle_cache_populate(vedata, ob);
}
/* TODO: these should not be overlays, just here for testing since it's
* easier to implement than integrating it into eevee/workbench. */
if (ob->type == OB_POINTCLOUD) {
OVERLAY_pointcloud_cache_populate(vedata, ob);
}
/* Relationship, object center, bounbox ... */
if (!pd->hide_overlays) {
OVERLAY_extra_cache_populate(vedata, ob);
@ -482,7 +475,6 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_armature_draw(vedata);
OVERLAY_particle_draw(vedata);
OVERLAY_metaball_draw(vedata);
OVERLAY_pointcloud_draw(vedata);
OVERLAY_gpencil_draw(vedata);
OVERLAY_extra_draw(vedata);

View File

@ -138,6 +138,11 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
GPUShader *sh_geom_ptcloud = OVERLAY_shader_outline_prepass_pointcloud();
pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil();
pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
@ -288,6 +293,12 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
return;
}
if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) {
/* Looks bad in this case. Could be relaxed if we draw a
* wireframe of some sort in the future. */
return;
}
if (dupli && !init_dupli) {
geom = dupli->outline_geom;
shgroup = dupli->outline_shgrp;
@ -307,12 +318,18 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
}
if (geom) {
shgroup = pd->outlines_grp;
shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp;
}
}
if (shgroup && geom) {
DRW_shgroup_call(shgroup, geom, ob);
if (ob->type == OB_POINTCLOUD) {
/* Draw range to avoid drawcall batching messing up the instance attrib. */
DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0);
}
else {
DRW_shgroup_call(shgroup, geom, ob);
}
}
if (init_dupli) {

View File

@ -1,72 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2020, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*/
#include "DRW_render.h"
#include "DEG_depsgraph_query.h"
#include "DNA_pointcloud_types.h"
#include "BKE_pointcache.h"
#include "overlay_private.h"
/* -------------------------------------------------------------------- */
/** \name PointCloud
* \{ */
void OVERLAY_pointcloud_cache_init(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
GPUShader *sh;
DRWShadingGroup *grp;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
DRW_PASS_CREATE(psl->pointcloud_ps, state | pd->clipping_state);
sh = OVERLAY_shader_pointcloud_dot();
pd->pointcloud_dots_grp = grp = DRW_shgroup_create(sh, psl->pointcloud_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
void OVERLAY_pointcloud_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
struct GPUBatch *geom = DRW_cache_pointcloud_get_dots(ob);
const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->pointcloud_dots_grp);
DRW_shgroup_uniform_vec4_copy(grp, "color", color);
DRW_shgroup_call(grp, geom, ob);
}
void OVERLAY_pointcloud_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
DRW_draw_pass(psl->pointcloud_ps);
}
/** \} */

View File

@ -243,6 +243,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
DRWShadingGroup *outlines_ptcloud_grp;
DRWShadingGroup *outlines_gpencil_grp;
DRWShadingGroup *paint_depth_grp;
DRWShadingGroup *paint_surf_grp;
@ -550,10 +551,6 @@ void OVERLAY_particle_cache_init(OVERLAY_Data *vedata);
void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_particle_draw(OVERLAY_Data *vedata);
void OVERLAY_pointcloud_cache_init(OVERLAY_Data *vedata);
void OVERLAY_pointcloud_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_pointcloud_draw(OVERLAY_Data *vedata);
void OVERLAY_sculpt_cache_init(OVERLAY_Data *vedata);
void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_sculpt_draw(OVERLAY_Data *vedata);
@ -610,6 +607,7 @@ GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
GPUShader *OVERLAY_shader_outline_prepass_gpencil(void);
GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void);
GPUShader *OVERLAY_shader_extra_grid(void);
GPUShader *OVERLAY_shader_outline_detect(void);
GPUShader *OVERLAY_shader_paint_face(void);
@ -620,7 +618,6 @@ GPUShader *OVERLAY_shader_paint_weight(void);
GPUShader *OVERLAY_shader_paint_wire(void);
GPUShader *OVERLAY_shader_particle_dot(void);
GPUShader *OVERLAY_shader_particle_shape(void);
GPUShader *OVERLAY_shader_pointcloud_dot(void);
GPUShader *OVERLAY_shader_sculpt_mask(void);
GPUShader *OVERLAY_shader_volume_velocity(bool use_needle);
GPUShader *OVERLAY_shader_wireframe(bool custom_bias);

View File

@ -103,8 +103,6 @@ extern char datatoc_paint_weight_vert_glsl[];
extern char datatoc_paint_wire_vert_glsl[];
extern char datatoc_particle_vert_glsl[];
extern char datatoc_particle_frag_glsl[];
extern char datatoc_pointcloud_vert_glsl[];
extern char datatoc_pointcloud_frag_glsl[];
extern char datatoc_sculpt_mask_vert_glsl[];
extern char datatoc_sculpt_mask_frag_glsl[];
extern char datatoc_volume_velocity_vert_glsl[];
@ -127,6 +125,7 @@ extern char datatoc_common_fullscreen_vert_glsl[];
extern char datatoc_common_fxaa_lib_glsl[];
extern char datatoc_common_smaa_lib_glsl[];
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
typedef struct OVERLAY_Shaders {
@ -181,6 +180,7 @@ typedef struct OVERLAY_Shaders {
GPUShader *motion_path_vert;
GPUShader *outline_prepass;
GPUShader *outline_prepass_gpencil;
GPUShader *outline_prepass_pointcloud;
GPUShader *outline_prepass_wire;
GPUShader *outline_detect;
GPUShader *paint_face;
@ -1135,6 +1135,33 @@ GPUShader *OVERLAY_shader_outline_prepass_gpencil(void)
return sh_data->outline_prepass_gpencil;
}
GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
if (!sh_data->outline_prepass_pointcloud) {
sh_data->outline_prepass_pointcloud = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_common_pointcloud_lib_glsl,
datatoc_gpu_shader_common_obinfos_lib_glsl,
datatoc_outline_prepass_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_common_view_lib_glsl,
datatoc_gpencil_common_lib_glsl,
datatoc_outline_prepass_frag_glsl,
NULL},
.defs = (const char *[]){sh_cfg->def,
"#define POINTCLOUD\n",
"#define INSTANCED_ATTR\n",
"#define UNIFORM_RESOURCE_ID\n",
NULL},
});
}
return sh_data->outline_prepass_pointcloud;
}
GPUShader *OVERLAY_shader_outline_detect(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
@ -1306,25 +1333,6 @@ GPUShader *OVERLAY_shader_particle_shape(void)
return sh_data->particle_shape;
}
GPUShader *OVERLAY_shader_pointcloud_dot(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
if (!sh_data->pointcloud_dot) {
sh_data->pointcloud_dot = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_globals_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_pointcloud_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_pointcloud_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, "#define USE_DOTS\n", NULL},
});
}
return sh_data->pointcloud_dot;
}
GPUShader *OVERLAY_shader_sculpt_mask(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();

View File

@ -235,10 +235,15 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
}
}
if (use_wire && ob->type == OB_VOLUME) {
/* Volume object as points exception. */
Volume *volume = ob->data;
if (volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS) {
if (use_wire && ELEM(ob->type, OB_VOLUME, OB_POINTCLOUD)) {
bool draw_as_points = true;
if (ob->type == OB_VOLUME) {
/* Volume object as points exception. */
Volume *volume = ob->data;
draw_as_points = volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS;
}
if (draw_as_points) {
float *color;
OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);

View File

@ -1,7 +1,7 @@
uniform bool isTransform;
#ifndef USE_GPENCIL
#if !defined(USE_GPENCIL) && !defined(POINTCLOUD)
in vec3 pos;
#endif
@ -56,7 +56,11 @@ void main()
# endif
#else
# ifdef POINTCLOUD
vec3 world_pos = pointcloud_get_pos();
# else
vec3 world_pos = point_object_to_world(pos);
# endif
gl_Position = point_world_to_ndc(world_pos);
# ifdef USE_GEOM
vPos = point_world_to_view(world_pos);

View File

@ -1,16 +0,0 @@
in vec4 finalColor;
out vec4 fragColor;
void main()
{
float dist = length(gl_PointCoord - vec2(0.5));
if (dist > 0.5) {
discard;
}
/* Nice sphere falloff. */
float intensity = sqrt(1.0 - dist * 2.0) * 0.5 + 0.5;
fragColor = finalColor * vec4(intensity, intensity, intensity, 1.0);
}

View File

@ -1,27 +0,0 @@
uniform vec4 color;
/* ---- Per instance Attrs ---- */
in vec3 pointcloud_pos;
in vec3 pointcloud_radius;
out vec4 finalColor;
void main()
{
vec3 world_pos = point_object_to_world(pointcloud_pos);
vec3 world_size = abs(mat3(ModelMatrix) * vec3(pointcloud_radius));
float world_radius = (world_size.x + world_size.y + world_size.z) / 3.0;
gl_Position = point_world_to_ndc(world_pos);
/* World sized points. */
gl_PointSize = sizePixel * world_radius * ProjectionMatrix[1][1] * sizeViewport.y /
gl_Position.w;
finalColor = color;
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
}

View File

@ -0,0 +1,38 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_pointcloud_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)
void main()
{
vec3 world_pos;
pointcloud_get_pos_and_nor(world_pos, normal_interp);
normal_interp = normalize(normal_world_to_view(normal_interp));
gl_Position = point_world_to_ndc(world_pos);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
uv_interp = vec2(0.0);
#ifdef OPAQUE_MATERIAL
float metallic, roughness;
#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = vec3(1.0);
}
#ifdef OPAQUE_MATERIAL
packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
#endif
object_id = int((uint(resource_id) + 1u) & 0xFFu);
}

View File

@ -130,6 +130,17 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
}
}
BLI_INLINE void workbench_object_drawcall(DRWShadingGroup *grp, struct GPUBatch *geom, Object *ob)
{
if (ob->type == OB_POINTCLOUD) {
/* Draw range to avoid drawcall batching messing up the instance attrib. */
DRW_shgroup_call_instance_range(grp, ob, geom, 0, 0);
}
else {
DRW_shgroup_call(grp, geom, ob);
}
}
static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@ -145,7 +156,7 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER);
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, state);
DRW_shgroup_call(grp, geom, ob);
workbench_object_drawcall(grp, geom, ob);
}
}
else {
@ -157,7 +168,7 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
continue;
}
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0);
DRW_shgroup_call(grp, geoms[i], ob);
workbench_object_drawcall(grp, geoms[i], ob);
}
}
}
@ -194,7 +205,7 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
if (geom) {
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp);
DRW_shgroup_call(grp, geom, ob);
workbench_object_drawcall(grp, geom, ob);
}
}
else {
@ -207,7 +218,7 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
continue;
}
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp);
DRW_shgroup_call(grp, geoms[i], ob);
workbench_object_drawcall(grp, geoms[i], ob);
}
}
}
@ -450,7 +461,7 @@ void workbench_cache_finish(void *ved)
/* 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++) {
for (int k = 0; k < WORKBENCH_DATATYPE_MAX; 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;

View File

@ -162,7 +162,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
eV3DShadingColorType color_type,
bool hair,
eWORKBENCH_DataType datatype,
bool *r_transp)
{
Image *ima = NULL;
@ -180,7 +180,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
switch (color_type) {
case V3D_SHADING_TEXTURE_COLOR: {
return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, sampler, hair);
return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, sampler, datatype);
}
case V3D_SHADING_MATERIAL_COLOR: {
/* For now, we use the same ubo for material and object coloring but with different indices.
@ -191,7 +191,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
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];
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
if (r_transp && transp) {
*r_transp = true;
@ -216,7 +216,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
case V3D_SHADING_VERTEX_COLOR: {
const bool transp = wpd->shading.xray_alpha < 1.0f;
DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp;
DRWShadingGroup *grp = wpd->prepass[transp][infront][datatype].vcol_shgrp;
return grp;
}
default: {
@ -231,7 +231,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type);
const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f;
DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp;
DRWShadingGroup *grp = wpd->prepass[transp][infront][datatype].common_shgrp;
if (resource_changed) {
grp = DRW_shgroup_create_sub(grp);
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
@ -251,7 +251,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Image *ima,
ImageUser *iuser,
eGPUSamplerState sampler,
bool hair)
eWORKBENCH_DataType datatype)
{
GPUTexture *tex = NULL, *tex_tile_data = NULL;
@ -275,7 +275,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
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];
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
DRWShadingGroup **grp_tex = NULL;
/* A hashmap stores image shgroups to pack all similar drawcalls together. */

View File

@ -59,10 +59,10 @@ void workbench_opaque_engine_init(WORKBENCH_Data *data)
});
}
void workbench_opaque_cache_init(WORKBENCH_Data *data)
void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
{
WORKBENCH_PassList *psl = data->psl;
WORKBENCH_PrivateData *wpd = data->stl->wpd;
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
struct GPUShader *sh;
DRWShadingGroup *grp;
@ -84,31 +84,31 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data)
pass = psl->opaque_ps;
}
for (int hair = 0; hair < 2; hair++) {
wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
for (eWORKBENCH_DataType data = 0; data < WORKBENCH_DATATYPE_MAX; data++) {
wpd->prepass[opaque][infront][data].material_hash = BLI_ghash_ptr_new(__func__);
sh = workbench_shader_opaque_get(wpd, hair);
sh = workbench_shader_opaque_get(wpd, data);
wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[opaque][infront][data].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);
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[opaque][infront][data].vcol_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", 0); /* Default material. (uses vcol) */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, hair, false);
sh = workbench_shader_opaque_image_get(wpd, data, false);
wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[opaque][infront][data].image_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", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, hair, true);
sh = workbench_shader_opaque_image_get(wpd, data, true);
wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[opaque][infront][data].image_tiled_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", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);

View File

@ -71,6 +71,14 @@ struct RenderEngine;
struct RenderLayer;
struct rcti;
typedef enum eWORKBENCH_DataType {
WORKBENCH_DATATYPE_MESH = 0,
WORKBENCH_DATATYPE_HAIR,
WORKBENCH_DATATYPE_POINTCLOUD,
WORKBENCH_DATATYPE_MAX,
} eWORKBENCH_DataType;
typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *opaque_fb;
struct GPUFrameBuffer *opaque_infront_fb;
@ -292,8 +300,8 @@ typedef struct WORKBENCH_PrivateData {
/** Object IDs buffer for curvature & outline. */
struct GPUTexture *object_id_tx;
/** Pre-pass information for each draw types [transparent][infront][hair]. */
WORKBENCH_Prepass prepass[2][2][2];
/** Pre-pass information for each draw types [transparent][infront][datatype]. */
WORKBENCH_Prepass prepass[2][2][WORKBENCH_DATATYPE_MAX];
/* Materials */
/** Copy of vldata->material_ubo for faster access. */
@ -392,14 +400,16 @@ 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_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType data);
GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
eWORKBENCH_DataType data,
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_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType data);
GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
bool hair,
eWORKBENCH_DataType data,
bool tiled);
GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd);
@ -454,7 +464,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
int mat_nr,
eV3DShadingColorType color_type,
bool hair,
eWORKBENCH_DataType datatype,
bool *r_transp);
DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Object *ob,
@ -462,17 +472,20 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
Image *ima,
ImageUser *iuser,
eGPUSamplerState sampler,
bool hair);
eWORKBENCH_DataType datatype);
#define WORKBENCH_OBJECT_DATATYPE(ob) \
((ob->type == OB_POINTCLOUD) ? WORKBENCH_DATATYPE_POINTCLOUD : WORKBENCH_DATATYPE_MESH)
#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)
workbench_material_setup_ex(wpd, ob, mat_nr, color_type, WORKBENCH_OBJECT_DATATYPE(ob), 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)
workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_OBJECT_DATATYPE(ob))
#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \
workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0)
workbench_material_setup_ex(wpd, ob, mat_nr, color_type, WORKBENCH_DATATYPE_HAIR, 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_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR)
/* workbench_data.c */
void workbench_private_data_init(WORKBENCH_PrivateData *wpd);

View File

@ -29,11 +29,13 @@
#include "workbench_private.h"
extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_smaa_lib_glsl[];
extern char datatoc_workbench_prepass_vert_glsl[];
extern char datatoc_workbench_prepass_hair_vert_glsl[];
extern char datatoc_workbench_prepass_pointcloud_vert_glsl[];
extern char datatoc_workbench_prepass_frag_glsl[];
extern char datatoc_workbench_effect_cavity_frag_glsl[];
@ -74,7 +76,6 @@ extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
/* Maximum number of variations. */
#define MAX_LIGHTING 3
#define MAX_COLOR 3
#define MAX_GEOM 2
enum {
VOLUME_SH_SLICE = 0,
@ -85,8 +86,9 @@ enum {
#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
static struct {
struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR];
struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR];
struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][MAX_COLOR];
struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX]
[MAX_LIGHTING][MAX_COLOR];
struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
struct GPUShader *oit_resolve_sh;
@ -119,6 +121,7 @@ void workbench_shader_library_ensure(void)
/* NOTE: Theses needs to be ordered by dependencies. */
DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_pointcloud_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
@ -177,15 +180,18 @@ static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textur
return (textured) ? (tiled ? 2 : 1) : 0;
}
static GPUShader *workbench_shader_get_ex(
WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled)
static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd,
bool transp,
eWORKBENCH_DataType datatype,
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];
(transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][color] :
&e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][color];
if (*shader == NULL) {
char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
@ -194,8 +200,11 @@ static GPUShader *workbench_shader_get_ex(
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_file = (datatype == WORKBENCH_DATATYPE_HAIR) ?
datatoc_workbench_prepass_hair_vert_glsl :
((datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
datatoc_workbench_prepass_pointcloud_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];
@ -207,6 +216,10 @@ static GPUShader *workbench_shader_get_ex(
defines,
transp ? "#define TRANSPARENT_MATERIAL\n" :
"#define OPAQUE_MATERIAL\n",
(datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
"#define UNIFORM_RESOURCE_ID\n"
"#define INSTANCED_ATTR\n" :
NULL,
NULL},
});
@ -217,26 +230,29 @@ static GPUShader *workbench_shader_get_ex(
return *shader;
}
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair)
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype)
{
return workbench_shader_get_ex(wpd, false, hair, false, false);
return workbench_shader_get_ex(wpd, false, datatype, false, false);
}
GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled)
GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
eWORKBENCH_DataType datatype,
bool tiled)
{
return workbench_shader_get_ex(wpd, false, hair, true, tiled);
return workbench_shader_get_ex(wpd, false, datatype, true, tiled);
}
GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair)
GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd,
eWORKBENCH_DataType datatype)
{
return workbench_shader_get_ex(wpd, true, hair, false, false);
return workbench_shader_get_ex(wpd, true, datatype, false, false);
}
GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
bool hair,
eWORKBENCH_DataType datatype,
bool tiled)
{
return workbench_shader_get_ex(wpd, true, hair, true, tiled);
return workbench_shader_get_ex(wpd, true, datatype, true, tiled);
}
GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)

View File

@ -83,10 +83,10 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
}
}
void workbench_transparent_cache_init(WORKBENCH_Data *data)
void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
{
WORKBENCH_PassList *psl = data->psl;
WORKBENCH_PrivateData *wpd = data->stl->wpd;
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
struct GPUShader *sh;
DRWShadingGroup *grp;
@ -105,30 +105,30 @@ void workbench_transparent_cache_init(WORKBENCH_Data *data)
pass = psl->transp_accum_ps;
}
for (int hair = 0; hair < 2; hair++) {
wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__);
for (eWORKBENCH_DataType data = 0; data < WORKBENCH_DATATYPE_MAX; data++) {
wpd->prepass[transp][infront][data].material_hash = BLI_ghash_ptr_new(__func__);
sh = workbench_shader_transparent_get(wpd, hair);
sh = workbench_shader_transparent_get(wpd, data);
wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[transp][infront][data].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);
wpd->prepass[transp][infront][data].vcol_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", 0); /* Default material. (uses vcol) */
sh = workbench_shader_transparent_image_get(wpd, hair, false);
sh = workbench_shader_transparent_image_get(wpd, data, false);
wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[transp][infront][data].image_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", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
sh = workbench_shader_transparent_image_get(wpd, hair, true);
sh = workbench_shader_transparent_image_get(wpd, data, true);
wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
wpd->prepass[transp][infront][data].image_tiled_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", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);

View File

@ -829,7 +829,7 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob)
case OB_HAIR:
return NULL;
case OB_POINTCLOUD:
return NULL;
return DRW_pointcloud_batch_cache_get_dots(ob);
case OB_VOLUME:
return DRW_cache_volume_face_wireframe_get(ob);
case OB_GPENCIL: {
@ -880,7 +880,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
case OB_HAIR:
return NULL;
case OB_POINTCLOUD:
return NULL;
return DRW_cache_pointcloud_surface_get(ob);
case OB_VOLUME:
return NULL;
default:
@ -958,7 +958,7 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob,
case OB_HAIR:
return NULL;
case OB_POINTCLOUD:
return NULL;
return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
case OB_VOLUME:
return NULL;
default:
@ -3289,9 +3289,16 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob)
GPUBatch *DRW_cache_pointcloud_get_dots(Object *object)
{
BLI_assert(object->type == OB_POINTCLOUD);
return DRW_pointcloud_batch_cache_get_dots(object);
}
GPUBatch *DRW_cache_pointcloud_surface_get(Object *object)
{
BLI_assert(object->type == OB_POINTCLOUD);
return DRW_pointcloud_batch_cache_get_surface(object);
}
/* -------------------------------------------------------------------- */
/** \name Volume
* \{ */

View File

@ -215,6 +215,7 @@ struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is
/* PointCloud */
struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj);
struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj);
/* Volume */
typedef struct DRWVolumeGrid {

View File

@ -144,6 +144,10 @@ int DRW_hair_material_count_get(struct Hair *hair);
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob);
struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
/* Volume */
int DRW_volume_material_count_get(struct Volume *volume);

View File

@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_object_types.h"
@ -45,11 +46,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud);
/* PointCloud GPUBatch Cache */
typedef struct PointCloudBatchCache {
GPUVertBuf *pos;
GPUBatch *batch;
GPUVertBuf *pos; /* Position and radius. */
GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */
GPUIndexBuf *geom_indices;
GPUBatch *dots;
GPUBatch *surface;
GPUBatch **surface_per_mat;
/* settings to determine if cache is invalid */
bool is_dirty;
int mat_len;
} PointCloudBatchCache;
/* GPUBatch cache management. */
@ -57,7 +65,14 @@ typedef struct PointCloudBatchCache {
static bool pointcloud_batch_cache_valid(PointCloud *pointcloud)
{
PointCloudBatchCache *cache = pointcloud->batch_cache;
return (cache && cache->is_dirty == false);
if (cache == NULL) {
return false;
}
if (cache->mat_len != DRW_pointcloud_material_count_get(pointcloud)) {
return false;
}
return cache->is_dirty == false;
}
static void pointcloud_batch_cache_init(PointCloud *pointcloud)
@ -71,6 +86,10 @@ static void pointcloud_batch_cache_init(PointCloud *pointcloud)
memset(cache, 0, sizeof(*cache));
}
cache->mat_len = DRW_pointcloud_material_count_get(pointcloud);
cache->surface_per_mat = MEM_callocN(sizeof(GPUBatch *) * cache->mat_len,
"pointcloud suface_per_mat");
cache->is_dirty = false;
}
@ -109,8 +128,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud)
return;
}
GPU_BATCH_DISCARD_SAFE(cache->batch);
GPU_BATCH_DISCARD_SAFE(cache->dots);
GPU_BATCH_DISCARD_SAFE(cache->surface);
GPU_VERTBUF_DISCARD_SAFE(cache->pos);
GPU_VERTBUF_DISCARD_SAFE(cache->geom);
GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices);
if (cache->surface_per_mat) {
for (int i = 0; i < cache->mat_len; i++) {
GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
MEM_SAFE_FREE(cache->surface_per_mat);
}
void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud)
@ -126,35 +155,83 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
}
PointCloud *pointcloud = ob->data;
const bool has_radius = pointcloud->radius != NULL;
static GPUVertFormat format = {0};
static uint pos_id;
static uint radius_id;
static uint pos;
if (format.attr_len == 0) {
/* initialize vertex format */
pos_id = GPU_vertformat_attr_add(&format, "pointcloud_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
radius_id = GPU_vertformat_attr_add(
&format, "pointcloud_radius", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
/* From the opengl wiki:
* Note that size does not have to exactly match the size used by the vertex shader. If the
* vertex shader has fewer components than the attribute provides, then the extras are ignored.
* If the vertex shader has more components than the array provides, the extras are given
* values from the vector (0, 0, 0, 1) for the missing XYZW components.
*/
int comp_len = has_radius ? 4 : 3;
pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, comp_len, GPU_FETCH_FLOAT);
}
GPU_VERTBUF_DISCARD_SAFE(cache->pos);
cache->pos = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint);
GPU_vertbuf_attr_fill(cache->pos, pos_id, pointcloud->co);
if (pointcloud->radius) {
GPU_vertbuf_attr_fill(cache->pos, radius_id, pointcloud->radius);
}
else if (pointcloud->totpoint) {
/* TODO: optimize for constant radius by not including in vertex buffer at all? */
float *radius = MEM_malloc_arrayN(pointcloud->totpoint, sizeof(float), __func__);
if (has_radius) {
float(*vbo_data)[4] = (float(*)[4])cache->pos->data;
for (int i = 0; i < pointcloud->totpoint; i++) {
/* TODO: add default radius to PointCloud data structure. */
radius[i] = 0.01f;
copy_v3_v3(vbo_data[i], pointcloud->co[i]);
/* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */
vbo_data[i][3] = pointcloud->radius[i] * 100.0f;
}
GPU_vertbuf_attr_fill(cache->pos, radius_id, radius);
MEM_freeN(radius);
}
else {
GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co);
}
}
static const float half_octahedron_normals[5][3] = {
{0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
};
static const uint half_octahedron_tris[4][3] = {
{0, 1, 2},
{0, 2, 3},
{0, 3, 4},
{0, 4, 1},
};
static void pointcloud_batch_cache_ensure_geom(Object *UNUSED(ob), PointCloudBatchCache *cache)
{
if (cache->geom != NULL) {
return;
}
static GPUVertFormat format = {0};
static uint pos;
if (format.attr_len == 0) {
/* initialize vertex format */
pos = GPU_vertformat_attr_add(&format, "pos_inst", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "nor");
}
cache->geom = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache->geom, ARRAY_SIZE(half_octahedron_normals));
GPU_vertbuf_attr_fill(cache->geom, pos, half_octahedron_normals);
GPUIndexBufBuilder builder;
GPU_indexbuf_init(&builder,
GPU_PRIM_TRIS,
ARRAY_SIZE(half_octahedron_tris),
ARRAY_SIZE(half_octahedron_normals));
for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) {
GPU_indexbuf_add_tri_verts(&builder, UNPACK3(half_octahedron_tris[i]));
}
cache->geom_indices = GPU_indexbuf_build(&builder);
}
GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob)
@ -162,12 +239,47 @@ GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob)
PointCloud *pointcloud = ob->data;
PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud);
if (cache->batch == NULL) {
if (cache->dots == NULL) {
pointcloud_batch_cache_ensure_pos(ob, cache);
cache->batch = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL);
cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL);
}
return cache->batch;
return cache->dots;
}
GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob)
{
PointCloud *pointcloud = ob->data;
PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud);
if (cache->surface == NULL) {
pointcloud_batch_cache_ensure_pos(ob, cache);
pointcloud_batch_cache_ensure_geom(ob, cache);
cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false);
}
return cache->surface;
}
GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob,
struct GPUMaterial **UNUSED(gpumat_array),
uint gpumat_array_len)
{
PointCloud *pointcloud = ob->data;
PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud);
BLI_assert(cache->mat_len == gpumat_array_len);
if (cache->surface_per_mat[0] == NULL) {
pointcloud_batch_cache_ensure_pos(ob, cache);
pointcloud_batch_cache_ensure_geom(ob, cache);
cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false);
}
return cache->surface_per_mat;
}
int DRW_pointcloud_material_count_get(PointCloud *pointcloud)

View File

@ -793,10 +793,10 @@ void DRW_shgroup_call_range(
drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
}
/* A count of 0 instance will use the default number of instance in the batch. */
void DRW_shgroup_call_instance_range(
DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
{
BLI_assert(i_ct > 0);
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);

View File

@ -0,0 +1,39 @@
/* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
in vec4 pos; /* Position and radius. */
/* ---- Instanced attribs ---- */
in vec3 pos_inst;
in vec3 nor;
mat3 pointcloud_get_facing_matrix(vec3 p)
{
mat3 facing_mat;
facing_mat[2] = normalize(ViewMatrixInverse[3].xyz - p);
facing_mat[1] = normalize(cross(ViewMatrixInverse[0].xyz, facing_mat[2]));
facing_mat[0] = cross(facing_mat[1], facing_mat[2]);
return facing_mat;
}
/* Return world position and normal. */
void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor)
{
vec3 p = point_object_to_world(pos.xyz);
mat3 facing_mat = pointcloud_get_facing_matrix(p);
float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0));
/* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */
radius *= 0.01;
outpos = p + (facing_mat * pos_inst) * radius;
outnor = facing_mat * nor;
}
vec3 pointcloud_get_pos(void)
{
vec3 outpos, outnor;
pointcloud_get_pos_and_nor(outpos, outnor);
return outpos;
}

View File

@ -175,6 +175,7 @@ uniform mat4 ModelMatrixInverse;
#define normal_object_to_world(n) (transpose(mat3(ModelMatrixInverse)) * n)
#define normal_world_to_object(n) (transpose(mat3(ModelMatrix)) * n)
#define normal_world_to_view(n) (mat3(ViewMatrix) * n)
#define normal_view_to_world(n) (mat3(ViewMatrixInverse) * n)
#define point_object_to_ndc(p) (ViewProjectionMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0))
#define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz)