HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RAY_DemoGT.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  * This is a sample procedural DSO
27  */
28 
29 #undef UT_ASSERT_LEVEL
30 #define UT_ASSERT_LEVEL 4
31 
32 #include <UT/UT_DSOVersion.h>
33 #include <UT/UT_MTwister.h>
34 #include <UT/UT_StackBuffer.h>
35 #include <RAY/RAY_ProcGT.h>
36 #include <GT/GT_PrimitiveBuilder.h>
37 #include <GT/GT_PrimCurveMesh.h>
38 #include "RAY_DemoGT.h"
40 
41 using namespace HDK_Sample;
42 
43 // Sample definition in an IFD
44 // ray_procedural -m -1 -.1 -1 -M 1 .1 1 demogt debug 0 count 10000 segments 2
45 
46 static RAY_ProceduralArg theArgs[] = {
47  RAY_ProceduralArg("maxradius", "real", "0.01"),
48  RAY_ProceduralArg("count", "int", "100"),
49  RAY_ProceduralArg("segments", "int", "1"),
50  RAY_ProceduralArg("debug", "int", "0"),
52 };
53 
55 {
56 public:
58  : RAY_ProceduralFactory::ProcDefinition("demogt")
59  {
60  }
61  RAY_Procedural *create() const override { return new RAY_DemoGT(); }
62  RAY_ProceduralArg *arguments() const override { return theArgs; }
63 };
64 
65 void
67 {
68  factory->insert(new ProcDef);
69 }
70 
72  : myMaxRadius(0.05)
73  , myCurveCount(0)
74  , mySegments(1)
75  , myDebug(false)
76 {
77  myBox.initBounds(0, 0, 0);
78 }
79 
81 {
82 }
83 
84 const char *
86 {
87  return "RAY_DemoGT";
88 }
89 
90 int
92 {
93  if (box)
94  myBox = *box;
95  else
96  myBox = UT_BoundingBox(-1, -1, -1, 1, 1, 1);
97 
98  // Import the number of motion segments
99  if (!import("segments", &mySegments, 1))
100  mySegments = 1;
101 
102  if (!import("count", &myCurveCount, 1))
103  myCurveCount = 100;
104 
105  if (!import("maxradius", &myMaxRadius, 1))
106  myMaxRadius = 0.05;
107 
108  int ival;
109  if (import("debug", &ival, 1))
110  myDebug = (ival != 0);
111 
112  if (myDebug)
113  return true;
114  // Only need to render if there's geometry to render
115  return myCurveCount > 0 && mySegments > 0 && myMaxRadius > 0;
116 }
117 
118 void
120 {
121  box = myBox;
122 
123  // Now, expand bounds to include the maximum radius of a curve
124  box.expandBounds(0, myMaxRadius);
125 }
126 
127 static GT_PrimitiveHandle
128 makeCurveMesh(const UT_BoundingBox &box,
129  int ncurves,
130  fpreal maxradius,
131  int segments)
132 {
133  static const int pts_per_curve = 4;
135  GT_Real16Array *f16;
136  int npts = ncurves * pts_per_curve;
137 
138  // Allocate colors as uniform fpreal16 data
139  GT_DataArrayHandle clr;
140  f16 = new GT_Real16Array(ncurves, 3, GT_TYPE_COLOR);
141  for (int i = 0; i < ncurves*3; ++i)
142  f16->data()[i] = twist.frandom();
143 
144  clr.reset(f16);
145 
146  // Allocate widths as per-point fpreal16 data
147  GT_DataArrayHandle widths;
148  f16 = new GT_Real16Array(npts, 1);
149  for (int curve = 0; curve < ncurves; curve++)
150  {
151  fpreal16 *val = f16->data() + pts_per_curve * curve;
152  fpreal width = SYSlerp(maxradius, maxradius*.1,
153  fpreal(twist.frandom())) * 2;
154  for (int pt = 0; pt < pts_per_curve; ++pt)
155  {
156  val[pt] = width;
157  width *= .7; // Taper each curve
158  }
159  }
160  widths.reset(f16);
161 
162  // Allocate "P" as per-point fpreal32 data
163  UT_StackBuffer<GT_DataArrayHandle> P(segments); // One for each segment
164  UT_StackBuffer<GT_Real32Array *> Pdata(segments);
165  UT_StackBuffer<fpreal> Py(pts_per_curve);
166  for (int i = 0; i < segments; ++i)
167  {
168  Pdata[i] = new GT_Real32Array(npts, 3, GT_TYPE_POINT);
169  P[i] = Pdata[i];
170  }
171 
172  for (int i = 0; i < pts_per_curve; ++i)
173  {
174  fpreal fity = fpreal(i)/(pts_per_curve-1);
175  Py[i] = SYSlerp((fpreal)box.ymin(), (fpreal)box.ymax(), fity);
176  }
177 
178  // Now, set positions
179  for (int curve = 0; curve < ncurves; ++curve)
180  {
181  fpreal tx = SYSlerp(.1, .9, twist.frandom());
182  fpreal tz = SYSlerp(.1, .9, twist.frandom());
183  for (int seg = 0; seg < segments; ++seg)
184  {
185  fpreal px, pz;
186  fpreal vx, vz;
187  px = SYSlerp(box.xmin(), box.xmax(), tx);
188  pz = SYSlerp(box.zmin(), box.zmax(), tz);
189 
190  // Choose a different velocity trajectory per motion segment
191  vx = SYSlerp(0.0, box.xsize()*.1/segments, twist.frandom()-.5);
192  vz = SYSlerp(0.0, box.zsize()*.1/segments, twist.frandom()-.5);
193 
194  // Choose a different height per motion segment
195  fpreal height = SYSlerp(.5, 1.0, twist.frandom());
196  int off = curve * pts_per_curve * 3;
197  for (int pt = 0; pt < pts_per_curve; ++pt)
198  {
199  Pdata[seg]->data()[off+pt*3+0] = px;
200  Pdata[seg]->data()[off+pt*3+1] = Py[pt] * height;
201  Pdata[seg]->data()[off+pt*3+2] = pz;
202  UT_ASSERT(px >= box.xmin() && px < box.xmax());
203  UT_ASSERT(pz >= box.zmin() && pz < box.zmax());
204  px += vx;
205  pz += vz;
206  vx *= .4;
207  vz *= .4;
208  }
209  }
210  }
211  // Debug the P values
212  //P[0]->dumpValues("P");
213 
214  // Now we have all the data arrays, we can build the curve
215  GT_AttributeMap *amap;
216  GT_AttributeList *uniform;
218 
219  // First, create the uniform attributes
220  amap = new GT_AttributeMap();
221  amap->add("Cd", true);
222  uniform = new GT_AttributeList(amap, segments); // 2 motion segments
223  for (int seg = 0; seg < segments; ++seg)
224  uniform->set(0, clr, seg); // Share color data for segment
225 
226  // Now, create the per-vertex attributes
227  amap = new GT_AttributeMap();
228  amap->add("P", true);
229  amap->add("width", true);
230  vertex = new GT_AttributeList(amap, segments);
231  for (int seg = 0; seg < segments; ++seg)
232  {
233  vertex->set(0, P[seg], seg); // Set P for the motion segment
234  vertex->set(1, widths, seg); // Share width data
235  }
236 
237  // Create the vertex per curve counts
238  GT_DataArrayHandle vertex_counts;
239  vertex_counts.reset(new GT_IntConstant(ncurves, pts_per_curve));
240 
241  // Create a new curve mesh
243  vertex_counts,
244  GT_AttributeListHandle(vertex),
245  GT_AttributeListHandle(uniform),
247  false));
248 
249  // Debug the curve primitive
250  //prim->dumpPrimitive();
251  return prim;
252 }
253 
254 static GT_PrimitiveHandle
255 testBox(const UT_BoundingBox &box, fpreal32 maxwidth)
256 {
257  GT_BuilderStatus err;
258  GT_PrimitiveHandle prim;
259  fpreal16 clr[3] = { .3f, .5f, 1.f };
260  prim = GT_PrimitiveBuilder::wireBox(err, box,
262  << GT_Attribute("constant fpreal32 width", &maxwidth)
263  << GT_Attribute("constant color16 Cd", clr)
264  );
265  return prim;
266 }
267 
268 void
270 {
271  // To render this procedural, we create a new GT procedural as a child
273 
274  GT_PrimitiveHandle prim;
275  if (myDebug)
276  prim = testBox(myBox, myMaxRadius*2);
277  else
278  {
279  int one = 1;
280  prim = makeCurveMesh(myBox, myCurveCount, myMaxRadius, mySegments);
281 
282  // Turn on subdivision curve rendering
283  obj->changeSetting("object:rendersubdcurves", 1, &one);
284  }
285  int zero;
286  obj->changeSetting("geometry:computeN", 1, &zero);
287 
288  // Add the child procedural
289  obj->addProcedural(new RAY_ProcGT(prim));
290 }
SIM_API const UT_StringHolder vertex
void getBoundingBox(UT_BoundingBox &box) override
The bounding box is the "object space" bounds of the procedural.
Definition: RAY_DemoGT.C:119
T zsize() const
void set(int idx, const GT_DataArrayHandle &h, int motion_segment=0)
Assign an array to a given index in the list.
A symbol table for attribute data.
ProcDef()
Definition: RAY_DemoGT.C:57
UT_IntrusivePtr< GT_AttributeList > GT_AttributeListHandle
Definition: GT_Handles.h:28
GT_DANumeric< fpreal32 > GT_Real32Array
Definition: GT_DANumeric.h:522
GA_API const UT_StringHolder twist
Procedural primitive for mantra (RAY)
void registerProcedural(RAY_ProceduralFactory *factory)
Modern interface to register procedurals.
Definition: RAY_DemoGT.C:66
bool insert(ProcDefinition *def, bool replace_existing=true)
T * data() const
Raw access to the data array.
Definition: GT_DANumeric.h:130
GA_API const UT_StringHolder P
fpreal32 frandom()
Definition: UT_MTwister.h:63
std::pair< const char *, UT_VariadicPODType > GT_Attribute
UT_Matrix2T< T > SYSlerp(const UT_Matrix2T< T > &v1, const UT_Matrix2T< T > &v2, S t)
Definition: UT_Matrix2.h:675
float fpreal32
Definition: SYS_Types.h:200
A mesh of curves.
int add(const UT_StringHolder &name, bool replace_existing)
SYS_FORCE_INLINE void expandBounds(T relative, T absolute)
GLint GLsizei GLsizei height
Definition: glcorearb.h:103
int initialize(const UT_BoundingBox *) override
Definition: RAY_DemoGT.C:91
UT_VariadicT< GT_Attribute > GT_VariadicAttributes
UT_BoundingBoxT< float > UT_BoundingBox
Definition: GEO_Detail.h:41
~RAY_DemoGT() override
Definition: RAY_DemoGT.C:80
const char * className() const override
Definition: RAY_DemoGT.C:85
RAY_ProceduralChildPtr createChild() const
T xsize() const
A procedural using GT to create geometry for rendering.
Definition: RAY_DemoGT.h:39
static GT_PrimitiveHandle wireBox(GT_BuilderStatus &err, const UT_BoundingBox &box, const GT_VariadicAttributes &attribs=GT_VariadicAttributes())
Parameter definition for arguments to RAY_Procedural.
fpreal64 fpreal
Definition: SYS_Types.h:277
GLuint GLfloat * val
Definition: glcorearb.h:1608
SYS_FORCE_INLINE void initBounds()
GLint GLsizei width
Definition: glcorearb.h:103
RAY_ProceduralArg * arguments() const override
Provide a const reference to the arguments for the procedural.
Definition: RAY_DemoGT.C:62
Procedural to render a single GT primitive.
Definition: RAY_ProcGT.h:48
GT_DAConstantValue< int64 > GT_IntConstant
An array of numeric values (int32, int64, fpreal16, fpreal32, fpreal64)
Definition: GT_DANumeric.h:23
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
RAY_Procedural * create() const override
Create a procedural, and pass ownership of the instance to mantra.
Definition: RAY_DemoGT.C:61
void render() override
Definition: RAY_DemoGT.C:269
Return the status of primitive creation from GT_PrimitiveBuilder.
ImageBuf OIIO_API zero(ROI roi, int nthreads=0)
Class to create a procedural.
GT_DANumeric< fpreal16 > GT_Real16Array
Definition: GT_DANumeric.h:521