Implement hair drawing with Draw Manager in Clay engine

Part of T51378
This commit is contained in:
Luca Rood 2017-05-09 16:23:47 +02:00
parent bd31b1f182
commit 0eb32ab228
Notes: blender-bot 2023-02-14 02:41:05 +01:00
Referenced by commit 3af8f52752, Fix crash when changing Clay "Edge Strength"
18 changed files with 715 additions and 3 deletions

View File

@ -68,6 +68,16 @@ class COLLECTION_PT_clay_settings(CollectionButtonsPanel, Panel):
col.template_override_property(collection_props, scene_props, "ssao_factor_edge")
col.template_override_property(collection_props, scene_props, "ssao_distance")
col.template_override_property(collection_props, scene_props, "ssao_attenuation")
col.template_override_property(collection_props, scene_props, "world_intensity")
col.separator()
col.label("Hair Settings:")
col.template_override_property(collection_props, scene_props, "diffuse_intensity")
col.template_override_property(collection_props, scene_props, "specular_intensity")
col.template_override_property(collection_props, scene_props, "specular_hardness")
col.template_override_property(collection_props, scene_props, "color_randomicity")
col.template_override_property(collection_props, scene_props, "hair_diffuse_color")
col.template_override_property(collection_props, scene_props, "hair_specular_color")
class COLLECTION_PT_object_mode_settings(CollectionButtonsPanel, Panel):

View File

@ -615,6 +615,16 @@ class RENDER_PT_clay_collection_settings(RenderButtonsPanel, Panel):
col.prop(props, "ssao_distance")
col.prop(props, "ssao_attenuation")
col.separator()
col.label("Hair Settings:")
col.prop(props, "world_intensity")
col.prop(props, "diffuse_intensity")
col.prop(props, "specular_intensity")
col.prop(props, "specular_hardness")
col.prop(props, "color_randomicity")
col.prop(props, "hair_diffuse_color")
col.prop(props, "hair_specular_color")
class RENDER_PT_eevee_poststack_settings(RenderButtonsPanel, Panel):
bl_label = "Post Process Stack"
COMPAT_ENGINES = {'BLENDER_EEVEE'}

View File

@ -479,3 +479,10 @@ void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
struct ParticleSystem *psys);
#endif
/* Draw Cache */
enum {
BKE_PARTICLE_BATCH_DIRTY_ALL = 0,
};
void BKE_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode);
void BKE_particle_batch_cache_free(struct ParticleSystem *psys);

View File

@ -4305,3 +4305,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_EDITED;
}
}
/* Draw Engine */
void (*BKE_particle_batch_cache_dirty_cb)(ParticleSystem *psys, int mode) = NULL;
void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
void BKE_particle_batch_cache_dirty(ParticleSystem *psys, int mode)
{
if (psys->batch_cache) {
BKE_particle_batch_cache_dirty_cb(psys, mode);
}
}
void BKE_particle_batch_cache_free(ParticleSystem *psys)
{
if (psys->batch_cache) {
BKE_particle_batch_cache_free_cb(psys);
}
}

View File

@ -4321,6 +4321,8 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, cons
/* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
if (psys->renderdata==0)
invert_m4_m4(psys->imat, ob->obmat);
BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */

View File

@ -4372,6 +4372,8 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->tree = NULL;
psys->bvhtree = NULL;
psys->batch_cache = NULL;
}
return;
}

View File

@ -59,6 +59,7 @@ set(SRC
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_particles.c
intern/draw_common.c
intern/draw_manager.c
intern/draw_manager_text.c
@ -108,6 +109,8 @@ data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC)
data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC)
data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC)
data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC)
data_to_c_simple(engines/clay/shaders/particle_vert.glsl SRC)
data_to_c_simple(engines/clay/shaders/particle_strand_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)

View File

