Particles: initial support for the Time input node

This commit is contained in:
Jacques Lucke 2020-07-28 12:03:02 +02:00
parent c8e45c3fe9
commit 3b9e16a4f7
5 changed files with 104 additions and 12 deletions

View File

@ -487,7 +487,7 @@ simulation_node_categories = [
NodeItem("SimulationNodeParticleSimulation"),
]),
SimulationNodeCategory("SIM_INPUTS", "Input", items=[
not_implemented_node("SimulationNodeTime"),
NodeItem("SimulationNodeTime"),
NodeItem("SimulationNodeParticleAttribute"),
NodeItem("FunctionNodeGroupInstanceID"),
NodeItem("ShaderNodeValue"),

View File

@ -79,6 +79,12 @@ class ResourceCollector : NonCopyable, NonMovable {
*/
template<typename T> void add(destruct_ptr<T> resource, const char *name)
{
/* There is no need to keep track of such types. */
if (std::is_trivially_destructible_v<T>) {
resource.release();
return;
}
BLI_assert(resource.get() != nullptr);
this->add(
resource.release(),

View File

@ -116,8 +116,9 @@ void ParticleFunctionEvaluator::compute_globals()
fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size());
/* Add input parameters. */
ParticleFunctionInputContext input_context{solve_context_, particles_};
for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
input->add_input(particles_.attributes, params, resources_);
input->add_input(input_context, params, resources_);
}
/* Add output parameters. */
@ -143,8 +144,9 @@ void ParticleFunctionEvaluator::compute_per_particle()
fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size());
/* Add input parameters. */
ParticleFunctionInputContext input_context{solve_context_, particles_};
for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
input->add_input(particles_.attributes, params, resources_);
input->add_input(input_context, params, resources_);
}
/* Add output parameters. */

View File

@ -26,10 +26,15 @@
namespace blender::sim {
struct ParticleFunctionInputContext {
const SimulationSolveContext &solve_context;
const ParticleChunkContext &particles;
};
class ParticleFunctionInput {
public:
virtual ~ParticleFunctionInput() = default;
virtual void add_input(fn::AttributesRef attributes,
virtual void add_input(ParticleFunctionInputContext &context,
fn::MFParamsBuilder &params,
ResourceCollector &resources) const = 0;
};

View File

@ -28,12 +28,15 @@
#include "BLI_hash.h"
#include "BLI_rand.hh"
#include "BLI_set.hh"
namespace blender::sim {
using fn::GVSpan;
using fn::MFContextBuilder;
using fn::MFDataType;
using fn::MFDummyNode;
using fn::MFFunctionNode;
using fn::MFInputSocket;
using fn::MFNetwork;
using fn::MFNetworkEvaluator;
@ -53,6 +56,8 @@ using nodes::NodeTreeRefMap;
struct DummyDataSources {
Map<const MFOutputSocket *, std::string> particle_attributes;
Set<const MFOutputSocket *> simulation_time;
Set<const MFOutputSocket *> scene_time;
};
extern "C" {
@ -226,6 +231,47 @@ static void prepare_particle_attribute_nodes(CollectContext &context)
}
}
static void prepare_time_input_nodes(CollectContext &context)
{
Span<const DNode *> time_input_dnodes = nodes_by_type(context, "SimulationNodeTime");
Vector<const DNode *> simulation_time_inputs;
Vector<const DNode *> scene_time_inputs;
for (const DNode *dnode : time_input_dnodes) {
NodeSimInputTimeType type = (NodeSimInputTimeType)dnode->node_ref().bnode()->custom1;
switch (type) {
case NODE_SIM_INPUT_SIMULATION_TIME: {
simulation_time_inputs.append(dnode);
break;
}
case NODE_SIM_INPUT_SCENE_TIME: {
scene_time_inputs.append(dnode);
break;
}
}
}
if (simulation_time_inputs.size() > 0) {
MFOutputSocket &new_socket = context.network.add_input("Simulation Time",
MFDataType::ForSingle<float>());
for (const DNode *dnode : simulation_time_inputs) {
MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
context.network.relink(old_socket, new_socket);
context.network.remove(old_socket.node());
}
context.data_sources.simulation_time.add(&new_socket);
}
if (scene_time_inputs.size() > 0) {
MFOutputSocket &new_socket = context.network.add_input("Scene Time",
MFDataType::ForSingle<float>());
for (const DNode *dnode : scene_time_inputs) {
MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
context.network.relink(old_socket, new_socket);
context.network.remove(old_socket.node());
}
context.data_sources.scene_time.add(&new_socket);
}
}
class ParticleAttributeInput : public ParticleFunctionInput {
private:
std::string attribute_name_;
@ -237,11 +283,12 @@ class ParticleAttributeInput : public ParticleFunctionInput {
{
}
void add_input(AttributesRef attributes,
void add_input(ParticleFunctionInputContext &context,
MFParamsBuilder &params,
ResourceCollector &UNUSED(resources)) const override
{
std::optional<GSpan> span = attributes.try_get(attribute_name_, attribute_type_);
std::optional<GSpan> span = context.particles.attributes.try_get(attribute_name_,
attribute_type_);
if (span.has_value()) {
params.add_readonly_single_input(*span);
}
@ -251,6 +298,29 @@ class ParticleAttributeInput : public ParticleFunctionInput {
}
};
class SceneTimeInput : public ParticleFunctionInput {
void add_input(ParticleFunctionInputContext &context,
MFParamsBuilder &params,
ResourceCollector &resources) const override
{
const float time = DEG_get_ctime(&context.solve_context.depsgraph);
float *time_ptr = &resources.construct<float>(AT, time);
params.add_readonly_single_input(time_ptr);
}
};
class SimulationTimeInput : public ParticleFunctionInput {
void add_input(ParticleFunctionInputContext &context,
MFParamsBuilder &params,
ResourceCollector &resources) const override
{
/* TODO: Vary this per particle. */
const float time = context.solve_context.solve_interval.stop();
float *time_ptr = &resources.construct<float>(AT, time);
params.add_readonly_single_input(time_ptr);
}
};
static const ParticleFunction *create_particle_function_for_inputs(
CollectContext &context, Span<const MFInputSocket *> sockets_to_compute)
{
@ -264,13 +334,21 @@ static const ParticleFunction *create_particle_function_for_inputs(
Vector<const ParticleFunctionInput *> per_particle_inputs;
for (const MFOutputSocket *socket : dummy_deps) {
const std::string *attribute_name = context.data_sources.particle_attributes.lookup_ptr(
socket);
if (attribute_name == nullptr) {
return nullptr;
if (context.data_sources.particle_attributes.contains(socket)) {
const std::string *attribute_name = context.data_sources.particle_attributes.lookup_ptr(
socket);
if (attribute_name == nullptr) {
return nullptr;
}
per_particle_inputs.append(&context.resources.construct<ParticleAttributeInput>(
AT, *attribute_name, socket->data_type().single_type()));
}
else if (context.data_sources.scene_time.contains(socket)) {
per_particle_inputs.append(&context.resources.construct<SceneTimeInput>(AT));
}
else if (context.data_sources.simulation_time.contains(socket)) {
per_particle_inputs.append(&context.resources.construct<SimulationTimeInput>(AT));
}
per_particle_inputs.append(&context.resources.construct<ParticleAttributeInput>(
AT, *attribute_name, socket->data_type().single_type()));
}
const MultiFunction &per_particle_fn = context.resources.construct<MFNetworkEvaluator>(
@ -689,6 +767,7 @@ void collect_simulation_influences(Simulation &simulation,
initialize_particle_attribute_builders(context);
prepare_particle_attribute_nodes(context);
prepare_time_input_nodes(context);
collect_forces(context);
collect_emitters(context);