HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SIM_SolverHair.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 
28 #include "SIM_SolverHair.h"
29 #include <UT/UT_DSOVersion.h>
30 #include <GU/GU_PrimPoly.h>
31 #include <PRM/PRM_Include.h>
32 #include <SIM/SIM_DopDescription.h>
33 #include <SIM/SIM_GeometryCopy.h>
34 #include <SIM/SIM_DataFilter.h>
35 #include <SIM/SIM_Object.h>
36 #include <SIM/SIM_ObjectArray.h>
37 #include <SIM/SIM_Engine.h>
38 #include <SIM/SIM_Force.h>
39 
40 using namespace HDK_Sample;
41 
42 void
44 {
46 }
47 
48 namespace HDK_Sample {
49 
52 {
53 public:
54 #if defined(HOUDINI_11)
56  const SIM_Object &object,
57  const UT_DMatrix4 &xform,
58  fpreal timestep,
59  const GB_AttributeRef &massoffset,
60  const GB_AttributeRef &veloffset);
61 #else
63  const SIM_Object &object,
64  const UT_DMatrix4 &xform,
65  fpreal timestep,
66  const GA_RWHandleF &masshandle,
67  const GA_RWHandleV3 &velhandle);
68 #endif
69  ~SIM_HairForceCallback() override;
70 
71  void callbackConst(const SIM_Data *data,
72  const char *name) override;
73  void forceCallbackOffset(GA_Offset ptoff,
74  const UT_Vector3 &force,
75  const UT_Vector3 &torque) override;
76 
77 private:
78  GU_Detail &myGdp;
79  const SIM_Object &myObject;
80  const UT_DMatrix4 myTransform;
81  fpreal myTimestep;
82  GA_RWHandleF myMassHandle;
83  GA_RWHandleV3 myVelHandle;
84 };
85 
86 } // namespace HDK_Sample
87 
89  const SIM_Object &object,
90  const UT_DMatrix4 &xform,
91  fpreal timestep,
92  const GA_RWHandleF &masshandle,
93  const GA_RWHandleV3 &velhandle)
94  : myGdp(gdp)
95  , myObject(object)
96  , myTransform(xform)
97  , myTimestep(timestep)
98  , myMassHandle(masshandle)
99  , myVelHandle(velhandle)
100 {
101 }
102 
104 {
105 }
106 
107 void
109 {
111  GU_DetailHandle gdh;
112 
113  gdh.allocateAndSet(&myGdp, false);
114  force->getPointForces(*this, myObject, gdh, myTransform, 0, 0, false);
115 }
116 
117 void
119  const UT_Vector3 &force,
120  const UT_Vector3 &)
121 {
122  float mass = myMassHandle.get(ptoff);
123  myVelHandle.set(ptoff, myVelHandle.get(ptoff) + (force/mass)*myTimestep);
124 }
125 
127  : BaseClass(factory),
129 {
130 }
131 
133 {
134 }
135 
136 const SIM_DopDescription *
137 SIM_SolverHair::getSolverHairDopDescription()
138 {
139  static PRM_Template theTemplates[] = {
140  PRM_Template()
141  };
142 
143  static SIM_DopDescription theDopDescription(true,
144  "hdk_hairsolver",
145  "Hair Solver",
147  classname(),
148  theTemplates);
149 
150  return &theDopDescription;
151 }
152 
153 void
155  const SIM_ObjectArray &srcobjs,
156  const SIM_Object &object,
157  const SIM_Time &timestep) const
158 {
159  SIM_GeometryAutoWriteLock lock(&hairgeo);
160  GU_Detail &gdp = lock.getGdp();
161 
162  UT_DMatrix4 xform;
163  hairgeo.getTransform(xform);
164  for (exint geonum = 0; geonum < srcobjs.entries(); geonum++)
165  {
166  const SIM_Object *sourceobj = srcobjs(geonum);
167  const SIM_Geometry *sourcegeo = sourceobj->getGeometry();
168  if (!sourcegeo || sourcegeo->getGeometry().isNull())
169  continue;
170 
171  GU_DetailHandleAutoReadLock sourcegdl(sourcegeo->getGeometry());
172  const GU_Detail *sourcegdp = sourcegdl.getGdp();
173  UT_DMatrix4 sourcexform;
174 
175  SIMgetGeometryTransform(sourcexform, *sourceobj);
176 #if defined(HOUDINI_11)
177  const UT_Vector3 zero(0.0, 0.0, 0.0);
178  const float one = 1.0;
179  massoffset = gdp.addPointAttrib(
181  sizeof(float), GB_ATTRIB_FLOAT, &one);
182  veloffset = gdp.addPointAttrib(
184  sizeof(UT_Vector3), GB_ATTRIB_VECTOR, &zero);
185 #else
188  1, GA_Defaults(1.0)));
191  3, GA_Defaults(0.0));
192  velref.setTypeInfo(GA_TYPE_VECTOR); // Transform as vector
193  GA_RWHandleV3 velhandle(velref);
194 #endif
195 
196  // Apply all forces and move the hairs according to those forces.
197  SIM_HairForceCallback callback(gdp, object, xform, timestep,
198  masshandle, velhandle);
199  object.forEachConstSubData(callback,
200  SIM_DataFilterByType("SIM_Force"),
203 
204  // Integrate our velocities.
205  {
206  GA_Offset hairptoff;
207  GA_FOR_ALL_PTOFF((&gdp), hairptoff)
208  {
209  UT_Vector3 dp = velhandle.get(hairptoff);
210  dp *= timestep;
211 
212  gdp.setPos3(hairptoff, gdp.getPos3(hairptoff) + dp);
213  }
214  }
215 
216  // Now pull all the points along to make sure the hair length
217  // remains constant.
218  GA_Iterator primit(gdp.getPrimitiveRange());
219  GA_Offset sourceptoff;
220  GA_FOR_ALL_PTOFF(sourcegdp, sourceptoff)
221  {
222  if (primit.atEnd())
223  break;
224 
225  GA_Primitive *hairpoly = gdp.getPrimitiveList().get(*primit);
226  if (hairpoly->getTypeId() == GA_PRIMPOLY &&
227  hairpoly->getVertexCount() == 10)
228  {
229  UT_Vector3 startpos = sourcegdp->getPos3(sourceptoff);
230  startpos *= sourcexform;
231 
232  GA_Offset hairpt0off = hairpoly->getPointOffset(0);
233  GA_Offset hairpt1off = hairpoly->getPointOffset(1);
234  // Calculate the change in position we need to enforce
235  // our length constraints. Then calculate the change in
236  // velocity inherent in this change in position, using
237  // dp = vt, we get dv = dp/t.
238  UT_Vector3 dp = startpos - gdp.getPos3(hairpt0off);
239  UT_Vector3 dv = dp / timestep;
240  UT_Vector3 vel = velhandle.get(hairpt0off);
241  vel += dv;
242  // Apply drag. Just scale down the velocity.
243  vel *= 0.8;
244  velhandle.set(hairpt0off, vel);
245  gdp.setPos3(hairpt0off, gdp.getPos3(hairpt0off) + dp);
246  GA_Offset hairpt2off;
247  for (int ptnum = 1; ptnum < 10; ptnum++)
248  {
249  if (ptnum < 9)
250  hairpt2off = hairpoly->getPointOffset(ptnum + 1);
251  UT_Vector3 midline = gdp.getPos3(hairpt2off) - gdp.getPos3(hairpt0off);
252  // Calculate the change in position we need to enforce
253  // our length constraints. Then calculate the change in
254  // velocity inherent in this change in position, using
255  // dp = vt, we get dv = dp/t.
256  dp = midline * (0.1 / midline.length()) +
257  gdp.getPos3(hairpt0off) - gdp.getPos3(hairpt1off);
258  dv = dp / timestep;
259  vel = velhandle.get(hairpt1off);
260  vel += dv;
261  // Apply drag. Just scale down the velocity.
262  vel *= 0.8;
263  velhandle.set(hairpt1off, vel);
264  gdp.setPos3(hairpt1off, gdp.getPos3(hairpt1off) + dp);
265  hairpt0off = hairpt1off;
266  hairpt1off = hairpt2off;
267  }
268  }
269  ++primit;
270  }
271  }
272 }
273 
274 void
276  const SIM_ObjectArray &srcobjs) const
277 {
278  SIM_GeometryAutoWriteLock lock(&hairgeo);
279  GU_Detail &gdp = lock.getGdp();
280 
281  for (exint geonum = 0; geonum < srcobjs.entries(); geonum++)
282  {
283  const SIM_Object *sourceobj = srcobjs(geonum);
284  const SIM_Geometry *sourcegeo = sourceobj->getGeometry();
285  if(!sourcegeo || sourcegeo->getGeometry().isNull())
286  continue;
287 
288  GU_DetailHandleAutoReadLock sourcegdl(sourcegeo->getGeometry());
289  const GU_Detail *sourcegdp = sourcegdl.getGdp();
290  UT_DMatrix4 sourcexform;
291 
292  SIMgetGeometryTransform(sourcexform, *sourceobj);
293  GA_Offset sourceptoff;
294  GA_FOR_ALL_PTOFF(sourcegdp, sourceptoff)
295  {
296  UT_Vector4 startpos = sourcegdp->getPos4(sourceptoff);
297  startpos *= sourcexform;
298  GU_PrimPoly *newpoly = GU_PrimPoly::build(&gdp, 0, GU_POLY_OPEN, 0);
299  for (int i = 0; i < 10; i++)
300  {
301  GA_Offset newptoff = gdp.appendPointOffset();
302  gdp.setPos3(newptoff, startpos.x(),
303  startpos.y() + (fpreal)i * 0.1,
304  startpos.z());
305  newpoly->appendVertex(newptoff);
306  }
307  }
308  }
309 }
310 
313  SIM_Object &object,
314  SIM_ObjectArray &,
315  const SIM_Time &timestep,
316  bool newobject)
317 {
318  SIM_GeometryCopy *hairgeo = 0;
319  SIM_ObjectArray sourceobjects;
320 
321  if( newobject )
322  {
324  {
325  hairgeo = SIM_DATA_CREATE(object, SIM_GEOMETRY_DATANAME,
326  SIM_GeometryCopy, 0);
327  object.getAffectors(sourceobjects, "SIM_RelationshipSource");
328  if( hairgeo && sourceobjects.entries() > 0 )
329  createHairFromSource(*hairgeo, sourceobjects);
330  }
331  }
332  else
333  {
335  if( hairgeo )
336  {
337  object.getAffectors(sourceobjects, "SIM_RelationshipSource");
338  if( hairgeo && sourceobjects.entries() > 0 )
339  solveHair(*hairgeo, sourceobjects, object, timestep);
340  }
341  }
342 
343  return hairgeo ? SIM_SOLVER_SUCCESS : SIM_SOLVER_FAIL;
344 }
345 
#define SIM_FORCES_DATANAME
Definition: SIM_Names.h:45
virtual void createHairFromSource(SIM_GeometryCopy &hairgeo, const SIM_ObjectArray &srcobjs) const
virtual void solveHair(SIM_GeometryCopy &hairgeo, const SIM_ObjectArray &srcobjs, const SIM_Object &object, const SIM_Time &timestep) const
SYS_FORCE_INLINE GA_Attribute * addPointAttrib(const GA_Attribute *src)
Definition: GEO_Detail.h:1684
#define SIM_DATA_CASTCONST(Data, DataClass)
Definition: SIM_Utils.h:34
exint entries() const
SYS_FORCE_INLINE GA_Offset getPointOffset(GA_Size i) const
Definition: GA_Primitive.h:254
SYS_FORCE_INLINE GA_Size getVertexCount() const
Return the number of vertices used by this primitive.
Definition: GA_Primitive.h:232
SIM_SolverHair(const SIM_DataFactory *factory)
void getTransform(UT_DMatrix4 &xform) const
Iteration over a range of elements.
Definition: GA_Iterator.h:29
bool setTypeInfo(GA_TypeInfo info)
Set type information on the attribute.
#define IMPLEMENT_DATAFACTORY(DataClass)
Class which stores the default values for a GA_Attribute.
Definition: GA_Defaults.h:35
GA_Attribute * addFloatTuple(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringHolder &name, int tuple_size, const GA_Defaults &defaults=GA_Defaults(0.0), const UT_Options *creation_args=0, const GA_AttributeOptions *attribute_options=0, GA_Storage storage=GA_STORE_REAL32, const GA_ReuseStrategy &reuse=GA_ReuseStrategy())
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector4.h:493
void initializeSIM(void *)
UT_Vector3T< float > UT_Vector3
SIM_API const UT_StringHolder torque
int64 exint
Definition: SYS_Types.h:125
SYS_FORCE_INLINE const GA_PrimitiveTypeId & getTypeId() const
Definition: GA_Primitive.h:177
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:617
constexpr SYS_FORCE_INLINE T length() const noexcept
Definition: UT_Vector3.h:361
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
Definition: GA_Detail.h:185
void getPointForces(SIM_PointForceCallback &cb, const SIM_Object &object, const GU_ConstDetailHandle &gdh, const UT_DMatrix4 &geoxform, const SIM_Position *position, const SIM_Motion *motion, bool forcesinworldspace) const
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector4.h:491
void allocateAndSet(GU_Detail *gdp, bool own=true)
GA_Size GA_Offset
Definition: GA_Types.h:641
SIM_HairForceCallback(GU_Detail &gdp, const SIM_Object &object, const UT_DMatrix4 &xform, fpreal timestep, const GA_RWHandleF &masshandle, const GA_RWHandleV3 &velhandle)
This class provides a way to manage a reference to an attribute permitting Read-Write access...
void forceCallbackOffset(GA_Offset ptoff, const UT_Vector3 &force, const UT_Vector3 &torque) override
static GU_PrimPoly * build(GA_Detail *gdp, int npts, int open=0, int appendpts=1)
Definition: GU_PrimPoly.h:126
GA_Size appendVertex(GA_Offset ptoff) override
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector4.h:495
Holds pointers to a number of SIM_Object objects.
#define SIM_DATA_GET(Parent, DataName, DataClass)
Definition: SIM_Utils.h:40
const SIM_Geometry * getGeometry() const
#define SIM_SOLVER_DATANAME
Definition: SIM_Names.h:55
SYS_FORCE_INLINE T get(GA_Offset off, int comp=0) const
Definition: GA_Handle.h:203
GLuint const GLchar * name
Definition: glcorearb.h:786
#define GA_FOR_ALL_PTOFF(gdp, ptoff)
Definition: GA_GBMacros.h:88
SIM_Result solveSingleObjectSubclass(SIM_Engine &engine, SIM_Object &object, SIM_ObjectArray &feedbacktoobjects, const SIM_Time &timestep, bool newobject) override
GA_API const UT_StringHolder mass
SYS_FORCE_INLINE GA_Offset appendPointOffset()
Definition: GEO_Detail.h:1143
SYS_FORCE_INLINE const GA_Primitive * get(GA_Offset off) const
SYS_FORCE_INLINE void setPos3(GA_Offset ptoff, const UT_Vector3 &pos)
Set P from a UT_Vector3.
Definition: GA_Detail.h:237
#define GU_POLY_OPEN
Definition: GU_Types.h:120
SIM_API const UT_StringHolder force
#define SIM_GEOMETRY_DATANAME
Definition: SIM_Names.h:44
This filter rejects all data.
SYS_FORCE_INLINE void set(GA_Offset off, const T &val) const
Definition: GA_Handle.h:354
fpreal64 fpreal
Definition: SYS_Types.h:277
UT_StringHolder getStdAttributeName(GEO_Standard_Attributes name, int layer=-1) const
GU_ConstDetailHandle getGeometry() const
Data represents a direction vector. Token "vector".
Definition: GA_Types.h:111
const GA_PrimitiveList & getPrimitiveList() const
Definition: GA_Detail.h:792
SIM_API void SIMgetGeometryTransform(UT_DMatrix4 &result, const SIM_Object &)
This class is used for callbacks from SIM_Force::getPointForces().
Definition: SIM_Force.h:25
GA_Range getPrimitiveRange(const GA_PrimitiveGroup *group=0) const
Get a range of all primitives in the detail.
Definition: GA_Detail.h:1733
ImageBuf OIIO_API zero(ROI roi, int nthreads=0)
#define SIM_DATA_CREATE(Parent, DataName, DataClass, Flags)
Definition: SIM_Utils.h:63
void callbackConst(const SIM_Data *data, const char *name) override
Definition: format.h:895
This implements a SIM_Geometry that copies the source geometry.