@ -21,9 +21,12 @@
#include "DRW_render.h"
#include "DNA_particle_types.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_particle.h"
#include "BLI_dynstr.h"
#include "BLI_rand.h"
@ -43,6 +46,8 @@
extern char datatoc_clay_frag_glsl[];
extern char datatoc_clay_vert_glsl[];
extern char datatoc_ssao_alchemy_glsl[];
extern char datatoc_particle_vert_glsl[];
extern char datatoc_particle_strand_frag_glsl[];
/* *********** LISTS *********** */
@ -59,24 +64,45 @@ typedef struct CLAY_UBO_Material {
} CLAY_UBO_Material; /* 48 bytes */
BLI_STATIC_ASSERT_ALIGN(CLAY_UBO_Material, 16);
typedef struct CLAY_HAIR_UBO_Material {
float hair_world;
float hair_diffuse;
float hair_specular;
float hair_hardness;
float hair_randomicity;
float pad1[3];
float hair_diffuse_color[3];
float pad2;
float hair_specular_color[3];
float pad3;
} CLAY_HAIR_UBO_Material; /* 48 bytes */
#define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */
typedef struct CLAY_UBO_Storage {
CLAY_UBO_Material materials[MAX_CLAY_MAT];
} CLAY_UBO_Storage;
typedef struct CLAY_HAIR_UBO_Storage {
CLAY_HAIR_UBO_Material materials[MAX_CLAY_MAT];
} CLAY_HAIR_UBO_Storage;
/* GPUViewport.storage
* Is freed everytime the viewport engine changes */
typedef struct CLAY_Storage {
/* Materials Parameter UBO */
CLAY_UBO_Storage mat_storage;
CLAY_HAIR_UBO_Storage hair_mat_storage;
int ubo_current_id;
int hair_ubo_current_id;
DRWShadingGroup *shgrps[MAX_CLAY_MAT];
DRWShadingGroup *hair_shgrps[MAX_CLAY_MAT];
} CLAY_Storage;
typedef struct CLAY_StorageList {
struct CLAY_Storage *storage;
struct GPUUniformBuffer *mat_ubo;
struct GPUUniformBuffer *hair_mat_ubo;
struct CLAY_PrivateData *g_data;
} CLAY_StorageList;
@ -99,6 +125,7 @@ typedef struct CLAY_PassList {
struct DRWPass *depth_pass;
struct DRWPass *depth_pass_cull;
struct DRWPass *clay_pass;
struct DRWPass *hair_pass;
} CLAY_PassList;
typedef struct CLAY_Data {
@ -116,6 +143,7 @@ static struct {
struct GPUShader *depth_sh;
/* Shading Pass */
struct GPUShader *clay_sh;
struct GPUShader *hair_sh;
/* Matcap textures */
struct GPUTexture *matcap_array;
@ -129,8 +157,12 @@ static struct {
struct GPUTexture *jitter_tx;
struct GPUTexture *sampling_tx;
/* hair */
float hair_light[3];
/* Just a serie of int from 0 to MAX_CLAY_MAT-1 */
int ubo_mat_idxs[MAX_CLAY_MAT];
int hair_ubo_mat_idxs[MAX_CLAY_MAT];
} e_data = {NULL}; /* Engine data */
typedef struct CLAY_PrivateData {
@ -140,6 +172,7 @@ typedef struct CLAY_PrivateData {
DRWShadingGroup *depth_shgrp_cull;
DRWShadingGroup *depth_shgrp_cull_select;
DRWShadingGroup *depth_shgrp_cull_active;
DRWShadingGroup *hair;
} CLAY_PrivateData; /* Transient data */
/* Functions */
@ -324,6 +357,10 @@ static void CLAY_engine_init(void *vedata)
MEM_freeN(matcap_with_ao);
}
if (!e_data.hair_sh) {
e_data.hair_sh = DRW_shader_create(datatoc_particle_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, "#define MAX_MATERIAL 512\n");
}
if (!stl->storage) {
stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage");
}
@ -332,6 +369,10 @@ static void CLAY_engine_init(void *vedata)
stl->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL);
}
if (!stl->hair_mat_ubo) {
stl->hair_mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_HAIR_UBO_Storage), NULL);
}
if (e_data.ubo_mat_idxs[1] == 0) {
/* Just int to have pointers to them */
for (int i = 0; i < MAX_CLAY_MAT; ++i) {
@ -413,6 +454,13 @@ static void CLAY_engine_init(void *vedata)
e_data.cached_sample_num = ssao_samples;
}
}
/* hair setup */
{
e_data.hair_light[0] = 1.0f;
e_data.hair_light[1] = -0.5f;
e_data.hair_light[2] = -0.7f;
}
}
static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *vedata, DRWPass *pass, int *material_id)
@ -437,6 +485,16 @@ static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *vedata, DRWPass *pass, in
return grp;
}
static DRWShadingGroup *CLAY_hair_shgroup_create(DRWPass *pass, int *material_id)
{
DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass);
DRW_shgroup_uniform_vec3(grp, "light", e_data.hair_light, 1);
DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1);
return grp;
}
static int search_mat_to_ubo(
CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
float matcap_val, float ssao_distance, float ssao_factor_cavity,
@ -464,6 +522,36 @@ static int search_mat_to_ubo(
return -1;
}
static int search_hair_mat_to_ubo(CLAY_Storage *storage, float hair_world, float hair_diffuse, float hair_specular,
float hair_hardness, float hair_randomicity, const float *hair_diff_color,
const float *hair_spec_color)
{
/* For now just use a linear search and test all parameters */
/* TODO make a hash table */
for (int i = 0; i < storage->hair_ubo_current_id; ++i) {
CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[i];
if ((ubo->hair_world == hair_world) &&
(ubo->hair_diffuse == hair_diffuse) &&
(ubo->hair_specular == hair_specular) &&
(ubo->hair_hardness == hair_hardness) &&
(ubo->hair_randomicity == hair_randomicity) &&
(ubo->hair_diffuse_color[0] == hair_diff_color[0]) &&
(ubo->hair_diffuse_color[1] == hair_diff_color[1]) &&
(ubo->hair_diffuse_color[2] == hair_diff_color[2]) &&
(ubo->hair_diffuse_color[3] == hair_diff_color[3]) &&
(ubo->hair_specular_color[0] == hair_spec_color[0]) &&
(ubo->hair_specular_color[1] == hair_spec_color[1]) &&
(ubo->hair_specular_color[2] == hair_spec_color[2]) &&
(ubo->hair_specular_color[3] == hair_spec_color[3]))
{
return i;
}
}
return -1;
}
static int push_mat_to_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
float matcap_val, float ssao_distance, float ssao_factor_cavity,
float ssao_factor_edge, float ssao_attenuation, int matcap_icon)
@ -491,6 +579,32 @@ static int push_mat_to_ubo(CLAY_Storage *storage, float matcap_rot, float matcap
return id;
}
static int push_hair_mat_to_ubo(CLAY_Storage *storage, float hair_world, float hair_diffuse, float hair_specular,
float hair_hardness, float hair_randomicity, const float *hair_diff_color,
const float *hair_spec_color)
{
int id = storage->hair_ubo_current_id;
CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[id];
ubo->hair_world = hair_world;
ubo->hair_diffuse = hair_diffuse;
ubo->hair_specular = hair_specular;
ubo->hair_hardness = hair_hardness;
ubo->hair_randomicity = hair_randomicity;
ubo->hair_diffuse_color[0] = hair_diff_color[0];
ubo->hair_diffuse_color[1] = hair_diff_color[1];
ubo->hair_diffuse_color[2] = hair_diff_color[2];
ubo->hair_diffuse_color[3] = hair_diff_color[3];
ubo->hair_specular_color[0] = hair_spec_color[0];
ubo->hair_specular_color[1] = hair_spec_color[1];
ubo->hair_specular_color[2] = hair_spec_color[2];
ubo->hair_specular_color[3] = hair_spec_color[3];
storage->hair_ubo_current_id++;
return id;
}
static int mat_in_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue, float matcap_sat,
float matcap_val, float ssao_distance, float ssao_factor_cavity,
float ssao_factor_edge, float ssao_attenuation, int matcap_icon)
@ -510,6 +624,23 @@ static int mat_in_ubo(CLAY_Storage *storage, float matcap_rot, float matcap_hue,
return id;
}
static int hair_mat_in_ubo(CLAY_Storage *storage, float hair_world, float hair_diffuse, float hair_specular,
float hair_hardness, float hair_randomicity, const float *hair_diff_color,
const float *hair_spec_color)
{
/* Search material in UBO */
int id = search_hair_mat_to_ubo(storage, hair_world, hair_diffuse, hair_specular,
hair_hardness, hair_randomicity, hair_diff_color, hair_spec_color);
/* if not found create it */
if (id == -1) {
id = push_hair_mat_to_ubo(storage, hair_world, hair_diffuse, hair_specular,
hair_hardness, hair_randomicity, hair_diff_color, hair_spec_color);
}
return id;
}
static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
{
DRWShadingGroup **shgrps = stl->storage->shgrps;
@ -541,6 +672,34 @@ static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, CLA
return shgrps[id];
}
static DRWShadingGroup *CLAY_hair_shgrp_get(Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl)
{
DRWShadingGroup **hair_shgrps = stl->storage->hair_shgrps;
IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY);
/* Default Settings */
float hair_world = BKE_collection_engine_property_value_get_float(props, "world_intensity");
float hair_diffuse = BKE_collection_engine_property_value_get_float(props, "diffuse_intensity");
float hair_specular = BKE_collection_engine_property_value_get_float(props, "specular_intensity");
float hair_hardness = BKE_collection_engine_property_value_get_float(props, "specular_hardness");
float hair_randomicity = BKE_collection_engine_property_value_get_float(props, "color_randomicity");
const float *hair_diff_color = BKE_collection_engine_property_value_get_float_array(props, "hair_diffuse_color");
const float *hair_spec_color = BKE_collection_engine_property_value_get_float_array(props, "hair_specular_color");
int hair_id = hair_mat_in_ubo(stl->storage, hair_world, hair_diffuse, hair_specular,
hair_hardness, hair_randomicity, hair_diff_color, hair_spec_color);
if (hair_shgrps[hair_id] == NULL) {
hair_shgrps[hair_id] = CLAY_hair_shgroup_create(psl->hair_pass, &e_data.hair_ubo_mat_idxs[hair_id]);
/* if it's the first shgrp, pass bind the material UBO */
if (stl->storage->hair_ubo_current_id == 1) {
DRW_shgroup_uniform_block(hair_shgrps[0], "material_block", stl->hair_mat_ubo);
}
}
return hair_shgrps[hair_id];
}
static void CLAY_cache_init(void *vedata)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
@ -568,6 +727,13 @@ static void CLAY_cache_init(void *vedata)
stl->storage->ubo_current_id = 0;
memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
}
/* Hair Pass */
{
psl->hair_pass = DRW_pass_create("Hair Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
stl->storage->hair_ubo_current_id = 0;
memset(stl->storage->hair_shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT);
}
}
static void CLAY_cache_populate(void *vedata, Object *ob)
@ -575,7 +741,7 @@ static void CLAY_cache_populate(void *vedata, Object *ob)
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
DRWShadingGroup *clay_shgrp;
DRWShadingGroup *clay_shgrp, *hair_shgrp;
if (!DRW_object_is_renderable(ob))
return;
@ -592,6 +758,35 @@ static void CLAY_cache_populate(void *vedata, Object *ob)
clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl);
DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat);
}
if (ob->type == OB_MESH) {
for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys_check_enabled(ob, psys, false)) {
ParticleSettings *part = psys->part;
int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
draw_as = PART_DRAW_DOT;
}
switch (draw_as) {
case PART_DRAW_PATH:
geom = DRW_cache_particles_get_hair(psys);
break;
default:
geom = NULL;
break;
}
if (geom) {
static float mat[4][4];
unit_m4(mat);
hair_shgrp = CLAY_hair_shgrp_get(ob, stl, psl);
DRW_shgroup_call_add(hair_shgrp, geom, mat);
}
}
}
}
}
static void CLAY_cache_finish(void *vedata)
@ -599,6 +794,7 @@ static void CLAY_cache_finish(void *vedata)
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
DRW_uniformbuffer_update(stl->mat_ubo, &stl->storage->mat_storage);
DRW_uniformbuffer_update(stl->hair_mat_ubo, &stl->storage->hair_mat_storage);
}
static void CLAY_draw_scene(void *vedata)
@ -620,6 +816,7 @@ static void CLAY_draw_scene(void *vedata)
/* Pass 3 : Shading */
DRW_draw_pass(psl->clay_pass);
DRW_draw_pass(psl->hair_pass);
}
static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
@ -628,6 +825,9 @@ static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine),
props->type == IDP_GROUP &&
props->subtype == IDP_GROUP_SUB_ENGINE_RENDER);
static float default_hair_diffuse_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
static float default_hair_specular_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
BKE_collection_engine_property_add_int(props, "matcap_icon", ICON_MATCAP_01);
BKE_collection_engine_property_add_int(props, "type", CLAY_MATCAP_NONE);
BKE_collection_engine_property_add_float(props, "matcap_rotation", 0.0f);
@ -637,7 +837,13 @@ static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine),
BKE_collection_engine_property_add_float(props, "ssao_distance", 0.2f);
BKE_collection_engine_property_add_float(props, "ssao_attenuation", 1.0f);
BKE_collection_engine_property_add_float(props, "ssao_factor_cavity", 1.0f);
BKE_collection_engine_property_add_float(props, "ssao_factor_edge", 1.0f);
BKE_collection_engine_property_add_float(props, "world_intensity", 0.1f);
BKE_collection_engine_property_add_float(props, "diffuse_intensity", 0.2f);
BKE_collection_engine_property_add_float(props, "specular_intensity", 0.3f);
BKE_collection_engine_property_add_float(props, "specular_hardness", 4.0f);
BKE_collection_engine_property_add_float(props, "color_randomicity", 0.0f);
BKE_collection_engine_property_add_float_array(props, "hair_diffuse_color", default_hair_diffuse_color, 4);
BKE_collection_engine_property_add_float_array(props, "hair_specular_color", default_hair_specular_color, 4);
}
static void CLAY_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
@ -652,6 +858,7 @@ static void CLAY_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
static void CLAY_engine_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.clay_sh);
DRW_SHADER_FREE_SAFE(e_data.hair_sh);
DRW_TEXTURE_FREE_SAFE(e_data.matcap_array);
DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
DRW_TEXTURE_FREE_SAFE(e_data.sampling_tx);

