Implement hair in eevee
New implementation of hair for Eevee. Note: A hard coded "transmission" property is being used. This should eventually be exposed to the UI, possibly in the form of SSS properties.
This commit is contained in:
parent
0d9611718d
commit
c59abb4c9a
|
@ -4,7 +4,7 @@ uniform mat3 NormalMatrix;
|
|||
uniform mat4 ModelViewMatrix;
|
||||
|
||||
in vec3 pos;
|
||||
in vec3 tang;
|
||||
in vec3 nor;
|
||||
in int ind;
|
||||
out vec3 tangent;
|
||||
out vec3 viewPosition;
|
||||
|
@ -28,7 +28,7 @@ float rand(int s)
|
|||
void main()
|
||||
{
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
|
||||
tangent = normalize(NormalMatrix * tang);
|
||||
tangent = normalize(NormalMatrix * nor);
|
||||
viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
|
||||
colRand = rand(ind);
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ static void EEVEE_draw_scene(void *vedata)
|
|||
/* Shading pass */
|
||||
DRW_draw_pass(psl->default_pass);
|
||||
DRW_draw_pass(psl->default_flat_pass);
|
||||
DRW_draw_pass(psl->default_hair_pass);
|
||||
DRW_draw_pass(psl->material_pass);
|
||||
|
||||
/* Post Process */
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "BLI_dynstr.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "BKE_particle.h"
|
||||
|
||||
#include "GPU_material.h"
|
||||
|
||||
#include "eevee_engine.h"
|
||||
|
@ -55,6 +57,7 @@ enum {
|
|||
enum {
|
||||
VAR_MAT_MESH = (1 << 0),
|
||||
VAR_MAT_PROBE = (1 << 1),
|
||||
VAR_MAT_HAIR = (1 << 2),
|
||||
};
|
||||
|
||||
/* *********** STATIC *********** */
|
||||
|
@ -63,6 +66,7 @@ static struct {
|
|||
|
||||
struct GPUShader *default_lit;
|
||||
struct GPUShader *default_lit_flat;
|
||||
struct GPUShader *default_lit_hair;
|
||||
|
||||
struct GPUShader *default_background;
|
||||
|
||||
|
@ -183,12 +187,19 @@ void EEVEE_materials_init(void)
|
|||
datatoc_lit_surface_vert_glsl, NULL, frag_str,
|
||||
SHADER_DEFINES
|
||||
"#define MESH_SHADER\n");
|
||||
|
||||
e_data.default_lit_flat = DRW_shader_create(
|
||||
datatoc_lit_surface_vert_glsl, NULL, frag_str,
|
||||
SHADER_DEFINES
|
||||
"#define MESH_SHADER\n"
|
||||
"#define USE_FLAT_NORMAL\n");
|
||||
|
||||
e_data.default_lit_hair = DRW_shader_create(
|
||||
datatoc_lit_surface_vert_glsl, NULL, frag_str,
|
||||
SHADER_DEFINES
|
||||
"#define MESH_SHADER\n"
|
||||
"#define HAIR_SHADER\n");
|
||||
|
||||
MEM_freeN(frag_str);
|
||||
|
||||
/* Textures */
|
||||
|
@ -257,6 +268,15 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma)
|
|||
SHADER_DEFINES "#define MESH_SHADER\n");
|
||||
}
|
||||
|
||||
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
|
||||
{
|
||||
return GPU_material_from_nodetree(
|
||||
scene, ma->nodetree, &ma->gpumaterial, &DRW_engine_viewport_eevee_type,
|
||||
VAR_MAT_HAIR,
|
||||
datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib,
|
||||
SHADER_DEFINES "#define MESH_SHADER\n" "#define HAIR_SHADER\n");
|
||||
}
|
||||
|
||||
static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata)
|
||||
{
|
||||
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
|
||||
|
@ -280,6 +300,7 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
/* Create Material Ghash */
|
||||
{
|
||||
stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
|
||||
stl->g_data->hair_material_hash = BLI_ghash_ptr_new("Eevee_hair_material ghash");
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -322,7 +343,7 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
|
||||
{
|
||||
struct GPUShader *depth_sh = DRW_shader_create_3D_depth_only();
|
||||
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
|
||||
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE;
|
||||
psl->depth_pass = DRW_pass_create("Depth Pass", state);
|
||||
stl->g_data->depth_shgrp = DRW_shgroup_create(depth_sh, psl->depth_pass);
|
||||
|
||||
|
@ -332,7 +353,7 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
}
|
||||
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_WIRE;
|
||||
psl->default_pass = DRW_pass_create("Default Lit Pass", state);
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit, psl->default_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
|
@ -340,10 +361,14 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata)
|
|||
psl->default_flat_pass = DRW_pass_create("Default Flat Lit Pass", state);
|
||||
shgrp = DRW_shgroup_create(e_data.default_lit_flat, psl->default_flat_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
|
||||
psl->default_hair_pass = DRW_pass_create("Default Hair Lit Pass", state);
|
||||
shgrp = DRW_shgroup_create(e_data.default_lit_hair, psl->default_hair_pass);
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
}
|
||||
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_WIRE;
|
||||
psl->material_pass = DRW_pass_create("Material Shader Pass", state);
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +466,81 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
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;
|
||||
|
||||
if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
|
||||
struct 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];
|
||||
|
||||
unit_m4(mat);
|
||||
|
||||
if (ma == NULL) {
|
||||
ma = &defmaterial;
|
||||
}
|
||||
|
||||
float *color_p = &ma->r;
|
||||
float *metal_p = &ma->ray_mirror;
|
||||
float *spec_p = &ma->spec;
|
||||
float *rough_p = &ma->gloss_mir;
|
||||
|
||||
DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
|
||||
|
||||
shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
|
||||
|
||||
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);
|
||||
|
||||
shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
|
||||
if (shgrp) {
|
||||
add_standard_uniforms(shgrp, sldata);
|
||||
|
||||
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 = DRW_shgroup_create(e_data.default_lit_hair, psl->default_hair_pass);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEVEE_materials_cache_finish(EEVEE_Data *vedata)
|
||||
|
@ -448,6 +548,7 @@ void EEVEE_materials_cache_finish(EEVEE_Data *vedata)
|
|||
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
|
||||
|
||||
BLI_ghash_free(stl->g_data->material_hash, NULL, NULL);
|
||||
BLI_ghash_free(stl->g_data->hair_material_hash, NULL, NULL);
|
||||
}
|
||||
|
||||
void EEVEE_materials_free(void)
|
||||
|
@ -455,6 +556,7 @@ void EEVEE_materials_free(void)
|
|||
MEM_SAFE_FREE(e_data.frag_shader_lib);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_lit);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_lit_flat);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_lit_hair);
|
||||
DRW_SHADER_FREE_SAFE(e_data.default_background);
|
||||
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ typedef struct EEVEE_PassList {
|
|||
struct DRWPass *depth_pass_cull;
|
||||
struct DRWPass *default_pass;
|
||||
struct DRWPass *default_flat_pass;
|
||||
struct DRWPass *default_hair_pass;
|
||||
struct DRWPass *material_pass;
|
||||
struct DRWPass *background_pass;
|
||||
} EEVEE_PassList;
|
||||
|
@ -318,6 +319,7 @@ typedef struct EEVEE_PrivateData {
|
|||
struct DRWShadingGroup *depth_shgrp;
|
||||
struct DRWShadingGroup *depth_shgrp_cull;
|
||||
struct GHash *material_hash;
|
||||
struct GHash *hair_material_hash;
|
||||
} EEVEE_PrivateData; /* Transient data */
|
||||
|
||||
/* eevee_data.c */
|
||||
|
@ -336,6 +338,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, str
|
|||
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
|
||||
struct GPUMaterial *EEVEE_material_mesh_lightprobe_get(struct Scene *scene, Material *ma);
|
||||
struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma);
|
||||
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma);
|
||||
void EEVEE_materials_free(void);
|
||||
|
||||
/* eevee_lights.c */
|
||||
|
|
|
@ -88,7 +88,70 @@ vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec)
|
|||
|
||||
return texture(tex, vec3(uvs, cubevec.w));
|
||||
}
|
||||
#ifdef HAIR_SHADER
|
||||
vec3 light_diffuse(LightData ld, ShadingData sd, vec3 albedo)
|
||||
{
|
||||
if (ld.l_type == SUN) {
|
||||
return direct_diffuse_sun(ld, sd) * albedo;
|
||||
}
|
||||
else if (ld.l_type == AREA) {
|
||||
return direct_diffuse_rectangle(ld, sd) * albedo;
|
||||
}
|
||||
else {
|
||||
return direct_diffuse_sphere(ld, sd) * albedo;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 light_specular(LightData ld, ShadingData sd, float roughness, vec3 f0)
|
||||
{
|
||||
if (ld.l_type == SUN) {
|
||||
return direct_ggx_sun(ld, sd, roughness, f0);
|
||||
}
|
||||
else if (ld.l_type == AREA) {
|
||||
return direct_ggx_rectangle(ld, sd, roughness, f0);
|
||||
}
|
||||
else {
|
||||
return direct_ggx_sphere(ld, sd, roughness, f0);
|
||||
}
|
||||
}
|
||||
|
||||
void light_shade(
|
||||
LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0,
|
||||
out vec3 diffuse, out vec3 specular)
|
||||
{
|
||||
const float transmission = 0.3; /* Uniform internal scattering factor */
|
||||
ShadingData sd_new = sd;
|
||||
|
||||
vec3 lamp_vec;
|
||||
|
||||
if (ld.l_type == SUN || ld.l_type == AREA) {
|
||||
lamp_vec = ld.l_forward;
|
||||
}
|
||||
else {
|
||||
lamp_vec = -sd.l_vector;
|
||||
}
|
||||
|
||||
vec3 norm_view = cross(sd.V, sd.N);
|
||||
norm_view = normalize(cross(norm_view, sd.N)); /* Normal facing view */
|
||||
|
||||
vec3 norm_lamp = cross(lamp_vec, sd.N);
|
||||
norm_lamp = normalize(cross(sd.N, norm_lamp)); /* Normal facing lamp */
|
||||
|
||||
/* Rotate view vector onto the cross(tangent, light) plane */
|
||||
vec3 view_vec = normalize(norm_lamp * dot(norm_view, sd.V) + sd.N * dot(sd.N, sd.V));
|
||||
|
||||
float occlusion = (dot(norm_view, norm_lamp) * 0.5 + 0.5);
|
||||
float occltrans = transmission + (occlusion * (1.0 - transmission)); /* Includes transmission component */
|
||||
|
||||
sd_new.N = -norm_lamp;
|
||||
|
||||
diffuse = light_diffuse(ld, sd_new, albedo) * occltrans;
|
||||
|
||||
sd_new.V = view_vec;
|
||||
|
||||
specular = light_specular(ld, sd_new, roughness, f0) * occlusion;
|
||||
}
|
||||
#else
|
||||
void light_shade(
|
||||
LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0,
|
||||
out vec3 diffuse, out vec3 specular)
|
||||
|
@ -118,6 +181,7 @@ void light_shade(
|
|||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void light_visibility(LightData ld, ShadingData sd, out float vis)
|
||||
{
|
||||
|
@ -254,20 +318,33 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness,
|
|||
sd.W = worldPosition;
|
||||
|
||||
vec3 radiance = vec3(0.0);
|
||||
|
||||
#ifdef HAIR_SHADER
|
||||
/* View facing normal */
|
||||
vec3 norm_view = cross(sd.V, sd.N);
|
||||
norm_view = normalize(cross(norm_view, sd.N)); /* Normal facing view */
|
||||
#endif
|
||||
|
||||
|
||||
/* Analitic Lights */
|
||||
for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) {
|
||||
LightData ld = lights_data[i];
|
||||
vec3 diff, spec;
|
||||
float vis;
|
||||
float vis = 1.0;
|
||||
|
||||
sd.l_vector = ld.l_position - worldPosition;
|
||||
|
||||
#ifndef HAIR_SHADER
|
||||
light_visibility(ld, sd, vis);
|
||||
#endif
|
||||
light_shade(ld, sd, albedo, roughnessSquared, f0, diff, spec);
|
||||
|
||||
radiance += vis * (diff + spec) * ld.l_color;
|
||||
}
|
||||
|
||||
#ifdef HAIR_SHADER
|
||||
sd.N = -norm_view;
|
||||
#endif
|
||||
|
||||
/* Envmaps */
|
||||
vec3 R = reflect(-sd.V, sd.N);
|
||||
|
@ -314,4 +391,4 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness,
|
|||
diff_accum.rgb * albedo;
|
||||
|
||||
return radiance + indirect_radiance * ao;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Partic
|
|||
if (format.attrib_ct == 0) {
|
||||
/* initialize vertex format */
|
||||
attr_id.pos = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
|
||||
attr_id.tan = VertexFormat_add_attrib(&format, "tang", COMP_F32, 3, KEEP_FLOAT);
|
||||
attr_id.tan = VertexFormat_add_attrib(&format, "nor", COMP_F32, 3, KEEP_FLOAT);
|
||||
attr_id.ind = VertexFormat_add_attrib(&format, "ind", COMP_I32, 1, KEEP_INT);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue