Mesh: Rewrite split edges algorithm #110661
|
@ -18,6 +18,7 @@
|
|||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_bit_vector.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_endian_switch.h"
|
||||
|
@ -61,6 +62,7 @@
|
|||
/* only for customdata_data_transfer_interp_normal_normals */
|
||||
#include "data_transfer_intern.h"
|
||||
|
||||
using blender::BitVector;
|
||||
using blender::float2;
|
||||
using blender::ImplicitSharingInfo;
|
||||
using blender::IndexRange;
|
||||
|
@ -3909,16 +3911,17 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
|
|||
}
|
||||
}
|
||||
|
||||
static bool customdata_layer_copy_check(const CustomDataLayer &source, const CustomDataLayer &dest)
|
||||
{
|
||||
return source.type == dest.type && STREQ(source.name, dest.name);
|
||||
}
|
||||
|
||||
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void *src_block,
|
||||
void **dest_block,
|
||||
const eCustomDataMask mask_exclude)
|
||||
{
|
||||
/* Note that having a version of this function without a 'mask_exclude'
|
||||
* would cause too much duplicate code, so add a check instead. */
|
||||
const bool no_mask = (mask_exclude == 0);
|
||||
|
||||
if (*dest_block == nullptr) {
|
||||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
if (*dest_block) {
|
||||
|
@ -3926,51 +3929,41 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
|
|||
}
|
||||
}
|
||||
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
BitVector<> copied_layers(dest->totlayer);
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
for (int layer_src_i : IndexRange(source->totlayer)) {
|
||||
const CustomDataLayer &layer_src = source->layers[layer_src_i];
|
||||
|
||||
if (CD_TYPE_AS_MASK(layer_src.type) & mask_exclude) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->totlayer) {
|
||||
return;
|
||||
}
|
||||
for (int layer_dst_i : IndexRange(dest->totlayer)) {
|
||||
CustomDataLayer &layer_dst = dest->layers[layer_dst_i];
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type &&
|
||||
STREQ(dest->layers[dest_i].name, source->layers[src_i].name))
|
||||
{
|
||||
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
|
||||
const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(
|
||||
eCustomDataType(source->layers[src_i].type));
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, src_data, typeInfo->size);
|
||||
}
|
||||
if (!customdata_layer_copy_check(layer_src, layer_dst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
copied_layers[layer_dst_i].set(true);
|
||||
|
||||
const void *src_data = POINTER_OFFSET(src_block, layer_src.offset);
|
||||
void *dest_data = POINTER_OFFSET(*dest_block, layer_dst.offset);
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer_src.type));
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, src_data, typeInfo->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (dest_i < dest->totlayer) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
/* Initialize dest layers that weren't in source. */
|
||||
for (int layer_dst_i : IndexRange(dest->totlayer)) {
|
||||
if (!copied_layers[layer_dst_i]) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, layer_dst_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -495,6 +495,7 @@ set(GLSL_SRC
|
|||
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_geom_world_vert.glsl
|
||||
engines/eevee_next/shaders/eevee_hiz_debug_frag.glsl
|
||||
engines/eevee_next/shaders/eevee_hiz_update_comp.glsl
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "eevee_engine.h"
|
||||
#include "eevee_instance.hh"
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -175,7 +177,7 @@ void Instance::scene_sync()
|
|||
void Instance::object_sync(Object *ob)
|
||||
{
|
||||
const bool is_renderable_type = ELEM(
|
||||
ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_LAMP, OB_LIGHTPROBE);
|
||||
ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_POINTCLOUD, OB_LAMP, OB_LIGHTPROBE);
|
||||
const int ob_visibility = DRW_object_visibility_in_active_context(ob);
|
||||
const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
|
||||
(ob->type == OB_MESH);
|
||||
|
@ -193,9 +195,24 @@ void Instance::object_sync(Object *ob)
|
|||
ObjectHandle &ob_handle = sync.sync_object(ob);
|
||||
|
||||
if (partsys_is_visible && ob != DRW_context_state_get()->object_edit) {
|
||||
int sub_key = 1;
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
if (md->type == eModifierType_ParticleSystem) {
|
||||
sync.sync_curves(ob, ob_handle, res_handle, md);
|
||||
ParticleSystem *particle_sys = reinterpret_cast<ParticleSystemModifierData *>(md)->psys;
|
||||
ParticleSettings *part_settings = particle_sys->part;
|
||||
const int draw_as = (part_settings->draw_as == PART_DRAW_REND) ? part_settings->ren_as :
|
||||
part_settings->draw_as;
|
||||
if (draw_as != PART_DRAW_PATH ||
|
||||
!DRW_object_is_visible_psys_in_active_context(ob, particle_sys)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectHandle _ob_handle = {0};
|
||||
_ob_handle.object_key = ObjectKey(ob_handle.object_key.ob, sub_key++);
|
||||
_ob_handle.recalc = particle_sys->recalc;
|
||||
ResourceHandle _res_handle = manager->resource_handle(float4x4(ob->object_to_world));
|
||||
|
||||
sync.sync_curves(ob, _ob_handle, _res_handle, md, particle_sys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +225,8 @@ void Instance::object_sync(Object *ob)
|
|||
case OB_MESH:
|
||||
sync.sync_mesh(ob, ob_handle, res_handle, ob_ref);
|
||||
break;
|
||||
case OB_POINTCLOUD:
|
||||
sync.sync_point_cloud(ob, ob_handle, res_handle, ob_ref);
|
||||
case OB_VOLUME:
|
||||
break;
|
||||
case OB_CURVES:
|
||||
|
@ -268,9 +287,7 @@ void Instance::render_sync()
|
|||
/* TODO: Remove old draw manager calls. */
|
||||
DRW_render_instance_buffer_finish();
|
||||
|
||||
/* Also we weed to have a correct FBO bound for #DRW_hair_update */
|
||||
// GPU_framebuffer_bind();
|
||||
// DRW_hair_update();
|
||||
DRW_curves_update();
|
||||
}
|
||||
|
||||
bool Instance::do_probe_sync() const
|
||||
|
|
|
@ -39,6 +39,7 @@ enum eMaterialPipeline {
|
|||
|
||||
enum eMaterialGeometry {
|
||||
MAT_GEOM_MESH = 0,
|
||||
MAT_GEOM_POINT_CLOUD,
|
||||
MAT_GEOM_CURVES,
|
||||
MAT_GEOM_GPENCIL,
|
||||
MAT_GEOM_VOLUME,
|
||||
|
@ -102,6 +103,8 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob)
|
|||
return MAT_GEOM_VOLUME;
|
||||
case OB_GPENCIL_LEGACY:
|
||||
return MAT_GEOM_GPENCIL;
|
||||
case OB_POINTCLOUD:
|
||||
return MAT_GEOM_POINT_CLOUD;
|
||||
default:
|
||||
return MAT_GEOM_MESH;
|
||||
}
|
||||
|
|
|
@ -127,6 +127,8 @@ void Sampling::step()
|
|||
/* TODO de-correlate. */
|
||||
data_.dimensions[SAMPLING_AO_U] = r[0];
|
||||
data_.dimensions[SAMPLING_AO_V] = r[1];
|
||||
/* TODO de-correlate. */
|
||||
data_.dimensions[SAMPLING_CURVES_U] = r[0];
|
||||
}
|
||||
{
|
||||
/* Using leaped Halton sequence so we can reused the same primes as lens. */
|
||||
|
|
|
@ -314,6 +314,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
|||
case MAT_GEOM_MESH:
|
||||
/** Noop. */
|
||||
break;
|
||||
case MAT_GEOM_POINT_CLOUD:
|
||||
case MAT_GEOM_CURVES:
|
||||
/** Hair attributes come from sampler buffer. Transfer attributes to sampler. */
|
||||
for (auto &input : info.vertex_inputs_) {
|
||||
|
@ -382,8 +383,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
|||
}
|
||||
|
||||
{
|
||||
/* Only mesh and curves support vertex displacement for now. */
|
||||
if (ELEM(geometry_type, MAT_GEOM_MESH, MAT_GEOM_CURVES, MAT_GEOM_GPENCIL)) {
|
||||
if (!ELEM(geometry_type, MAT_GEOM_WORLD, MAT_GEOM_VOLUME)) {
|
||||
vert_gen << "vec3 nodetree_displacement()\n";
|
||||
vert_gen << "{\n";
|
||||
vert_gen << ((codegen.displacement) ? codegen.displacement : "return vec3(0);\n");
|
||||
|
@ -444,6 +444,9 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
|
|||
case MAT_GEOM_MESH:
|
||||
info.additional_info("eevee_geom_mesh");
|
||||
break;
|
||||
case MAT_GEOM_POINT_CLOUD:
|
||||
info.additional_info("eevee_geom_point_cloud");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Pipeline Info. */
|
||||
|
|
|
@ -101,6 +101,7 @@ enum eSamplingDimension : uint32_t {
|
|||
SAMPLING_RAYTRACE_X = 18u,
|
||||
SAMPLING_AO_U = 19u,
|
||||
SAMPLING_AO_V = 20u,
|
||||
SAMPLING_CURVES_U = 21u,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1094,6 +1095,14 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer)
|
|||
{
|
||||
return textureLod(util_tx, float3(uv, layer), 0.0);
|
||||
}
|
||||
|
||||
/* Sample at uv position but with scale and bias so that uv space bounds lie on texel centers. */
|
||||
float4 utility_tx_sample_lut(sampler2DArray util_tx, float2 uv, float layer)
|
||||
{
|
||||
/* Scale and bias coordinates, for correct filtered lookup. */
|
||||
uv = uv * ((UTIL_TEX_SIZE - 1.0) / UTIL_TEX_SIZE) + (0.5 / UTIL_TEX_SIZE);
|
||||
return textureLod(util_tx, float3(uv, layer), 0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
#include "draw_common.hh"
|
||||
|
||||
#include "eevee_instance.hh"
|
||||
|
||||
namespace blender::eevee {
|
||||
|
@ -154,6 +156,49 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Point Cloud
|
||||
* \{ */
|
||||
|
||||
void SyncModule::sync_point_cloud(Object *ob,
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
const ObjectRef &ob_ref)
|
||||
{
|
||||
int material_slot = 1;
|
||||
|
||||
bool has_motion = inst_.velocity.step_object_sync(
|
||||
ob, ob_handle.object_key, res_handle, ob_handle.recalc);
|
||||
|
||||
Material &material = inst_.materials.material_get(
|
||||
ob, has_motion, material_slot - 1, MAT_GEOM_POINT_CLOUD);
|
||||
|
||||
auto drawcall_add = [&](MaterialPass &matpass) {
|
||||
if (matpass.sub_pass == nullptr) {
|
||||
return;
|
||||
}
|
||||
PassMain::Sub &object_pass = matpass.sub_pass->sub("Point Cloud Sub Pass");
|
||||
GPUBatch *geometry = point_cloud_sub_pass_setup(object_pass, ob, matpass.gpumat);
|
||||
object_pass.draw(geometry, res_handle);
|
||||
};
|
||||
|
||||
drawcall_add(material.shading);
|
||||
drawcall_add(material.prepass);
|
||||
drawcall_add(material.shadow);
|
||||
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
GPUMaterial *gpu_material =
|
||||
inst_.materials.material_array_get(ob, has_motion).gpu_materials[material_slot - 1];
|
||||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
||||
bool is_caster = material.shadow.sub_pass != nullptr;
|
||||
bool is_alpha_blend = material.is_alpha_blend_transparent;
|
||||
inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name GPencil
|
||||
* \{ */
|
||||
|
@ -298,52 +343,41 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandl
|
|||
/** \name Hair
|
||||
* \{ */
|
||||
|
||||
static void shgroup_curves_call(MaterialPass &matpass,
|
||||
Object *ob,
|
||||
ParticleSystem *part_sys = nullptr,
|
||||
ModifierData *modifier_data = nullptr)
|
||||
{
|
||||
UNUSED_VARS(ob, modifier_data);
|
||||
if (matpass.sub_pass == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (part_sys != nullptr) {
|
||||
// DRW_shgroup_hair_create_sub(ob, part_sys, modifier_data, matpass.sub_pass, matpass.gpumat);
|
||||
}
|
||||
else {
|
||||
// DRW_shgroup_curves_create_sub(ob, matpass.sub_pass, matpass.gpumat);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncModule::sync_curves(Object *ob,
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
ModifierData *modifier_data)
|
||||
ModifierData *modifier_data,
|
||||
ParticleSystem *particle_sys)
|
||||
{
|
||||
UNUSED_VARS(res_handle);
|
||||
int mat_nr = CURVES_MATERIAL_NR;
|
||||
|
||||
ParticleSystem *part_sys = nullptr;
|
||||
if (modifier_data != nullptr) {
|
||||
part_sys = reinterpret_cast<ParticleSystemModifierData *>(modifier_data)->psys;
|
||||
if (!DRW_object_is_visible_psys_in_active_context(ob, part_sys)) {
|
||||
return;
|
||||
}
|
||||
ParticleSettings *part_settings = part_sys->part;
|
||||
const int draw_as = (part_settings->draw_as == PART_DRAW_REND) ? part_settings->ren_as :
|
||||
part_settings->draw_as;
|
||||
if (draw_as != PART_DRAW_PATH) {
|
||||
return;
|
||||
}
|
||||
mat_nr = part_settings->omat;
|
||||
if (particle_sys != nullptr) {
|
||||
mat_nr = particle_sys->part->omat;
|
||||
}
|
||||
|
||||
bool has_motion = inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc);
|
||||
bool has_motion = inst_.velocity.step_object_sync(
|
||||
ob, ob_handle.object_key, res_handle, ob_handle.recalc, modifier_data, particle_sys);
|
||||
Material &material = inst_.materials.material_get(ob, has_motion, mat_nr - 1, MAT_GEOM_CURVES);
|
||||
|
||||
shgroup_curves_call(material.shading, ob, part_sys, modifier_data);
|
||||
shgroup_curves_call(material.prepass, ob, part_sys, modifier_data);
|
||||
shgroup_curves_call(material.shadow, ob, part_sys, modifier_data);
|
||||
auto drawcall_add = [&](MaterialPass &matpass) {
|
||||
if (matpass.sub_pass == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (particle_sys != nullptr) {
|
||||
PassMain::Sub &sub_pass = matpass.sub_pass->sub("Hair SubPass");
|
||||
GPUBatch *geometry = hair_sub_pass_setup(
|
||||
sub_pass, inst_.scene, ob, particle_sys, modifier_data, matpass.gpumat);
|
||||
sub_pass.draw(geometry, res_handle);
|
||||
}
|
||||
else {
|
||||
PassMain::Sub &sub_pass = matpass.sub_pass->sub("Curves SubPass");
|
||||
GPUBatch *geometry = curves_sub_pass_setup(sub_pass, inst_.scene, ob, matpass.gpumat);
|
||||
sub_pass.draw(geometry, res_handle);
|
||||
}
|
||||
};
|
||||
|
||||
drawcall_add(material.shading);
|
||||
drawcall_add(material.prepass);
|
||||
drawcall_add(material.shadow);
|
||||
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
GPUMaterial *gpu_material =
|
||||
|
@ -351,9 +385,6 @@ void SyncModule::sync_curves(Object *ob,
|
|||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
||||
/* TODO(fclem) Hair velocity. */
|
||||
// shading_passes.velocity.gpencil_add(ob, ob_handle);
|
||||
|
||||
bool is_caster = material.shadow.sub_pass != nullptr;
|
||||
bool is_alpha_blend = material.is_alpha_blend_transparent;
|
||||
inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend);
|
||||
|
|
|
@ -40,15 +40,15 @@ struct ObjectKey {
|
|||
Object *parent;
|
||||
/** Dupli objects recursive unique identifier */
|
||||
int id[MAX_DUPLI_RECUR];
|
||||
/** If object uses particle system hair. */
|
||||
bool use_particle_hair;
|
||||
/** Used for particle system hair. */
|
||||
int sub_key_;
|
||||
#ifdef DEBUG
|
||||
char name[64];
|
||||
#endif
|
||||
ObjectKey() : ob(nullptr), parent(nullptr){};
|
||||
|
||||
ObjectKey(Object *ob_, Object *parent_, int id_[MAX_DUPLI_RECUR], bool use_particle_hair_)
|
||||
: ob(ob_), parent(parent_), use_particle_hair(use_particle_hair_)
|
||||
ObjectKey(Object *ob_, Object *parent_, int id_[MAX_DUPLI_RECUR], int sub_key_ = 0)
|
||||
: ob(ob_), parent(parent_), sub_key_(sub_key_)
|
||||
{
|
||||
if (id_) {
|
||||
memcpy(id, id_, sizeof(id));
|
||||
|
@ -67,16 +67,19 @@ struct ObjectKey {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (sub_key_ != 0) {
|
||||
hash_value = BLI_ghashutil_combine_hash(hash_value, sub_key_);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
STRNCPY(name, ob->id.name);
|
||||
#endif
|
||||
}
|
||||
|
||||
ObjectKey(Object *ob, DupliObject *dupli, Object *parent)
|
||||
: ObjectKey(ob, parent, dupli ? dupli->persistent_id : nullptr, false){};
|
||||
ObjectKey(Object *ob, DupliObject *dupli, Object *parent, int sub_key_ = 0)
|
||||
: ObjectKey(ob, parent, dupli ? dupli->persistent_id : nullptr, sub_key_){};
|
||||
|
||||
ObjectKey(Object *ob)
|
||||
: ObjectKey(ob, DRW_object_get_dupli(ob), DRW_object_get_dupli_parent(ob)){};
|
||||
ObjectKey(Object *ob, int sub_key_ = 0)
|
||||
: ObjectKey(ob, DRW_object_get_dupli(ob), DRW_object_get_dupli_parent(ob), sub_key_){};
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
|
@ -91,8 +94,8 @@ struct ObjectKey {
|
|||
if (parent != k.parent) {
|
||||
return (parent < k.parent);
|
||||
}
|
||||
if (use_particle_hair != k.use_particle_hair) {
|
||||
return (use_particle_hair < k.use_particle_hair);
|
||||
if (sub_key_ != k.sub_key_) {
|
||||
return (sub_key_ < k.sub_key_);
|
||||
}
|
||||
return memcmp(id, k.id, sizeof(id)) < 0;
|
||||
}
|
||||
|
@ -105,7 +108,7 @@ struct ObjectKey {
|
|||
if (parent != k.parent) {
|
||||
return false;
|
||||
}
|
||||
if (use_particle_hair != k.use_particle_hair) {
|
||||
if (sub_key_ != k.sub_key_) {
|
||||
return false;
|
||||
}
|
||||
return memcmp(id, k.id, sizeof(id)) == 0;
|
||||
|
@ -164,11 +167,16 @@ class SyncModule {
|
|||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
const ObjectRef &ob_ref);
|
||||
void sync_point_cloud(Object *ob,
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
const ObjectRef &ob_ref);
|
||||
void sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle);
|
||||
void sync_curves(Object *ob,
|
||||
ObjectHandle &ob_handle,
|
||||
ResourceHandle res_handle,
|
||||
ModifierData *modifier_data = nullptr);
|
||||
ModifierData *modifier_data = nullptr,
|
||||
ParticleSystem *particle_sys = nullptr);
|
||||
void sync_light_probe(Object *ob, ObjectHandle &ob_handle);
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
#include "BKE_object.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
|
||||
#include "draw_cache_impl.h"
|
||||
|
||||
#include "eevee_instance.hh"
|
||||
// #include "eevee_renderpasses.hh"
|
||||
#include "eevee_shader.hh"
|
||||
|
@ -85,7 +88,9 @@ void VelocityModule::step_camera_sync()
|
|||
bool VelocityModule::step_object_sync(Object *ob,
|
||||
ObjectKey &object_key,
|
||||
ResourceHandle resource_handle,
|
||||
int /*IDRecalcFlag*/ recalc)
|
||||
int /*IDRecalcFlag*/ recalc,
|
||||
ModifierData *modifier_data /*= nullptr*/,
|
||||
ParticleSystem *particle_sys /*= nullptr*/)
|
||||
{
|
||||
bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
|
||||
/* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry
|
||||
|
@ -105,7 +110,7 @@ bool VelocityModule::step_object_sync(Object *ob,
|
|||
VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
|
||||
vel.obj.ofs[step_] = object_steps_usage[step_]++;
|
||||
vel.obj.resource_id = resource_handle.resource_index();
|
||||
vel.id = (ID *)ob->data;
|
||||
vel.id = particle_sys ? &particle_sys->part->id : &ob->id;
|
||||
object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = float4x4_view(ob->object_to_world);
|
||||
if (step_ == STEP_CURRENT) {
|
||||
/* Replace invalid steps. Can happen if object was hidden in one of those steps. */
|
||||
|
@ -125,10 +130,17 @@ bool VelocityModule::step_object_sync(Object *ob,
|
|||
if (has_deform) {
|
||||
auto add_cb = [&]() {
|
||||
VelocityGeometryData data;
|
||||
if (particle_sys) {
|
||||
data.pos_buf = DRW_hair_pos_buffer_get(ob, particle_sys, modifier_data);
|
||||
return data;
|
||||
}
|
||||
switch (ob->type) {
|
||||
case OB_CURVES:
|
||||
data.pos_buf = DRW_curves_pos_buffer_get(ob);
|
||||
break;
|
||||
case OB_POINTCLOUD:
|
||||
data.pos_buf = DRW_pointcloud_position_and_radius_buffer_get(ob);
|
||||
break;
|
||||
default:
|
||||
data.pos_buf = DRW_cache_object_pos_vertbuf_get(ob);
|
||||
break;
|
||||
|
@ -173,7 +185,9 @@ bool VelocityModule::step_object_sync(Object *ob,
|
|||
}
|
||||
|
||||
/* TODO(@fclem): Reset sampling here? Should ultimately be covered by depsgraph update tags. */
|
||||
inst_.sampling.reset();
|
||||
/* NOTE(Miguel Pozo): Disable, since is_deform is always true for objects with particle
|
||||
* modifiers, and this causes the renderer to get stuck at sample 1. */
|
||||
// inst_.sampling.reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,9 @@ class VelocityModule {
|
|||
bool step_object_sync(Object *ob,
|
||||
ObjectKey &object_key,
|
||||
ResourceHandle resource_handle,
|
||||
int recalc = 0);
|
||||
int recalc = 0,
|
||||
ModifierData *modifier_data = nullptr,
|
||||
ParticleSystem *particle_sys = nullptr);
|
||||
|
||||
/* Moves next frame data to previous frame data. Nullify next frame data. */
|
||||
void step_swap();
|
||||
|
|
|
@ -60,6 +60,56 @@ vec3 attr_load_uv(vec3 attr)
|
|||
|
||||
/** \} */
|
||||
|
||||
#elif defined(MAT_GEOM_POINT_CLOUD)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Point Cloud
|
||||
*
|
||||
* Point Cloud objects loads attributes from buffers through sampler buffers.
|
||||
* \{ */
|
||||
|
||||
# pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
|
||||
|
||||
# ifdef OBINFO_LIB
|
||||
vec3 attr_load_orco(vec4 orco)
|
||||
{
|
||||
vec3 P = pointcloud_get_pos();
|
||||
vec3 lP = transform_point(ModelMatrixInverse, P);
|
||||
return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
|
||||
}
|
||||
# endif
|
||||
|
||||
vec4 attr_load_tangent(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec4(cd_buf);
|
||||
}
|
||||
vec3 attr_load_uv(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec3(cd_buf);
|
||||
}
|
||||
vec4 attr_load_color(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec4(cd_buf);
|
||||
}
|
||||
vec4 attr_load_vec4(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec4(cd_buf);
|
||||
}
|
||||
vec3 attr_load_vec3(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec3(cd_buf);
|
||||
}
|
||||
vec2 attr_load_vec2(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_vec2(cd_buf);
|
||||
}
|
||||
float attr_load_float(samplerBuffer cd_buf)
|
||||
{
|
||||
return pointcloud_get_customdata_float(cd_buf);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#elif defined(MAT_GEOM_GPENCIL)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -16,8 +16,6 @@ void main()
|
|||
|
||||
init_interface();
|
||||
|
||||
vec3 T;
|
||||
|
||||
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||
hair_get_pos_tan_binor_time(is_persp,
|
||||
ModelMatrixInverse,
|
||||
|
@ -30,14 +28,15 @@ void main()
|
|||
interp.curves_thickness,
|
||||
interp.curves_time_width);
|
||||
|
||||
interp.N = cross(T, interp.curves_binormal);
|
||||
interp.N = cross(interp.curves_tangent, interp.curves_binormal);
|
||||
interp.curves_strand_id = hair_get_strand_id();
|
||||
interp.barycentric_coords = hair_get_barycentric();
|
||||
#ifdef MAT_VELOCITY
|
||||
/* Due to the screen space nature of the vertex positioning, we compute only the motion of curve
|
||||
* strand, not its cylinder. Otherwise we would add the rotation velocity. */
|
||||
int vert_idx = hair_get_base_id();
|
||||
vec3 prv, nxt, pos = texelFetch(hairPointBuffer, vert_idx).point_position;
|
||||
vec3 prv, nxt;
|
||||
vec3 pos = texelFetch(hairPointBuffer, vert_idx).point_position;
|
||||
velocity_local_pos_get(pos, vert_idx, prv, nxt);
|
||||
/* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
|
||||
* ignores motion from animated displacement. Supporting animated displacement motion vectors
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_rotation_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
DRW_VIEW_FROM_RESOURCE_ID;
|
||||
#ifdef MAT_SHADOW
|
||||
shadow_interp.view_id = drw_view_id;
|
||||
#endif
|
||||
|
||||
init_interface();
|
||||
|
||||
point_cloud_interp.id = pointcloud_get_point_id();
|
||||
pointcloud_get_pos_and_radius(point_cloud_interp.position, point_cloud_interp.radius);
|
||||
pointcloud_get_pos_and_nor(interp.P, interp.N);
|
||||
#ifdef MAT_SHADOW
|
||||
/* Since point clouds always face the view, camera and shadow orientation don't match.
|
||||
* Apply a bias to avoid self-shadow issues. */
|
||||
/* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */
|
||||
float actual_radius = point_cloud_interp.radius * 0.01;
|
||||
interp.P -= cameraVec(interp.P) * actual_radius;
|
||||
#endif
|
||||
|
||||
#ifdef MAT_VELOCITY
|
||||
vec3 lP = point_world_to_object(point_cloud_interp.position);
|
||||
vec3 prv, nxt;
|
||||
velocity_local_pos_get(lP, point_cloud_interp.id, prv, nxt);
|
||||
/* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
|
||||
* ignores motion from animated displacement. Supporting animated displacement motion vectors
|
||||
* would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
|
||||
* different times, but also with different attributes (maybe we could assume static attribute at
|
||||
* least). */
|
||||
velocity_vertex(prv, lP, nxt, motion.prev, motion.next);
|
||||
#endif
|
||||
|
||||
init_globals();
|
||||
attrib_load();
|
||||
|
||||
interp.P += nodetree_displacement();
|
||||
|
||||
gl_Position = point_world_to_ndc(interp.P);
|
||||
}
|
|
@ -235,26 +235,111 @@ float nodetree_thickness();
|
|||
vec4 closure_to_rgba(Closure cl);
|
||||
#endif
|
||||
|
||||
/* Stubs. */
|
||||
vec2 btdf_lut(float a, float b, float c)
|
||||
/* Fresnel monochromatic, perfect mirror */
|
||||
float F_eta(float eta, float cos_theta)
|
||||
{
|
||||
return vec2(1, 0);
|
||||
/* Compute fresnel reflectance without explicitly computing
|
||||
* the refracted direction. */
|
||||
float c = abs(cos_theta);
|
||||
float g = eta * eta - 1.0 + c * c;
|
||||
if (g > 0.0) {
|
||||
g = sqrt(g);
|
||||
float A = (g - c) / (g + c);
|
||||
float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
|
||||
return 0.5 * A * A * (1.0 + B * B);
|
||||
}
|
||||
/* Total internal reflections. */
|
||||
return 1.0;
|
||||
}
|
||||
vec2 brdf_lut(float a, float b)
|
||||
|
||||
/* Simplified form of F_eta(eta, 1.0). */
|
||||
float F0_from_ior(float eta)
|
||||
{
|
||||
return vec2(1, 0);
|
||||
float A = (eta - 1.0) / (eta + 1.0);
|
||||
return A * A;
|
||||
}
|
||||
vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c)
|
||||
|
||||
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
|
||||
vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
return a;
|
||||
return lut.y * f90 + lut.x * f0;
|
||||
}
|
||||
vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c)
|
||||
|
||||
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
|
||||
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
|
||||
{
|
||||
return a;
|
||||
/**
|
||||
* From "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
|
||||
* by Carmelo J. Fdez-Aguera
|
||||
* https://jcgt.org/published/0008/01/03/paper.pdf
|
||||
*/
|
||||
vec3 FssEss = lut.y * f90 + lut.x * f0;
|
||||
|
||||
float Ess = lut.x + lut.y;
|
||||
float Ems = 1.0 - Ess;
|
||||
vec3 Favg = f0 + (1.0 - f0) / 21.0;
|
||||
vec3 Fms = FssEss * Favg / (1.0 - (1.0 - Ess) * Favg);
|
||||
/* We don't do anything special for diffuse surfaces because the principle bsdf
|
||||
* does not care about energy conservation of the specular layer for dielectrics. */
|
||||
return FssEss + Fms * Ems;
|
||||
}
|
||||
float F_eta(float a, float b)
|
||||
|
||||
vec2 brdf_lut(float cos_theta, float roughness)
|
||||
{
|
||||
return a;
|
||||
#ifdef EEVEE_UTILITY_TX
|
||||
return utility_tx_sample_lut(utility_tx, vec2(cos_theta, roughness), UTIL_BSDF_LAYER).rg;
|
||||
#else
|
||||
return vec2(1.0, 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
||||
{
|
||||
if (ior <= 1e-5) {
|
||||
return vec2(0.0);
|
||||
}
|
||||
|
||||
if (ior >= 1.0) {
|
||||
vec2 split_sum = brdf_lut(cos_theta, roughness);
|
||||
float f0 = F0_from_ior(ior);
|
||||
/* Baked IOR for GGX BRDF. */
|
||||
const float specular = 1.0;
|
||||
const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
|
||||
/* Avoid harsh transition coming from ior == 1. */
|
||||
float f90 = fast_sqrt(saturate(f0 / (F0_from_ior(eta_brdf) * 0.25)));
|
||||
float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r;
|
||||
/* Setting the BTDF to one is not really important since it is only used for multiscatter
|
||||
* and it's already quite close to ground truth. */
|
||||
float btdf = 1.0;
|
||||
return vec2(btdf, fresnel);
|
||||
}
|
||||
|
||||
/* IOR is sin of critical angle. */
|
||||
float critical_cos = sqrt(1.0 - ior * ior);
|
||||
|
||||
vec3 coords;
|
||||
coords.x = sqr(ior);
|
||||
coords.y = cos_theta;
|
||||
coords.y -= critical_cos;
|
||||
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
|
||||
coords.y = coords.y * 0.5 + 0.5;
|
||||
coords.z = roughness;
|
||||
|
||||
coords = saturate(coords);
|
||||
|
||||
float layer = coords.z * UTIL_BTDF_LAYER_COUNT;
|
||||
float layer_floored = floor(layer);
|
||||
|
||||
#ifdef EEVEE_UTILITY_TX
|
||||
coords.z = UTIL_BTDF_LAYER + layer_floored;
|
||||
vec2 btdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
|
||||
vec2 btdf_high = utility_tx_sample_lut(utility_tx, coords.xy, coords.z + 1.0).rg;
|
||||
/* Manual trilinear interpolation. */
|
||||
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
|
||||
return btdf;
|
||||
#else
|
||||
return vec2(0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void output_renderpass_color(int id, vec4 color)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
|
||||
#if defined(USE_BARYCENTRICS) && defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_MESH)
|
||||
vec3 barycentric_distances_get()
|
||||
|
@ -39,6 +40,18 @@ void init_globals_curves()
|
|||
{
|
||||
/* Shade as a cylinder. */
|
||||
float cos_theta = interp.curves_time_width / interp.curves_thickness;
|
||||
#if defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_CURVES)
|
||||
if (hairThicknessRes == 1) {
|
||||
/* Random cosine normal distribution on the hair surface. */
|
||||
float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).x;
|
||||
# ifdef EEVEE_SAMPLING_DATA
|
||||
/* Needs to check for SAMPLING_DATA,
|
||||
* otherwise Surfel and World (?!?!) shader validation fails. */
|
||||
noise = fract(noise + sampling_rng_1D_get(SAMPLING_CURVES_U));
|
||||
# endif
|
||||
cos_theta = noise * 2.0 - 1.0;
|
||||
}
|
||||
#endif
|
||||
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
|
||||
g_data.N = g_data.Ni = normalize(interp.N * sin_theta + interp.curves_binormal * cos_theta);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ GPU_SHADER_CREATE_INFO(eevee_sampling_data)
|
|||
.storage_buf(SAMPLING_BUF_SLOT, Qualifier::READ, "SamplingData", "sampling_buf");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_utility_texture)
|
||||
.define("EEVEE_UTILITY_TX")
|
||||
.sampler(RBUFS_UTILITY_TEX_SLOT, ImageType::FLOAT_2D_ARRAY, "utility_tx");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_camera).uniform_buf(CAMERA_BUF_SLOT, "CameraData", "camera_buf");
|
||||
|
@ -38,6 +39,25 @@ GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
|
|||
.vertex_source("eevee_geom_mesh_vert.glsl")
|
||||
.additional_info("draw_modelmat_new", "draw_resource_id_varying", "draw_view");
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(eevee_surf_point_cloud_iface, "point_cloud_interp")
|
||||
.smooth(Type::FLOAT, "radius")
|
||||
.smooth(Type::VEC3, "position")
|
||||
.flat(Type::INT, "id");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_geom_point_cloud)
|
||||
.additional_info("eevee_shared")
|
||||
.define("MAT_GEOM_POINT_CLOUD")
|
||||
.vertex_source("eevee_geom_point_cloud_vert.glsl")
|
||||
.vertex_out(eevee_surf_point_cloud_iface)
|
||||
/* TODO(Miguel Pozo): Remove once we get rid of old EEVEE. */
|
||||
.define("pointRadius", "point_cloud_interp.radius")
|
||||
.define("pointPosition", "point_cloud_interp.position")
|
||||
.define("pointID", "point_cloud_interp.id")
|
||||
.additional_info("draw_pointcloud_new",
|
||||
"draw_modelmat_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_view");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
|
||||
.additional_info("eevee_shared")
|
||||
.define("MAT_GEOM_GPENCIL")
|
||||
|
@ -48,10 +68,11 @@ GPU_SHADER_CREATE_INFO(eevee_geom_curves)
|
|||
.additional_info("eevee_shared")
|
||||
.define("MAT_GEOM_CURVES")
|
||||
.vertex_source("eevee_geom_curves_vert.glsl")
|
||||
.additional_info("draw_hair",
|
||||
"draw_curves_infos",
|
||||
.additional_info("draw_modelmat_new",
|
||||
"draw_resource_id_varying",
|
||||
"draw_resource_id_new");
|
||||
"draw_view",
|
||||
"draw_hair_new",
|
||||
"draw_curves_infos");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_geom_world)
|
||||
.additional_info("eevee_shared")
|
||||
|
@ -223,7 +244,8 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub)
|
|||
EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
|
||||
EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
|
||||
EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \
|
||||
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
|
||||
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__) \
|
||||
EEVEE_MAT_FINAL_VARIATION(prefix##_point_cloud, "eevee_geom_point_cloud", __VA_ARGS__)
|
||||
|
||||
# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
|
||||
EEVEE_MAT_GEOM_VARIATIONS(name##_world, "eevee_surf_world", __VA_ARGS__) \
|
||||
|
|
|
@ -152,6 +152,8 @@ void DRW_curves_batch_cache_create_requested(struct Object *ob);
|
|||
|
||||
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
|
||||
|
||||
struct GPUVertBuf *DRW_pointcloud_position_and_radius_buffer_get(struct Object *ob);
|
||||
|
||||
struct GPUVertBuf **DRW_pointcloud_evaluated_attribute(struct PointCloud *pointcloud,
|
||||
const char *name);
|
||||
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
|
||||
|
|
|
@ -387,6 +387,12 @@ GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob)
|
|||
return DRW_batch_request(&cache->eval_cache.dots);
|
||||
}
|
||||
|
||||
GPUVertBuf *DRW_pointcloud_position_and_radius_buffer_get(Object *ob)
|
||||
{
|
||||
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
|
||||
return pointcloud_position_and_radius_get(&pointcloud);
|
||||
}
|
||||
|
||||
GPUVertBuf **DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, const char *name)
|
||||
{
|
||||
PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud);
|
||||
|
|
|
@ -410,6 +410,18 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
|
|||
|
||||
void DRW_curves_update()
|
||||
{
|
||||
|
||||
/* Ensure there's a valid active view.
|
||||
* "Next" engines use this function, but this still uses the old Draw Manager. */
|
||||
if (DRW_view_default_get() == nullptr) {
|
||||
/* Create a dummy default view, it's not really used. */
|
||||
DRW_view_default_set(DRW_view_create(
|
||||
float4x4::identity().ptr(), float4x4::identity().ptr(), nullptr, nullptr, nullptr));
|
||||
}
|
||||
if (DRW_view_get_active() == nullptr) {
|
||||
DRW_view_set_active(DRW_view_default_get());
|
||||
}
|
||||
|
||||
/* Update legacy hair too, to avoid verbosity in callers. */
|
||||
DRW_hair_update();
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ void DRW_pointcloud_free()
|
|||
}
|
||||
|
||||
#include "draw_common.hh"
|
||||
/* For drw_curves_get_attribute_sampler_name. */
|
||||
#include "draw_curves_private.hh"
|
||||
namespace blender::draw {
|
||||
|
||||
template<typename PassT>
|
||||
|
@ -119,14 +121,20 @@ GPUBatch *point_cloud_sub_pass_setup_implementation(PassT &sub_ps,
|
|||
sub_ps.bind_texture("ptcloud_pos_rad_tx", pos_rad_buf);
|
||||
|
||||
if (gpu_material != nullptr) {
|
||||
/* Only single material supported for now. */
|
||||
GPUBatch **geom = pointcloud_surface_shaded_get(&pointcloud, &gpu_material, 1);
|
||||
return geom[0];
|
||||
}
|
||||
else {
|
||||
GPUBatch *geom = pointcloud_surface_get(&pointcloud);
|
||||
return geom;
|
||||
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
|
||||
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
|
||||
GPUVertBuf **attribute_buf = DRW_pointcloud_evaluated_attribute(&pointcloud, gpu_attr->name);
|
||||
if (attribute_buf) {
|
||||
char sampler_name[32];
|
||||
/** NOTE: Reusing curve attribute function. */
|
||||
drw_curves_get_attribute_sampler_name(gpu_attr->name, sampler_name);
|
||||
sub_ps.bind_texture(sampler_name, attribute_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GPUBatch *geom = pointcloud_surface_get(&pointcloud);
|
||||
return geom;
|
||||
}
|
||||
|
||||
GPUBatch *point_cloud_sub_pass_setup(PassMain::Sub &sub_ps,
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
|
||||
int pointcloud_get_point_id()
|
||||
{
|
||||
# ifdef GPU_VERTEX_SHADER
|
||||
return gl_VertexID / 32;
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
mat3 pointcloud_get_facing_matrix(vec3 p)
|
||||
|
@ -40,8 +43,12 @@ void pointcloud_get_pos_nor_radius(out vec3 outpos, out vec3 outnor, out float o
|
|||
|
||||
mat3 facing_mat = pointcloud_get_facing_matrix(p);
|
||||
|
||||
int vert_id = 0;
|
||||
# ifdef GPU_VERTEX_SHADER
|
||||
/* NOTE: Avoid modulo by non-power-of-two in shader. See Index buffer setup. */
|
||||
int vert_id = gl_VertexID % 32;
|
||||
vert_id = gl_VertexID % 32;
|
||||
# endif
|
||||
|
||||
vec3 pos_inst = vec3(0.0);
|
||||
|
||||
switch (vert_id) {
|
||||
|
|
Loading…
Reference in New Issue