Hair UV implementation for Eevee

This implements UV support for Eevee hair, enabling the usage of
textures.
This commit is contained in:
Luca Rood 2017-06-22 19:19:55 +02:00
parent 6f0b80425b
commit cbbfacdac0
6 changed files with 245 additions and 66 deletions

View File

@ -828,7 +828,7 @@ static void CLAY_cache_populate(void *vedata, Object *ob)
unit_m4(mat);
if (draw_as == PART_DRAW_PATH) {
geom = DRW_cache_particles_get_hair(psys);
geom = DRW_cache_particles_get_hair(psys, NULL);
hair_shgrp = CLAY_hair_shgrp_get(ob, stl, psl);
DRW_shgroup_call_add(hair_shgrp, geom, mat);
}

View File

@ -26,6 +26,7 @@
#include "DRW_render.h"
#include "DNA_world_types.h"
#include "DNA_modifier_types.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
@ -624,72 +625,76 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
if (ob != draw_ctx->scene->obedit) {
material_hash = stl->g_data->hair_material_hash;
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;
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
struct Gwn_Batch *hair_geom = DRW_cache_particles_get_hair(psys);
DRWShadingGroup *shgrp = NULL;
Material *ma = give_current_material(ob, part->omat);
static float mat[4][4];
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;
unit_m4(mat);
if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
struct Gwn_Batch *hair_geom = DRW_cache_particles_get_hair(psys, md);
DRWShadingGroup *shgrp = NULL;
Material *ma = give_current_material(ob, part->omat);
static float mat[4][4];
if (ma == NULL) {
ma = &defmaterial;
}
unit_m4(mat);
float *color_p = &ma->r;
float *metal_p = &ma->ray_mirror;
float *spec_p = &ma->spec;
float *rough_p = &ma->gloss_mir;
if (ma == NULL) {
ma = &defmaterial;
}
DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat);
float *color_p = &ma->r;
float *metal_p = &ma->ray_mirror;
float *spec_p = &ma->spec;
float *rough_p = &ma->gloss_mir;
shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat);
if (shgrp) {
DRW_shgroup_call_add(shgrp, hair_geom, mat);
}
else {
if (ma->use_nodes && ma->nodetree) {
Scene *scene = draw_ctx->scene;
struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
stl->effects->use_ao, stl->effects->use_bent_normals);
shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
if (shgrp) {
add_standard_uniforms(shgrp, sldata, vedata);
if (shgrp) {
DRW_shgroup_call_add(shgrp, hair_geom, mat);
}
else {
if (ma->use_nodes && ma->nodetree) {
Scene *scene = draw_ctx->scene;
struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
stl->effects->use_ao, stl->effects->use_bent_normals);
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
if (shgrp) {
add_standard_uniforms(shgrp, sldata, vedata);
BLI_ghash_insert(material_hash, ma, shgrp);
DRW_shgroup_call_add(shgrp, hair_geom, mat);
}
else {
/* Shader failed : pink color */
static float col[3] = {1.0f, 0.0f, 1.0f};
static float half = 0.5f;
color_p = col;
metal_p = spec_p = rough_p = ½
}
}
/* Fallback to default shader */
if (shgrp == NULL) {
shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false,
stl->effects->use_ao, stl->effects->use_bent_normals);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
BLI_ghash_insert(material_hash, ma, shgrp);
DRW_shgroup_call_add(shgrp, hair_geom, mat);
}
else {
/* Shader failed : pink color */
static float col[3] = {1.0f, 0.0f, 1.0f};
static float half = 0.5f;
color_p = col;
metal_p = spec_p = rough_p = ½
}
}
/* Fallback to default shader */
if (shgrp == NULL) {
shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false,
stl->effects->use_ao, stl->effects->use_bent_normals);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
BLI_ghash_insert(material_hash, ma, shgrp);
DRW_shgroup_call_add(shgrp, hair_geom, mat);
}
}
}

View File

