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