View File

@ -0,0 +1,46 @@
uniform vec3 light;
/* Material Parameters packed in an UBO */
struct Material {
vec4 one;
vec4 two;
vec4 hair_diffuse_color;
vec4 hair_specular_color;
};
layout(std140) uniform material_block {
Material shader_param[MAX_MATERIAL];
};
uniform int mat_id;
#define world shader_param[mat_id].one.x
#define diffuse shader_param[mat_id].one.y
#define specular shader_param[mat_id].one.z
#define hardness shader_param[mat_id].one.w
#define randomicity shader_param[mat_id].two.x
#define diffColor shader_param[mat_id].hair_diffuse_color
#define specColor shader_param[mat_id].hair_specular_color
in vec3 normal;
in vec3 viewPosition;
flat in float colRand;
out vec4 fragColor;
void main()
{
vec3 normal = normalize(normal);
vec3 specVec = normalize(normalize(light) + normalize(viewPosition));
float specCos = dot(specVec, normal);
float diffCos = dot(normalize(light), normal);
float maxChan = max(max(diffColor.r, diffColor.g), diffColor.b);
float diff;
float spec;
diff = world; /* world */
diff += sqrt(1.0 - diffCos*diffCos) * diffuse; /* diffuse */
spec = pow(1.0 - abs(specCos), hardness) * specular; /* specular */
fragColor = (diffColor - (colRand * maxChan * randomicity)) * diff; /* add diffuse */
fragColor += specColor * spec; /* add specular */
fragColor = clamp(fragColor, 0.0, 1.0);
}