@ -29,6 +29,7 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_modifier_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@ -2331,9 +2332,9 @@ Gwn_Batch *DRW_cache_lattice_vert_overlay_get(Object *ob)
/** \name Particles
* \{ */
Gwn_Batch *DRW_cache_particles_get_hair(ParticleSystem *psys)
Gwn_Batch *DRW_cache_particles_get_hair(ParticleSystem *psys, ModifierData *md)
{
return DRW_particles_batch_cache_get_hair(psys);
return DRW_particles_batch_cache_get_hair(psys, md);
}
Gwn_Batch *DRW_cache_particles_get_dots(ParticleSystem *psys)

View File

@ -28,6 +28,7 @@
struct Gwn_Batch;
struct Object;
struct ModifierData;
void DRW_shape_cache_free(void);
@ -144,7 +145,7 @@ struct Gwn_Batch *DRW_cache_lattice_wire_get(struct Object *ob);
struct Gwn_Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys);
struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_cache_particles_get_dots(struct ParticleSystem *psys);
struct Gwn_Batch *DRW_cache_particles_get_prim(int type);

View File

@ -30,6 +30,7 @@ struct Gwn_Batch;
struct ListBase;
struct CurveCache;
struct ParticleSystem;
struct ModifierData;
struct Curve;
struct Lattice;
@ -94,7 +95,7 @@ struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me);
struct Gwn_Batch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me);
/* Particles */
struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys);
struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct ParticleSystem *psys);
#endif /* __DRAW_CACHE_IMPL_H__ */

View File

