solaris nebula effect
23928 24 7- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- tallkien
- Member
- 225 posts
- Joined: July 2005
- Offline
Here's an interesting idea I've taken a shot at reimplementing in houdini, with some interesting results. I don't have houdini with me now but you can play around with this for some fun in the meantime
http://www.escapemotions.com/experiments/flame/index.html#top [escapemotions.com]
http://www.escapemotions.com/experiments/flame/index.html#top [escapemotions.com]
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
Thanks for posting your interactive flame-thing. It was a help.
Here's my first attempt:
http://toonlets.com/work/tube.jpg [toonlets.com]
chris
Here's my first attempt:
http://toonlets.com/work/tube.jpg [toonlets.com]
chris
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
- probbins
- Member
- 1145 posts
- Joined: July 2005
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- toonlets
- Member
- 15 posts
- Joined: March 2010
- Offline
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
Here it is.
#ifdef LINUX
#define DLLEXPORT
#define SIZEOF_VOID_P 8
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#define MAKING_DSO
// CRT
#include <limits.h>
#include <strstream>
#include <iostream>
using namespace std;
// H
#include <UT/UT_DSOVersion.h>
#include <GU/GU_Detail.h>
#include <OBJ/OBJ_Node.h>
#include <SOP/SOP_Node.h>
#include <PRM/PRM_Include.h>
#include <PRM/PRM_SpareData.h>
#include <PRM/PRM_ChoiceList.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <UT/UT_Vector3.h>
class SOP_Scallop :
public SOP_Node
{
public:
SOP_Scallop(OP_Network *net, const char *name, OP_Operator *entry) : SOP_Node(net,name,entry) {};
virtual ~SOP_Scallop() {};
static OP_Node *creator(OP_Network *net, const char *name, OP_Operator *entry);
static PRM_Template templateList;
protected:
virtual OP_ERROR cookMySop (OP_Context &context);
};
static PRM_Name bindnames =
{
PRM_Name(“obj#”, “OBJ Path”),
PRM_Name(“model#”, “Model”),
PRM_Name(“weight#”, “Weight”),
PRM_Name(“color#”, “Color”),
PRM_Name(“daemons”, “Number of Daemons”),
PRM_Name(0)
};
static PRM_Name modelNames =
{
PRM_Name(“linear”, “Linear”),
PRM_Name(“spherical”, “Spherical”),
PRM_Name(“polar”, “Polar”),
PRM_Name(“swirl”, “Swirl”),
PRM_Name(“trig”, “Trigonometric”),
PRM_Name(0)
};
static PRM_ChoiceList modelMenu(PRM_CHOICELIST_SINGLE, modelNames);
static PRM_Template theBindTemplates =
{
PRM_Template(PRM_STRING, PRM_TYPE_DYNAMIC_PATH, 1, &bindnames, 0, 0, 0, 0, &PRM_SpareData:bjGeometryPath),
PRM_Template(PRM_ORD, PRM_Template:RM_EXPORT_MAX, 1,&bindnames, 0, &modelMenu),
PRM_Template(PRM_FLT, 1, &bindnames),
PRM_Template(PRM_RGB, 3, &bindnames),
PRM_Template()
};
static PRM_Default switcherInfo = {
PRM_Default( 2, “Setup”),
PRM_Default( 1, “Daemons”)
};
PRM_Name savePathName(“path”,“Path”);
PRM_Default savePathDef(0,“”);
PRM_Name countName(“count”,“Count”);
PRM_Default countDef(1000,“”);
PRM_Name visibleName(“showpts”,“Show Points”);
PRM_Name visibleSizeName(“ptssz”,“Point Size”);
PRM_Template SOP_Scallop::templateList=
{
PRM_Template(PRM_SWITCHER_EXCLUSIVE,2, &PRMswitcherName, switcherInfo),
// SPOOL SETUP
PRM_Template(PRM_FILE,1,&savePathName,&savePathDef),
PRM_Template(PRM_INT,1,&countName,&countDef),
// DAEMONS
PRM_Template(PRM_MULTITYPE_LIST,
theBindTemplates, 4, &bindnames,
PRMzeroDefaults, 0, &PRM_SpareData::multiStartOffsetOne),
// RECENT
PRM_Template(PRM_TOGGLE,1,&visibleName,PRMoneDefaults),
PRM_Template(PRM_INT,1,&visibleSizeName,PRMtwoDefaults),
PRM_Template()
};
OP_Node *SOP_Scallop::creator(OP_Network *net,const char *name,OP_Operator *entry)
{
return new SOP_Scallop(net, name, entry);
};
struct Methods
{
static void Linear(float*) {};
static void Spherical(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
if(Len!=0) { _P /= Len; _P /= Len; _P /= Len+_P; };
};
static void Polar(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
_P = atan2(_P,_P); _P = Len;
};
static void Swirl(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
_P = Len*cos(Len); _P = Len*sin(Len);
};
static void Trigonometric(float*_P)
{
_P = cos(abs(_P+_P))-abs(sin(_P+_P));
_P = cos(_P);
_P = sin(_P);
};
};
typedef void (*NonLinear)(float*);
struct Daemon
{
NonLinear method;
UT_Matrix4 xform;
float c;
float weight;
float range;
bool Transform(float w, UT_Vector3& P, float* C);
Daemon() : method(Methods::Linear) { range=0; range=0; };
};
bool Daemon::Transform(float w, UT_Vector3& P, float* C)
{
if(w<range) return false;
if(w>=range) return false;
P = P*xform;
method(P.vec);
C=C+0.333*(c-C);
C=C+0.333*(c-C);
C=C+0.333*(c-C);
return true;
};
OP_ERROR SOP_Scallop::cookMySop(OP_Context &context)
{
//OP_Node::flags().timeDep = 1;
float now = context.getTime();
gdp->clearAndDestroy();
bool showPts = (evalInt(“showpts”,0,now)!=0);
if(showPts)
{
float sz = evalInt(“ptssz”,0,now);
if(sz > 0)
{
float one = 1.0f;
gdp->addAttrib(“showpoints”,4,GB_ATTRIB_FLOAT,&one);
gdp->addAttrib(“revealsize”,4,GB_ATTRIB_FLOAT,&sz);
};
};
int cnt = evalInt(“daemons”, 0, now);
//QList<Daemon> daemons;
Daemon* daemons=new Daemon;
float weights = 0;
int totd=0;
for(int i=1;i<=cnt;i++)
{
Daemon& d = daemons;
UT_String path = “”;
evalStringInst(“obj#”, &i, path, 0, now);
if(path == “”) continue;
SOP_Node* node = getSOPNode(path);
OBJ_Node* obj = dynamic_cast<OBJ_Node*>(node->getParent());
if(obj == NULL) continue;
addExtraInput(obj, OP_INTEREST_DATA);
d.xform = obj->getWorldTransform(context);
d.weight = evalFloatInst(“weight#”,&i,0,now);
d.c = evalFloatInst(“color#”,&i,0,now);
d.c = evalFloatInst(“color#”,&i,1,now);
d.c = evalFloatInst(“color#”,&i,2,now);
int mth = evalIntInst(“model#”,&i,0,now);
switch(mth)
{
case 1:
d.method = Methods:pherical;
break;
case 2:
d.method = Methods:olar;
break;
case 3:
d.method = Methods:wirl;
break;
case 4:
d.method = Methods::Trigonometric;
break;
case 0:
default:
d.method = Methods::Linear;
};
weights+=d.weight;
totd++;
};
if(totd == 0)
{
delete daemons;
return error();
}
float base = 0.0;
for(int i=0;i<totd;i++)
{
Daemon& d = daemons;
d.range=base;
d.range = base+d.weight/weights;
base=d.range;
};
int total = evalInt(“count”,0,now);
int dt = gdp->addDiffuseAttribute(GEO_POINT_DICT);
UT_Vector3 current(0,0,0);
float C = { 0,0,0 };
srand(0);
for(int i=-50;i<total;i++)
{
bool ok = false;
float w = double(rand())/double(RAND_MAX);
for(int j=0;j<totd;j++)
{
ok = daemons.Transform(w,current,C);
if(ok) break;
};
if(i<0) continue;
if(ok)
{
GEO_Point* p = gdp->appendPoint();
p->setPos(current);
float* Cd=p->castAttribData<float>(dt);
memcpy(Cd,C,12);
};
};
delete daemons;
return error();
}
void newSopOperator(OP_OperatorTable *table)
{
table->addOperator(new OP_Operator(
“hdk_scallop”,“Scallop”,
SOP_Scallop::creator,SOP_Scallop::templateList,
0,1));
}
We reimplemented our tool at Houdini, excluding Pixar's pointcloud export, which is produced by another node. You may play with different Non-linear formulas, which may be plugged easily. I don't think, that using CVEX as non-linear kernel will allow to build pointclouds very fast, but you may add such features too. Good luck!
Sample scene attached.
#ifdef LINUX
#define DLLEXPORT
#define SIZEOF_VOID_P 8
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#define MAKING_DSO
// CRT
#include <limits.h>
#include <strstream>
#include <iostream>
using namespace std;
// H
#include <UT/UT_DSOVersion.h>
#include <GU/GU_Detail.h>
#include <OBJ/OBJ_Node.h>
#include <SOP/SOP_Node.h>
#include <PRM/PRM_Include.h>
#include <PRM/PRM_SpareData.h>
#include <PRM/PRM_ChoiceList.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <UT/UT_Vector3.h>
class SOP_Scallop :
public SOP_Node
{
public:
SOP_Scallop(OP_Network *net, const char *name, OP_Operator *entry) : SOP_Node(net,name,entry) {};
virtual ~SOP_Scallop() {};
static OP_Node *creator(OP_Network *net, const char *name, OP_Operator *entry);
static PRM_Template templateList;
protected:
virtual OP_ERROR cookMySop (OP_Context &context);
};
static PRM_Name bindnames =
{
PRM_Name(“obj#”, “OBJ Path”),
PRM_Name(“model#”, “Model”),
PRM_Name(“weight#”, “Weight”),
PRM_Name(“color#”, “Color”),
PRM_Name(“daemons”, “Number of Daemons”),
PRM_Name(0)
};
static PRM_Name modelNames =
{
PRM_Name(“linear”, “Linear”),
PRM_Name(“spherical”, “Spherical”),
PRM_Name(“polar”, “Polar”),
PRM_Name(“swirl”, “Swirl”),
PRM_Name(“trig”, “Trigonometric”),
PRM_Name(0)
};
static PRM_ChoiceList modelMenu(PRM_CHOICELIST_SINGLE, modelNames);
static PRM_Template theBindTemplates =
{
PRM_Template(PRM_STRING, PRM_TYPE_DYNAMIC_PATH, 1, &bindnames, 0, 0, 0, 0, &PRM_SpareData:bjGeometryPath),
PRM_Template(PRM_ORD, PRM_Template:RM_EXPORT_MAX, 1,&bindnames, 0, &modelMenu),
PRM_Template(PRM_FLT, 1, &bindnames),
PRM_Template(PRM_RGB, 3, &bindnames),
PRM_Template()
};
static PRM_Default switcherInfo = {
PRM_Default( 2, “Setup”),
PRM_Default( 1, “Daemons”)
};
PRM_Name savePathName(“path”,“Path”);
PRM_Default savePathDef(0,“”);
PRM_Name countName(“count”,“Count”);
PRM_Default countDef(1000,“”);
PRM_Name visibleName(“showpts”,“Show Points”);
PRM_Name visibleSizeName(“ptssz”,“Point Size”);
PRM_Template SOP_Scallop::templateList=
{
PRM_Template(PRM_SWITCHER_EXCLUSIVE,2, &PRMswitcherName, switcherInfo),
// SPOOL SETUP
PRM_Template(PRM_FILE,1,&savePathName,&savePathDef),
PRM_Template(PRM_INT,1,&countName,&countDef),
// DAEMONS
PRM_Template(PRM_MULTITYPE_LIST,
theBindTemplates, 4, &bindnames,
PRMzeroDefaults, 0, &PRM_SpareData::multiStartOffsetOne),
// RECENT
PRM_Template(PRM_TOGGLE,1,&visibleName,PRMoneDefaults),
PRM_Template(PRM_INT,1,&visibleSizeName,PRMtwoDefaults),
PRM_Template()
};
OP_Node *SOP_Scallop::creator(OP_Network *net,const char *name,OP_Operator *entry)
{
return new SOP_Scallop(net, name, entry);
};
struct Methods
{
static void Linear(float*) {};
static void Spherical(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
if(Len!=0) { _P /= Len; _P /= Len; _P /= Len+_P; };
};
static void Polar(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
_P = atan2(_P,_P); _P = Len;
};
static void Swirl(float*_P)
{
float Len = sqrt(_P*_P+_P*_P+_P*_P);
_P = Len*cos(Len); _P = Len*sin(Len);
};
static void Trigonometric(float*_P)
{
_P = cos(abs(_P+_P))-abs(sin(_P+_P));
_P = cos(_P);
_P = sin(_P);
};
};
typedef void (*NonLinear)(float*);
struct Daemon
{
NonLinear method;
UT_Matrix4 xform;
float c;
float weight;
float range;
bool Transform(float w, UT_Vector3& P, float* C);
Daemon() : method(Methods::Linear) { range=0; range=0; };
};
bool Daemon::Transform(float w, UT_Vector3& P, float* C)
{
if(w<range) return false;
if(w>=range) return false;
P = P*xform;
method(P.vec);
C=C+0.333*(c-C);
C=C+0.333*(c-C);
C=C+0.333*(c-C);
return true;
};
OP_ERROR SOP_Scallop::cookMySop(OP_Context &context)
{
//OP_Node::flags().timeDep = 1;
float now = context.getTime();
gdp->clearAndDestroy();
bool showPts = (evalInt(“showpts”,0,now)!=0);
if(showPts)
{
float sz = evalInt(“ptssz”,0,now);
if(sz > 0)
{
float one = 1.0f;
gdp->addAttrib(“showpoints”,4,GB_ATTRIB_FLOAT,&one);
gdp->addAttrib(“revealsize”,4,GB_ATTRIB_FLOAT,&sz);
};
};
int cnt = evalInt(“daemons”, 0, now);
//QList<Daemon> daemons;
Daemon* daemons=new Daemon;
float weights = 0;
int totd=0;
for(int i=1;i<=cnt;i++)
{
Daemon& d = daemons;
UT_String path = “”;
evalStringInst(“obj#”, &i, path, 0, now);
if(path == “”) continue;
SOP_Node* node = getSOPNode(path);
OBJ_Node* obj = dynamic_cast<OBJ_Node*>(node->getParent());
if(obj == NULL) continue;
addExtraInput(obj, OP_INTEREST_DATA);
d.xform = obj->getWorldTransform(context);
d.weight = evalFloatInst(“weight#”,&i,0,now);
d.c = evalFloatInst(“color#”,&i,0,now);
d.c = evalFloatInst(“color#”,&i,1,now);
d.c = evalFloatInst(“color#”,&i,2,now);
int mth = evalIntInst(“model#”,&i,0,now);
switch(mth)
{
case 1:
d.method = Methods:pherical;
break;
case 2:
d.method = Methods:olar;
break;
case 3:
d.method = Methods:wirl;
break;
case 4:
d.method = Methods::Trigonometric;
break;
case 0:
default:
d.method = Methods::Linear;
};
weights+=d.weight;
totd++;
};
if(totd == 0)
{
delete daemons;
return error();
}
float base = 0.0;
for(int i=0;i<totd;i++)
{
Daemon& d = daemons;
d.range=base;
d.range = base+d.weight/weights;
base=d.range;
};
int total = evalInt(“count”,0,now);
int dt = gdp->addDiffuseAttribute(GEO_POINT_DICT);
UT_Vector3 current(0,0,0);
float C = { 0,0,0 };
srand(0);
for(int i=-50;i<total;i++)
{
bool ok = false;
float w = double(rand())/double(RAND_MAX);
for(int j=0;j<totd;j++)
{
ok = daemons.Transform(w,current,C);
if(ok) break;
};
if(i<0) continue;
if(ok)
{
GEO_Point* p = gdp->appendPoint();
p->setPos(current);
float* Cd=p->castAttribData<float>(dt);
memcpy(Cd,C,12);
};
};
delete daemons;
return error();
}
void newSopOperator(OP_OperatorTable *table)
{
table->addOperator(new OP_Operator(
“hdk_scallop”,“Scallop”,
SOP_Scallop::creator,SOP_Scallop::templateList,
0,1));
}
We reimplemented our tool at Houdini, excluding Pixar's pointcloud export, which is produced by another node. You may play with different Non-linear formulas, which may be plugged easily. I don't think, that using CVEX as non-linear kernel will allow to build pointclouds very fast, but you may add such features too. Good luck!
Sample scene attached.
- redpaw
- Member
- 75 posts
- Joined:
- Offline
This is pretty awesome Joe, thanks , one thing, compiling this I'm getting an error in the “Trigonometric” function, it appears that the absolute functions in that are erroring
“error: call of overloaded ‘abs(float)’ is ambiguous”
“error: call of overloaded ‘abs(double)’ is ambiguous”
commenting out that one option makes it all happy.
another question tho, is how do you control the scale of the functions?
I've tried making a new one with two nulls and can't get it to stay in a reasonable world size as in your example..
thanks for any hints..
-johnc
“error: call of overloaded ‘abs(float)’ is ambiguous”
“error: call of overloaded ‘abs(double)’ is ambiguous”
commenting out that one option makes it all happy.
another question tho, is how do you control the scale of the functions?
I've tried making a new one with two nulls and can't get it to stay in a reasonable world size as in your example..
thanks for any hints..
-johnc
- JoeMislang
- Member
- 48 posts
- Joined: Sept. 2006
- Offline
1. Simplest hints is to keep scaling at one of daemon less than 1.0. Some kind of non-linears make set limited, but scaling more than 1 blows pointcloud up in most of cases.
2. You may write fabs() infstead of abs()
3. I implemented VEX-based non-linear parts, these days I'll publish such version. It has a lot of additional features too.
Good luck and thank you!
2. You may write fabs() infstead of abs()
3. I implemented VEX-based non-linear parts, these days I'll publish such version. It has a lot of additional features too.
Good luck and thank you!
- flyingc
- Member
- 160 posts
- Joined:
- Offline
- eetu
- Member
- 606 posts
- Joined: May 2007
- Offline
As a variation on the theme, i once tried rendering some flame fractal images and then stacked them to form a volume: http://forums.odforce.net/index.php?/topic/8471-eetus-lab/page__view__findpost__p__56247 [forums.odforce.net]
eetu.
eetu.
-
- Quick Links