View File

@ -0,0 +1,34 @@
uniform mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ModelViewMatrix;
in vec3 pos;
in vec3 nor;
in int ind;
out vec3 normal;
out vec3 viewPosition;
flat out float colRand;
/* TODO: This function yields great distribution, but might be a bit inefficient because of the 4 trig ops.
* Something more efficient would be nice */
float rand(int seed)
{
vec4 nums = vec4(0.0);
nums.x = mod(tan(mod(float(seed + 1) * 238965.0, 342.0)), 1.0) + 0.01;
nums.y = mod(tan(mod(float(seed + 1) * 34435643.0, 756.0)), 1.0) + 0.01;
nums.z = mod(tan(mod(float(seed + 1) * 4356757.0, 456.0)), 1.0) + 0.01;
nums.w = mod(tan(mod(float(seed + 1) * 778679.0, 987.0)), 1.0) + 0.01;
float num = mod((nums.x / nums.y) + 1 - (nums.z / nums.w), 1.0);
num += 0.5;
return mod(num, 1.0);
}
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
normal = normalize(NormalMatrix * nor);
viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
colRand = rand(ind);
}

View File

@ -28,6 +28,7 @@
#include "DNA_mesh_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@ -1977,3 +1978,13 @@ Batch *DRW_cache_lattice_vert_overlay_get(Object *ob)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Particles
* \{ */
Batch *DRW_cache_particles_get_hair(ParticleSystem *psys)
{
return DRW_particles_batch_cache_get_hair(psys);
}

View File

@ -128,4 +128,7 @@ struct Batch *DRW_cache_lattice_verts_get(struct Object *ob);
struct Batch *DRW_cache_lattice_wire_get(struct Object *ob);
struct Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
struct Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys);
#endif /* __DRAW_CACHE_H__ */