@ -33,10 +33,13 @@
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
#include "BLI_ghash.h"
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
#include "BKE_particle.h"
#include "BKE_DerivedMesh.h"
#include "GPU_batch.h"
@ -170,21 +173,46 @@ static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache)
}
/* Gwn_Batch cache usage. */
static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ParticleBatchCache *cache)
static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ModifierData *md, ParticleBatchCache *cache)
{
if (cache->pos == NULL || cache->segments == NULL) {
int curr_point = 0;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
GWN_VERTBUF_DISCARD_SAFE(cache->pos);
GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
static Gwn_VertFormat format = { 0 };
static struct { uint pos, tan, ind; } attr_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
attr_id.tan = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
attr_id.ind = GWN_vertformat_attr_add(&format, "ind", GWN_COMP_I32, 1, GWN_FETCH_INT);
unsigned int *uv_id;
int uv_layers = 0;
MTFace **mtfaces;
float (**parent_uvs)[2] = NULL;
bool simple = psys->part->childtype == PART_CHILD_PARTICLES;
if (psmd) {
if (CustomData_has_layer(&psmd->dm_final->loopData, CD_MLOOPUV)) {
uv_layers = CustomData_number_of_layers(&psmd->dm_final->loopData, CD_MLOOPUV);
}
}
GWN_vertformat_clear(&format);
/* initialize vertex format */
attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
attr_id.tan = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
attr_id.ind = GWN_vertformat_attr_add(&format, "ind", GWN_COMP_I32, 1, GWN_FETCH_INT);
if (psmd) {
uv_id = MEM_mallocN(sizeof(*uv_id) * uv_layers, "UV attrib format");
for (int i = 0; i < uv_layers; i++) {
const char *name = CustomData_get_layer_name(&psmd->dm_final->loopData, CD_MLOOPUV, i);
char uuid[32];
BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name));
uv_id[i] = GWN_vertformat_attr_add(&format, uuid, GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
}
}
cache->pos = GWN_vertbuf_create_with_format(&format);
@ -193,12 +221,55 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
Gwn_IndexBufBuilder elb;
GWN_indexbuf_init(&elb, GWN_PRIM_LINES, cache->segment_count, cache->point_count);
if (uv_layers) {
DM_ensure_tessface(psmd->dm_final);
mtfaces = MEM_mallocN(sizeof(*mtfaces) * uv_layers, "Faces UV layers");
for (int i = 0; i < uv_layers; i++) {
mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->dm_final->faceData, CD_MTFACE, i);
}
}
if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
if (simple) {
parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs");
}
for (int i = 0; i < psys->totpart; i++) {
ParticleCacheKey *path = psys->pathcache[i];
if (path->segments > 0) {
float tangent[3];
int from = psmd ? psmd->psys->part->from : 0;
float (*uv)[2];
if (psmd) {
uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
if (simple) {
parent_uvs[i] = uv;
}
}
if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
ParticleData *particle = &psys->particles[i];
int num = particle->num_dmcache;
if (num == DMCACHE_NOTFOUND) {
if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
num = particle->num;
}
}
if (num != DMCACHE_NOTFOUND) {
MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
for (int j = 0; j < uv_layers; j++) {
psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]);
}
}
}
for (int j = 0; j < path->segments; j++) {
if (j == 0) {
@ -212,6 +283,12 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i);
if (psmd) {
for (int k = 0; k < uv_layers; k++) {
GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]);
}
}
GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1);
curr_point++;
@ -223,6 +300,16 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i);
if (psmd) {
for (int k = 0; k < uv_layers; k++) {
GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]);
}
if (!simple) {
MEM_freeN(uv);
}
}
curr_point++;
}
}
@ -231,11 +318,61 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
if (psys->childcache) {
int child_count = psys->totchild * psys->part->disp / 100;
if (simple && !parent_uvs) {
parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs");
}
for (int i = 0, x = psys->totpart; i < child_count; i++, x++) {
ParticleCacheKey *path = psys->childcache[i];
float tangent[3];
if (path->segments > 0) {
int from = psmd ? psmd->psys->part->from : 0;
float (*uv)[2];
if (!simple) {
if (psmd) {
uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
}
if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
ChildParticle *particle = &psys->child[i];
int num = psys->part->childtype == particle->num;
if (num != DMCACHE_NOTFOUND) {
MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
for (int j = 0; j < uv_layers; j++) {
psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]);
}
}
}
}
else if (!parent_uvs[psys->child[i].parent]) {
if (psmd) {
parent_uvs[psys->child[i].parent] = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs");
}
if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
ParticleData *particle = &psys->particles[psys->child[i].parent];
int num = particle->num_dmcache;
if (num == DMCACHE_NOTFOUND) {
if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
num = particle->num;
}
}
if (num != DMCACHE_NOTFOUND) {
MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
for (int j = 0; j < uv_layers; j++) {
psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, parent_uvs[psys->child[i].parent][j]);
}
}
}
}
for (int j = 0; j < path->segments; j++) {
if (j == 0) {
sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
@ -248,6 +385,13 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x);
if (psmd) {
for (int k = 0; k < uv_layers; k++) {
GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point,
simple ? parent_uvs[psys->child[i].parent][k] : uv[k]);
}
}
GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1);
curr_point++;
@ -259,11 +403,38 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent);
GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x);
if (psmd) {
for (int k = 0; k < uv_layers; k++) {
GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point,
simple ? parent_uvs[psys->child[i].parent][k] : uv[k]);
}
if (!simple) {
MEM_freeN(uv);
}
}
curr_point++;
}
}
}
if (parent_uvs) {
for (int i = 0; i < psys->totpart; i++) {
MEM_SAFE_FREE(parent_uvs[i]);
}
MEM_freeN(parent_uvs);
}
if (uv_layers) {
MEM_freeN(mtfaces);
}
if (psmd) {
MEM_freeN(uv_id);
}
cache->segments = GWN_indexbuf_build(&elb);
}
}
@ -322,13 +493,13 @@ static void particle_batch_cache_ensure_pos(ParticleSystem *psys, ParticleBatchC
}
}
Gwn_Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys)
Gwn_Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys, ModifierData *md)
{
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);
particle_batch_cache_ensure_pos_and_seg(psys, md, cache);
cache->hairs = GWN_batch_create(GWN_PRIM_LINES, cache->pos, cache->segments);
}