EEVEE-Next: Fix Hair and Curves motion vectors #112425
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "DNA_particle_types.h"
|
#include "DNA_particle_types.h"
|
||||||
|
|
||||||
|
#include "draw_common.hh"
|
||||||
|
|
||||||
namespace blender::eevee {
|
namespace blender::eevee {
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -291,9 +293,20 @@ void Instance::render_sync()
|
||||||
|
|
||||||
manager->begin_sync();
|
manager->begin_sync();
|
||||||
|
|
||||||
|
draw::hair_init();
|
||||||
|
draw::curves_init();
|
||||||
|
|
||||||
begin_sync();
|
begin_sync();
|
||||||
|
|
||||||
DRW_render_object_iter(this, render, depsgraph, object_sync_render);
|
DRW_render_object_iter(this, render, depsgraph, object_sync_render);
|
||||||
|
|
||||||
|
draw::hair_update(*manager);
|
||||||
|
draw::curves_update(*manager);
|
||||||
|
draw::hair_free();
|
||||||
|
draw::curves_free();
|
||||||
|
|
||||||
velocity.geometry_steps_fill();
|
velocity.geometry_steps_fill();
|
||||||
|
|
||||||
end_sync();
|
end_sync();
|
||||||
|
|
||||||
manager->end_sync();
|
manager->end_sync();
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "eevee_shader_shared.hh"
|
#include "eevee_shader_shared.hh"
|
||||||
#include "eevee_velocity.hh"
|
#include "eevee_velocity.hh"
|
||||||
|
|
||||||
|
#include "draw_common.hh"
|
||||||
|
|
||||||
namespace blender::eevee {
|
namespace blender::eevee {
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -100,7 +102,17 @@ void VelocityModule::step_sync(eVelocityStep step, float time)
|
||||||
step_ = step;
|
step_ = step;
|
||||||
object_steps_usage[step_] = 0;
|
object_steps_usage[step_] = 0;
|
||||||
step_camera_sync();
|
step_camera_sync();
|
||||||
|
|
||||||
|
draw::hair_init();
|
||||||
|
draw::curves_init();
|
||||||
|
|
||||||
DRW_render_object_iter(&inst_, inst_.render, inst_.depsgraph, step_object_sync_render);
|
DRW_render_object_iter(&inst_, inst_.render, inst_.depsgraph, step_object_sync_render);
|
||||||
|
|
||||||
|
draw::hair_update(*inst_.manager);
|
||||||
|
draw::curves_update(*inst_.manager);
|
||||||
|
draw::hair_free();
|
||||||
|
draw::curves_free();
|
||||||
|
|
||||||
geometry_steps_fill();
|
geometry_steps_fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +154,7 @@ bool VelocityModule::step_object_sync(Object *ob,
|
||||||
VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
|
VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
|
||||||
vel.obj.ofs[step_] = object_steps_usage[step_]++;
|
vel.obj.ofs[step_] = object_steps_usage[step_]++;
|
||||||
vel.obj.resource_id = resource_handle.resource_index();
|
vel.obj.resource_id = resource_handle.resource_index();
|
||||||
vel.id = particle_sys ? &particle_sys->part->id : &ob->id;
|
vel.id = object_key.hash_value;
|
||||||
object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = float4x4_view(ob->object_to_world);
|
object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = float4x4_view(ob->object_to_world);
|
||||||
if (step_ == STEP_CURRENT) {
|
if (step_ == STEP_CURRENT) {
|
||||||
/* Replace invalid steps. Can happen if object was hidden in one of those steps. */
|
/* Replace invalid steps. Can happen if object was hidden in one of those steps. */
|
||||||
|
@ -163,12 +175,22 @@ bool VelocityModule::step_object_sync(Object *ob,
|
||||||
auto add_cb = [&]() {
|
auto add_cb = [&]() {
|
||||||
VelocityGeometryData data;
|
VelocityGeometryData data;
|
||||||
if (particle_sys) {
|
if (particle_sys) {
|
||||||
data.pos_buf = DRW_hair_pos_buffer_get(ob, particle_sys, modifier_data);
|
if (inst_.is_viewport()) {
|
||||||
|
data.pos_buf = DRW_hair_pos_buffer_get(ob, particle_sys, modifier_data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.pos_buf = draw::hair_pos_buffer_get(inst_.scene, ob, particle_sys, modifier_data);
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
switch (ob->type) {
|
switch (ob->type) {
|
||||||
case OB_CURVES:
|
case OB_CURVES:
|
||||||
data.pos_buf = DRW_curves_pos_buffer_get(ob);
|
if (inst_.is_viewport()) {
|
||||||
|
data.pos_buf = DRW_curves_pos_buffer_get(ob);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.pos_buf = draw::curves_pos_buffer_get(inst_.scene, ob);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OB_POINTCLOUD:
|
case OB_POINTCLOUD:
|
||||||
data.pos_buf = DRW_pointcloud_position_and_radius_buffer_get(ob);
|
data.pos_buf = DRW_pointcloud_position_and_radius_buffer_get(ob);
|
||||||
|
@ -251,7 +273,7 @@ void VelocityModule::geometry_steps_fill()
|
||||||
vel.geo.len[step_] = geom.len;
|
vel.geo.len[step_] = geom.len;
|
||||||
vel.geo.ofs[step_] = geom.ofs;
|
vel.geo.ofs[step_] = geom.ofs;
|
||||||
/* Avoid reuse. */
|
/* Avoid reuse. */
|
||||||
vel.id = nullptr;
|
vel.id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry_map.clear();
|
geometry_map.clear();
|
||||||
|
@ -263,7 +285,6 @@ void VelocityModule::geometry_steps_fill()
|
||||||
*/
|
*/
|
||||||
void VelocityModule::step_swap()
|
void VelocityModule::step_swap()
|
||||||
{
|
{
|
||||||
|
|
||||||
auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
|
auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
|
||||||
std::swap(object_steps[step_a], object_steps[step_b]);
|
std::swap(object_steps[step_a], object_steps[step_b]);
|
||||||
std::swap(geometry_steps[step_a], geometry_steps[step_b]);
|
std::swap(geometry_steps[step_a], geometry_steps[step_b]);
|
||||||
|
|
|
@ -29,8 +29,8 @@ namespace blender::eevee {
|
||||||
class VelocityModule {
|
class VelocityModule {
|
||||||
public:
|
public:
|
||||||
struct VelocityObjectData : public VelocityIndex {
|
struct VelocityObjectData : public VelocityIndex {
|
||||||
/** ID to retrieve the corresponding #VelocityGeometryData after copy. */
|
/** ID key to retrieve the corresponding #VelocityGeometryData after copy. */
|
||||||
ID *id;
|
uint64_t id;
|
||||||
};
|
};
|
||||||
struct VelocityGeometryData {
|
struct VelocityGeometryData {
|
||||||
/** VertBuf not yet ready to be copied to the #VelocityGeometryBuf. */
|
/** VertBuf not yet ready to be copied to the #VelocityGeometryBuf. */
|
||||||
|
@ -46,8 +46,8 @@ class VelocityModule {
|
||||||
* geometry offset.
|
* geometry offset.
|
||||||
*/
|
*/
|
||||||
Map<ObjectKey, VelocityObjectData> velocity_map;
|
Map<ObjectKey, VelocityObjectData> velocity_map;
|
||||||
/** Geometry to be copied to VelocityGeometryBuf. Indexed by evaluated ID *. Empty after */
|
/** Geometry to be copied to VelocityGeometryBuf. Indexed by evaluated ID hash. Empty after */
|
||||||
Map<ID *, VelocityGeometryData> geometry_map;
|
Map<uint64_t, VelocityGeometryData> geometry_map;
|
||||||
/** Contains all objects matrices for each time step. */
|
/** Contains all objects matrices for each time step. */
|
||||||
std::array<VelocityObjectBuf *, 3> object_steps;
|
std::array<VelocityObjectBuf *, 3> object_steps;
|
||||||
/** Contains all Geometry steps from deforming objects for each time step. */
|
/** Contains all Geometry steps from deforming objects for each time step. */
|
||||||
|
|
|
@ -14,6 +14,19 @@
|
||||||
|
|
||||||
namespace blender::draw {
|
namespace blender::draw {
|
||||||
|
|
||||||
|
/** Hair. */
|
||||||
|
|
||||||
|
void hair_init();
|
||||||
|
|
||||||
|
GPUVertBuf *hair_pos_buffer_get(Scene *scene,
|
||||||
|
Object *object,
|
||||||
|
ParticleSystem *psys,
|
||||||
|
ModifierData *md);
|
||||||
|
|
||||||
|
void hair_update(Manager &manager);
|
||||||
|
|
||||||
|
void hair_free();
|
||||||
|
|
||||||
GPUBatch *hair_sub_pass_setup(PassMain::Sub &sub_ps,
|
GPUBatch *hair_sub_pass_setup(PassMain::Sub &sub_ps,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
Object *object,
|
Object *object,
|
||||||
|
@ -28,6 +41,16 @@ GPUBatch *hair_sub_pass_setup(PassSimple::Sub &sub_ps,
|
||||||
ModifierData *md,
|
ModifierData *md,
|
||||||
GPUMaterial *gpu_material = nullptr);
|
GPUMaterial *gpu_material = nullptr);
|
||||||
|
|
||||||
|
/** Curves. */
|
||||||
|
|
||||||
|
void curves_init();
|
||||||
|
|
||||||
|
GPUVertBuf *curves_pos_buffer_get(Scene *scene, Object *object);
|
||||||
|
|
||||||
|
void curves_update(Manager &manager);
|
||||||
|
|
||||||
|
void curves_free();
|
||||||
|
|
||||||
GPUBatch *curves_sub_pass_setup(PassMain::Sub &ps,
|
GPUBatch *curves_sub_pass_setup(PassMain::Sub &ps,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
|
@ -38,6 +61,8 @@ GPUBatch *curves_sub_pass_setup(PassSimple::Sub &ps,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
GPUMaterial *gpu_material = nullptr);
|
GPUMaterial *gpu_material = nullptr);
|
||||||
|
|
||||||
|
/* Point cloud. */
|
||||||
|
|
||||||
GPUBatch *point_cloud_sub_pass_setup(PassMain::Sub &sub_ps,
|
GPUBatch *point_cloud_sub_pass_setup(PassMain::Sub &sub_ps,
|
||||||
Object *object,
|
Object *object,
|
||||||
GPUMaterial *gpu_material = nullptr);
|
GPUMaterial *gpu_material = nullptr);
|
||||||
|
@ -46,6 +71,8 @@ GPUBatch *point_cloud_sub_pass_setup(PassSimple::Sub &sub_ps,
|
||||||
Object *object,
|
Object *object,
|
||||||
GPUMaterial *gpu_material = nullptr);
|
GPUMaterial *gpu_material = nullptr);
|
||||||
|
|
||||||
|
/** Volume. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add attribute bindings of volume grids to an existing pass.
|
* Add attribute bindings of volume grids to an existing pass.
|
||||||
* No draw call is added so the caller can decide how to use the data.
|
* No draw call is added so the caller can decide how to use the data.
|
||||||
|
|
|
@ -88,6 +88,25 @@ static GPUShader *curves_eval_shader_get(CurvesEvalShader type)
|
||||||
return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
|
return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drw_curves_ensure_dummy_vbo()
|
||||||
|
{
|
||||||
|
if (g_dummy_vbo != nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* initialize vertex format */
|
||||||
|
GPUVertFormat format = {0};
|
||||||
|
uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||||
|
|
||||||
|
g_dummy_vbo = GPU_vertbuf_create_with_format_ex(
|
||||||
|
&format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
|
||||||
|
|
||||||
|
const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
|
||||||
|
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
|
||||||
|
/* Create vbo immediately to bind to texture buffer. */
|
||||||
|
GPU_vertbuf_use(g_dummy_vbo);
|
||||||
|
}
|
||||||
|
|
||||||
void DRW_curves_init(DRWData *drw_data)
|
void DRW_curves_init(DRWData *drw_data)
|
||||||
{
|
{
|
||||||
/* Initialize legacy hair too, to avoid verbosity in callers. */
|
/* Initialize legacy hair too, to avoid verbosity in callers. */
|
||||||
|
@ -106,20 +125,7 @@ void DRW_curves_init(DRWData *drw_data)
|
||||||
g_tf_pass = DRW_pass_create("Update Curves Pass", DRW_STATE_WRITE_COLOR);
|
g_tf_pass = DRW_pass_create("Update Curves Pass", DRW_STATE_WRITE_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_dummy_vbo == nullptr) {
|
drw_curves_ensure_dummy_vbo();
|
||||||
/* initialize vertex format */
|
|
||||||
GPUVertFormat format = {0};
|
|
||||||
uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
|
||||||
|
|
||||||
g_dummy_vbo = GPU_vertbuf_create_with_format_ex(
|
|
||||||
&format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
|
|
||||||
|
|
||||||
const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
|
|
||||||
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
|
|
||||||
/* Create vbo immediately to bind to texture buffer. */
|
|
||||||
GPU_vertbuf_use(g_dummy_vbo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool)
|
void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool)
|
||||||
|
@ -553,12 +559,102 @@ void DRW_curves_free()
|
||||||
|
|
||||||
namespace blender::draw {
|
namespace blender::draw {
|
||||||
|
|
||||||
|
static PassSimple *g_pass = nullptr;
|
||||||
|
|
||||||
|
void curves_init()
|
||||||
|
{
|
||||||
|
if (!g_pass) {
|
||||||
|
g_pass = MEM_new<PassSimple>("drw_curves g_pass", "Update Curves Pass");
|
||||||
|
}
|
||||||
|
g_pass->init();
|
||||||
|
g_pass->state_set(DRW_STATE_NO_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CurvesEvalCache *curves_cache_get(Curves &curves,
|
||||||
|
GPUMaterial *gpu_material,
|
||||||
|
int subdiv,
|
||||||
|
int thickness_res)
|
||||||
|
{
|
||||||
|
CurvesEvalCache *cache;
|
||||||
|
const bool update = curves_ensure_procedural_data(
|
||||||
|
&curves, &cache, gpu_material, subdiv, thickness_res);
|
||||||
|
|
||||||
|
if (!update) {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int strands_len = cache->strands_len;
|
||||||
|
const int final_points_len = cache->final[subdiv].strands_res * strands_len;
|
||||||
|
|
||||||
|
auto cache_update = [&](GPUVertBuf *output_buf, GPUVertBuf *input_buf) {
|
||||||
|
PassSimple::Sub &ob_ps = g_pass->sub("Object Pass");
|
||||||
|
|
||||||
|
ob_ps.shader_set(
|
||||||
|
DRW_shader_curves_refine_get(CURVES_EVAL_CATMULL_ROM, PART_REFINE_SHADER_COMPUTE));
|
||||||
|
|
||||||
|
ob_ps.bind_texture("hairPointBuffer", input_buf);
|
||||||
|
ob_ps.bind_texture("hairStrandBuffer", cache->proc_strand_buf);
|
||||||
|
ob_ps.bind_texture("hairStrandSegBuffer", cache->proc_strand_seg_buf);
|
||||||
|
ob_ps.push_constant("hairStrandsRes", &cache->final[subdiv].strands_res);
|
||||||
|
ob_ps.bind_ssbo("posTime", output_buf);
|
||||||
|
|
||||||
|
const int max_strands_per_call = GPU_max_work_group_count(0);
|
||||||
|
int strands_start = 0;
|
||||||
|
while (strands_start < strands_len) {
|
||||||
|
int batch_strands_len = std::min(strands_len - strands_start, max_strands_per_call);
|
||||||
|
PassSimple::Sub &sub_ps = ob_ps.sub("Sub Pass");
|
||||||
|
sub_ps.push_constant("hairStrandOffset", strands_start);
|
||||||
|
sub_ps.dispatch(int3(batch_strands_len, cache->final[subdiv].strands_res, 1));
|
||||||
|
strands_start += batch_strands_len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (final_points_len > 0) {
|
||||||
|
cache_update(cache->final[subdiv].proc_buf, cache->proc_point_buf);
|
||||||
|
|
||||||
|
const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
|
||||||
|
for (int i : IndexRange(attrs.num_requests)) {
|
||||||
|
/* Only refine point attributes. */
|
||||||
|
if (attrs.requests[i].domain != ATTR_DOMAIN_CURVE) {
|
||||||
|
cache_update(cache->final[subdiv].attributes_buf[i], cache->proc_attributes_buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPUVertBuf *curves_pos_buffer_get(Scene *scene, Object *object)
|
||||||
|
{
|
||||||
|
const int subdiv = scene->r.hair_subdiv;
|
||||||
|
const int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
|
||||||
|
|
||||||
|
Curves &curves = *static_cast<Curves *>(object->data);
|
||||||
|
CurvesEvalCache *cache = curves_cache_get(curves, nullptr, subdiv, thickness_res);
|
||||||
|
|
||||||
|
return cache->final[subdiv].proc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void curves_update(Manager &manager)
|
||||||
|
{
|
||||||
|
manager.submit(*g_pass);
|
||||||
|
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void curves_free()
|
||||||
|
{
|
||||||
|
MEM_delete(g_pass);
|
||||||
|
g_pass = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename PassT>
|
template<typename PassT>
|
||||||
GPUBatch *curves_sub_pass_setup_implementation(PassT &sub_ps,
|
GPUBatch *curves_sub_pass_setup_implementation(PassT &sub_ps,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
GPUMaterial *gpu_material)
|
GPUMaterial *gpu_material)
|
||||||
{
|
{
|
||||||
|
/** NOTE: This still relies on the old DRW_curves implementation. */
|
||||||
|
|
||||||
CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
|
CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
|
||||||
CurvesInfosBuf &curves_infos = pool->alloc();
|
CurvesInfosBuf &curves_infos = pool->alloc();
|
||||||
BLI_assert(ob->type == OB_CURVES);
|
BLI_assert(ob->type == OB_CURVES);
|
||||||
|
|
|
@ -71,6 +71,30 @@ static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
|
||||||
return DRW_shader_hair_refine_get(refinement, drw_hair_shader_type_get());
|
return DRW_shader_hair_refine_get(refinement, drw_hair_shader_type_get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drw_hair_ensure_vbo()
|
||||||
|
{
|
||||||
|
if (g_dummy_vbo != nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* initialize vertex format */
|
||||||
|
GPUVertFormat format = {0};
|
||||||
|
uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||||
|
|
||||||
|
g_dummy_vbo = GPU_vertbuf_create_with_format_ex(
|
||||||
|
&format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
|
||||||
|
|
||||||
|
const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
|
||||||
|
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
|
||||||
|
/* Create VBO immediately to bind to texture buffer. */
|
||||||
|
GPU_vertbuf_use(g_dummy_vbo);
|
||||||
|
|
||||||
|
g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>("g_dummy_curves_info");
|
||||||
|
memset(
|
||||||
|
g_dummy_curves_info->is_point_attribute, 0, sizeof(g_dummy_curves_info->is_point_attribute));
|
||||||
|
g_dummy_curves_info->push_update();
|
||||||
|
}
|
||||||
|
|
||||||
void DRW_hair_init()
|
void DRW_hair_init()
|
||||||
{
|
{
|
||||||
if (GPU_transform_feedback_support() || GPU_compute_shader_support()) {
|
if (GPU_transform_feedback_support() || GPU_compute_shader_support()) {
|
||||||
|
@ -80,27 +104,7 @@ void DRW_hair_init()
|
||||||
g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
|
g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_dummy_vbo == nullptr) {
|
drw_hair_ensure_vbo();
|
||||||
/* initialize vertex format */
|
|
||||||
GPUVertFormat format = {0};
|
|
||||||
uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
|
||||||
|
|
||||||
g_dummy_vbo = GPU_vertbuf_create_with_format_ex(
|
|
||||||
&format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
|
|
||||||
|
|
||||||
const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
GPU_vertbuf_data_alloc(g_dummy_vbo, 1);
|
|
||||||
GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert);
|
|
||||||
/* Create VBO immediately to bind to texture buffer. */
|
|
||||||
GPU_vertbuf_use(g_dummy_vbo);
|
|
||||||
|
|
||||||
g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>(
|
|
||||||
"g_dummy_curves_info");
|
|
||||||
memset(g_dummy_curves_info->is_point_attribute,
|
|
||||||
0,
|
|
||||||
sizeof(g_dummy_curves_info->is_point_attribute));
|
|
||||||
g_dummy_curves_info->push_update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
|
static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
|
||||||
|
@ -437,6 +441,86 @@ void DRW_hair_free()
|
||||||
|
|
||||||
namespace blender::draw {
|
namespace blender::draw {
|
||||||
|
|
||||||
|
static PassSimple *g_pass = nullptr;
|
||||||
|
|
||||||
|
void hair_init()
|
||||||
|
{
|
||||||
|
if (!g_pass) {
|
||||||
|
g_pass = MEM_new<PassSimple>("drw_hair g_pass", "Update Hair Pass");
|
||||||
|
}
|
||||||
|
g_pass->init();
|
||||||
|
g_pass->state_set(DRW_STATE_NO_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParticleHairCache *hair_particle_cache_get(Object *object,
|
||||||
|
ParticleSystem *psys,
|
||||||
|
ModifierData *md,
|
||||||
|
GPUMaterial *gpu_material,
|
||||||
|
int subdiv,
|
||||||
|
int thickness_res)
|
||||||
|
{
|
||||||
|
ParticleHairCache *cache;
|
||||||
|
bool update = particles_ensure_procedural_data(
|
||||||
|
object, psys, md, &cache, gpu_material, subdiv, thickness_res);
|
||||||
|
|
||||||
|
if (!update) {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int strands_len = cache->strands_len;
|
||||||
|
const int final_points_len = cache->final[subdiv].strands_res * strands_len;
|
||||||
|
if (final_points_len > 0) {
|
||||||
|
PassSimple::Sub &ob_ps = g_pass->sub("Object Pass");
|
||||||
|
|
||||||
|
ob_ps.shader_set(
|
||||||
|
DRW_shader_hair_refine_get(PART_REFINE_CATMULL_ROM, PART_REFINE_SHADER_COMPUTE));
|
||||||
|
|
||||||
|
ob_ps.bind_texture("hairPointBuffer", cache->proc_point_buf);
|
||||||
|
ob_ps.bind_texture("hairStrandBuffer", cache->proc_strand_buf);
|
||||||
|
ob_ps.bind_texture("hairStrandSegBuffer", cache->proc_strand_seg_buf);
|
||||||
|
ob_ps.push_constant("hairStrandsRes", &cache->final[subdiv].strands_res);
|
||||||
|
ob_ps.bind_ssbo("posTime", cache->final[subdiv].proc_buf);
|
||||||
|
|
||||||
|
const int max_strands_per_call = GPU_max_work_group_count(0);
|
||||||
|
int strands_start = 0;
|
||||||
|
while (strands_start < strands_len) {
|
||||||
|
int batch_strands_len = std::min(strands_len - strands_start, max_strands_per_call);
|
||||||
|
PassSimple::Sub &sub_ps = ob_ps.sub("Sub Pass");
|
||||||
|
sub_ps.push_constant("hairStrandOffset", strands_start);
|
||||||
|
sub_ps.dispatch(int3(batch_strands_len, cache->final[subdiv].strands_res, 1));
|
||||||
|
strands_start += batch_strands_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPUVertBuf *hair_pos_buffer_get(Scene *scene,
|
||||||
|
Object *object,
|
||||||
|
ParticleSystem *psys,
|
||||||
|
ModifierData *md)
|
||||||
|
{
|
||||||
|
int subdiv = scene->r.hair_subdiv;
|
||||||
|
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
|
||||||
|
|
||||||
|
ParticleHairCache *cache = hair_particle_cache_get(
|
||||||
|
object, psys, md, nullptr, subdiv, thickness_res);
|
||||||
|
|
||||||
|
return cache->final[subdiv].proc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hair_update(Manager &manager)
|
||||||
|
{
|
||||||
|
manager.submit(*g_pass);
|
||||||
|
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hair_free()
|
||||||
|
{
|
||||||
|
MEM_delete(g_pass);
|
||||||
|
g_pass = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename PassT>
|
template<typename PassT>
|
||||||
GPUBatch *hair_sub_pass_setup_implementation(PassT &sub_ps,
|
GPUBatch *hair_sub_pass_setup_implementation(PassT &sub_ps,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
@ -445,6 +529,8 @@ GPUBatch *hair_sub_pass_setup_implementation(PassT &sub_ps,
|
||||||
ModifierData *md,
|
ModifierData *md,
|
||||||
GPUMaterial *gpu_material)
|
GPUMaterial *gpu_material)
|
||||||
{
|
{
|
||||||
|
/** NOTE: This still relies on the old DRW_hair implementation. */
|
||||||
|
|
||||||
int subdiv = scene->r.hair_subdiv;
|
int subdiv = scene->r.hair_subdiv;
|
||||||
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
|
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
|
||||||
ParticleHairCache *hair_cache = drw_hair_particle_cache_get(
|
ParticleHairCache *hair_cache = drw_hair_particle_cache_get(
|
||||||
|
|
Loading…
Reference in New Issue