View File

@ -29,6 +29,7 @@
struct Batch;
struct ListBase;
struct CurveCache;
struct ParticleSystem;
struct Curve;
struct Lattice;
@ -44,6 +45,9 @@ void DRW_mesh_batch_cache_free(struct Mesh *me);
void DRW_lattice_batch_cache_dirty(struct Lattice *lt, int mode);
void DRW_lattice_batch_cache_free(struct Lattice *lt);
void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode);
void DRW_particle_batch_cache_free(struct ParticleSystem *psys);
/* Curve */
struct Batch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache);
struct Batch *DRW_curve_batch_cache_get_normal_edge(
@ -85,4 +89,7 @@ struct Batch *DRW_mesh_batch_cache_get_overlay_loose_edges(struct Mesh *me);
struct Batch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me);
struct Batch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me);
/* Particles */
struct Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys);
#endif /* __DRAW_CACHE_IMPL_H__ */

View File

@ -0,0 +1,282 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* The Original Code is Copyright (C) 2017 by Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file draw_cache_impl_particles.c
* \ingroup draw
*
* \brief Particle API for render engines
*/
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
#include "DNA_particle_types.h"
#include "BKE_particle.h"
#include "GPU_batch.h"
#include "draw_cache_impl.h" /* own include */
static void particle_batch_cache_clear(ParticleSystem *psys);
/* ---------------------------------------------------------------------- */
/* Particle Batch Cache */
typedef struct ParticleBatchCache {
VertexBuffer *pos;
ElementList *segments;
Batch *hairs;
int segment_count;
int point_count;
/* settings to determine if cache is invalid */
bool is_dirty;
} ParticleBatchCache;
/* Batch cache management. */
static bool particle_batch_cache_valid(ParticleSystem *psys)
{
ParticleBatchCache *cache = psys->batch_cache;
if (cache == NULL) {
return false;
}
if (cache->is_dirty == false) {
return true;
}
else {
return false;
}
return true;
}
static void particle_batch_cache_init(ParticleSystem *psys)
{
ParticleBatchCache *cache = psys->batch_cache;
if (!cache) {
cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__);
}
else {
memset(cache, 0, sizeof(*cache));
}
cache->is_dirty = false;
}
static ParticleBatchCache *particle_batch_cache_get(ParticleSystem *psys)
{
if (!particle_batch_cache_valid(psys)) {
particle_batch_cache_clear(psys);
particle_batch_cache_init(psys);
}
return psys->batch_cache;
}
void DRW_particle_batch_cache_dirty(ParticleSystem *psys, int mode)
{
ParticleBatchCache *cache = psys->batch_cache;
if (cache == NULL) {
return;
}
switch (mode) {
case BKE_PARTICLE_BATCH_DIRTY_ALL:
cache->is_dirty = true;
break;
default:
BLI_assert(0);
}
}
static void particle_batch_cache_clear(ParticleSystem *psys)
{
ParticleBatchCache *cache = psys->batch_cache;
if (!cache) {
return;
}
BATCH_DISCARD_SAFE(cache->hairs);
VERTEXBUFFER_DISCARD_SAFE(cache->pos);
ELEMENTLIST_DISCARD_SAFE(cache->segments);
}
void DRW_particle_batch_cache_free(ParticleSystem *psys)
{
particle_batch_cache_clear(psys);
MEM_SAFE_FREE(psys->batch_cache);
}
static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache)
{
if (cache->pos == NULL || cache->segments == NULL) {
cache->segment_count = 0;
cache->point_count = 0;
if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
for (int i = 0; i < psys->totpart; i++) {
ParticleCacheKey *path = psys->pathcache[i];
if (path->segments) {
cache->segment_count += path->segments;
cache->point_count += path->segments + 1;
}
}
}
if (psys->childcache) {
int child_count = psys->totchild * psys->part->disp / 100;
for (int i = 0; i < child_count; i++) {
ParticleCacheKey *path = psys->childcache[i];
if (path->segments) {
cache->segment_count += path->segments;
cache->point_count += path->segments + 1;
}
}
}
}
}
/* Batch cache usage. */
static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ParticleBatchCache *cache)
{
if (cache->pos == NULL || cache->segments == NULL) {
static VertexFormat format = { 0 };
static unsigned pos_id, nor_id, ind_id;
int curr_point = 0;
VERTEXBUFFER_DISCARD_SAFE(cache->pos);
ELEMENTLIST_DISCARD_SAFE(cache->segments);
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
nor_id = VertexFormat_add_attrib(&format, "nor", COMP_F32, 3, KEEP_FLOAT);
ind_id = VertexFormat_add_attrib(&format, "ind", COMP_I32, 1, KEEP_INT);
}
cache->pos = VertexBuffer_create_with_format(&format);
VertexBuffer_allocate_data(cache->pos, cache->point_count);
ElementListBuilder elb;
ElementListBuilder_init(&elb, PRIM_LINES, cache->segment_count, cache->point_count);
if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
for (int i = 0; i < psys->totpart; i++) {
ParticleCacheKey *path = psys->pathcache[i];
if (path->segments) {
float tangent[3];
for (int j = 0; j < path->segments; j++) {
if (j == 0) {
sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
}
else {
sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
}
VertexBuffer_set_attrib(cache->pos, pos_id, curr_point, path[j].co);
VertexBuffer_set_attrib(cache->pos, nor_id, curr_point, tangent);
VertexBuffer_set_attrib(cache->pos, ind_id, curr_point, &i);
add_line_vertices(&elb, curr_point, curr_point + 1);
curr_point++;
}
sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
VertexBuffer_set_attrib(cache->pos, pos_id, curr_point, path[path->segments].co);
VertexBuffer_set_attrib(cache->pos, nor_id, curr_point, tangent);
VertexBuffer_set_attrib(cache->pos, ind_id, curr_point, &i);
curr_point++;
}
}
}
if (psys->childcache) {
int child_count = psys->totchild * psys->part->disp / 100;
for (int i = 0, x = psys->totpart; i < child_count; i++, x++) {
ParticleCacheKey *path = psys->childcache[i];
float tangent[3];
if (path->segments) {
for (int j = 0; j < path->segments; j++) {
if (j == 0) {
sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
}
else {
sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
}
VertexBuffer_set_attrib(cache->pos, pos_id, curr_point, path[j].co);
VertexBuffer_set_attrib(cache->pos, nor_id, curr_point, tangent);
VertexBuffer_set_attrib(cache->pos, ind_id, curr_point, &x);
add_line_vertices(&elb, curr_point, curr_point + 1);
curr_point++;
}
sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
VertexBuffer_set_attrib(cache->pos, pos_id, curr_point, path[path->segments].co);
VertexBuffer_set_attrib(cache->pos, nor_id, curr_point, tangent);
VertexBuffer_set_attrib(cache->pos, ind_id, curr_point, &x);
curr_point++;
}
}
}
cache->segments = ElementList_build(&elb);
}
}
Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys)
{
ParticleBatchCache *cache = particle_batch_cache_get(psys);
if (cache->hairs == NULL) {
ensure_seg_pt_count(psys, cache);
particle_batch_cache_ensure_pos_and_seg(psys, cache);
cache->hairs = Batch_create(PRIM_LINES, cache->pos, cache->segments);
}
return cache->hairs;
}

View File

@ -3100,6 +3100,9 @@ void DRW_engines_register(void)
/* BKE: lattice.c */
extern void *BKE_lattice_batch_cache_dirty_cb;
extern void *BKE_lattice_batch_cache_free_cb;
/* BKE: particle.c */
extern void *BKE_particle_batch_cache_dirty_cb;
extern void *BKE_particle_batch_cache_free_cb;
BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty;
BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free;
@ -3109,6 +3112,9 @@ void DRW_engines_register(void)
BKE_lattice_batch_cache_dirty_cb = DRW_lattice_batch_cache_dirty;
BKE_lattice_batch_cache_free_cb = DRW_lattice_batch_cache_free;
BKE_particle_batch_cache_dirty_cb = DRW_particle_batch_cache_dirty;
BKE_particle_batch_cache_free_cb = DRW_particle_batch_cache_free;
}
}

View File

@ -31,6 +31,7 @@
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_force.h"
#include "DNA_particle_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
@ -178,7 +179,6 @@ typedef struct OBJECT_PrivateData{
DRWShadingGroup *wire_select;
DRWShadingGroup *wire_select_group;
DRWShadingGroup *wire_transform;
} OBJECT_PrivateData; /* Transient data */
static struct {

View File

@ -324,6 +324,8 @@ typedef struct ParticleSystem {
float dt_frac; /* current time step, as a fraction of a frame */
float _pad; /* spare capacity */
void *batch_cache;
} ParticleSystem;
typedef enum eParticleDrawFlag {

View File

@ -2519,6 +2519,9 @@ static void rna_LayerEngineSettings_##_ENGINE_##_##_NAME_##_set(PointerRNA *ptr,
#define RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(_NAME_) \
RNA_LAYER_ENGINE_GET_SET(float, Clay, COLLECTION_MODE_NONE, _NAME_)
#define RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT_ARRAY(_NAME_, _LEN_) \
RNA_LAYER_ENGINE_GET_SET_ARRAY(float, Clay, COLLECTION_MODE_NONE, _NAME_, _LEN_)
#define RNA_LAYER_ENGINE_CLAY_GET_SET_INT(_NAME_) \
RNA_LAYER_ENGINE_GET_SET(int, Clay, COLLECTION_MODE_NONE, _NAME_)
@ -2575,6 +2578,13 @@ RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_cavity)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_factor_edge)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_distance)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(ssao_attenuation)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(world_intensity)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(diffuse_intensity)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(specular_intensity)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(specular_hardness)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT(color_randomicity)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT_ARRAY(hair_diffuse_color, 4)
RNA_LAYER_ENGINE_CLAY_GET_SET_FLOAT_ARRAY(hair_specular_color, 4)
#endif /* WITH_CLAY_ENGINE */
/* eevee engine */
@ -6363,6 +6373,57 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "world_intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_world_intensity_get", "rna_LayerEngineSettings_Clay_world_intensity_set", NULL);
RNA_def_property_ui_text(prop, "Hair World Light", "World lighting intensity for hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_diffuse_intensity_get", "rna_LayerEngineSettings_Clay_diffuse_intensity_set", NULL);
RNA_def_property_ui_text(prop, "Hair Diffuse", "Diffuse lighting intensity for hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_specular_intensity_get", "rna_LayerEngineSettings_Clay_specular_intensity_set", NULL);
RNA_def_property_ui_text(prop, "Hair Specular", "Specular lighting intensity for hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "specular_hardness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_specular_hardness_get", "rna_LayerEngineSettings_Clay_specular_hardness_set", NULL);
RNA_def_property_ui_text(prop, "Hair Specular Hardness", "Specular hardness for hair");
RNA_def_property_range(prop, 0.0f, 1000.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "color_randomicity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_color_randomicity_get", "rna_LayerEngineSettings_Clay_color_randomicity_set", NULL);
RNA_def_property_ui_text(prop, "Hair Color Randomicity", "Color randomicity for hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "hair_diffuse_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_hair_diffuse_color_get",
"rna_LayerEngineSettings_Clay_hair_diffuse_color_set", NULL);
RNA_def_property_ui_text(prop, "Hair Diffuse Color", "Diffuse component of hair shading color");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "hair_specular_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_hair_specular_color_get",
"rna_LayerEngineSettings_Clay_hair_specular_color_set", NULL);
RNA_def_property_ui_text(prop, "Hair Specular Color", "Specular component of hair shading color");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
RNA_define_verify_sdna(1); /* not in sdna */
}
#endif /* WITH_CLAY_ENGINE */