HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GR_PrimTetra.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 #include "GR_PrimTetra.h"
27 #include <GR/GR_Light.h>
28 #include "GEO_PrimTetra.h"
29 
30 #include <DM/DM_RenderTable.h>
31 #include <GR/GR_Utils.h>
32 #include <RE/RE_ElementArray.h>
33 #include <RE/RE_Geometry.h>
34 #include <RE/RE_LightList.h>
35 #include <RE/RE_ShaderHandle.h>
36 #include <RE/RE_VertexArray.h>
37 
38 #include <GT/GT_GEOPrimitive.h>
39 
40 using namespace HDK_Sample;
41 
42 // See GEO_PrimTetra::registerMyself() for installation of the hook.
43 
45  : GUI_PrimitiveHook("Tetrahedron")
46 {
47 }
48 
50 {
51 }
52 
55  const GEO_Primitive *geo_prim,
56  const GR_RenderInfo *info,
57  const char *cache_name,
58  GR_PrimAcceptResult &processed)
59 {
60  return new GR_PrimTetra(info, cache_name, geo_prim);
61 }
62 
64  const char *cache_name,
65  const GEO_Primitive *prim)
66  : GR_Primitive(info, cache_name, GA_PrimCompat::TypeMask(0))
67 {
68 
69  myID = prim->getTypeId().get();
70  myGeo = NULL;
71 }
72 
74 {
75  delete myGeo;
76 }
77 
78 
81  int geo_type,
82  const GT_PrimitiveHandle &ph,
83  const GEO_Primitive *prim)
84 {
85  if(geo_type == myID)
86  return GR_PROCESSED;
87 
88  return GR_NOT_PROCESSED;
89 }
90 
91 
92 void
94  const GT_PrimitiveHandle &primh,
95  const GR_UpdateParms &p)
96 {
97  if(r.isVulkan())
98  return;
99 
100  // Fetch the GEO primitive from the GT primitive handle
101  const GEO_PrimTetra *tet = NULL;
102 
103  // GL3 and above requires named vertex attributes, while GL2 and GL1 use
104  // the older builtin names.
105 
106  const char *posname = "P";
107  const char *nmlname = "N";
108  RE_VertexArray *pos = NULL;
109  RE_VertexArray *nml = NULL;
110  UT_Vector3FArray pt;
111 
112  // Initialize the geometry with the proper name for the GL cache
113  if(!myGeo)
114  myGeo = new RE_Geometry;
115  myGeo->cacheBuffers(getCacheName());
116 
117  getGEOPrimFromGT<GEO_PrimTetra>(primh, tet);
118 
119  const int num_tets = tet ? 1 : 0;
120  if(num_tets == 0)
121  {
122  delete myGeo;
123  myGeo = NULL;
124  return;
125  }
126 
127  // Extract tetra point positions.
128  {
130  const GU_Detail *dtl = georl.getGdp();
131 
132  for(int v=0; v<4; v++)
133  pt.append(dtl->getPos3(dtl->vertexPoint(tet->getVertexOffset(v))));
134  }
135 
136  // Initialize the number of points in the geometry.
137  myGeo->setNumPoints( 12 * num_tets);
138 
139  GR_UpdateParms dp(p);
140  const GR_Decoration pdecs[] = { GR_POINT_MARKER,
143  GR_POINT_UV,
151  GR_VERTEX_UV,
154  dp, pdecs, GR_POINT_ATTRIB);
155 
156 
157  // Fetch P (point position). If its cache version matches, no upload is
158  // required.
159  pos = myGeo->findCachedAttrib(r, posname, RE_GPU_FLOAT32, 3,
160  RE_ARRAY_POINT, true);
161  if(pos->getCacheVersion() != dp.geo_version)
162  {
163  // map() returns a pointer to the GL buffer
164  UT_Vector3F *pdata = static_cast<UT_Vector3F *>(pos->map(r));
165  if(pdata)
166  {
167  for(int t=0; t<num_tets; t++)
168  {
169  pdata[0] = pt(t*4);
170  pdata[1] = pt(t*4+1);
171  pdata[2] = pt(t*4+2);
172 
173  pdata[3] = pt(t*4);
174  pdata[4] = pt(t*4+2);
175  pdata[5] = pt(t*4+3);
176 
177  pdata[6] = pt(t*4+1);
178  pdata[7] = pt(t*4+2);
179  pdata[8] = pt(t*4+3);
180 
181  pdata[9] = pt(t*4);
182  pdata[10] = pt(t*4+3);
183  pdata[11] = pt(t*4+1);
184 
185  pdata += 12;
186  }
187 
188  // unmap the buffer so it can be used by GL
189  pos->unmap(r);
190 
191  // Always set the cache version after assigning data.
192  pos->setCacheVersion(dp.geo_version);
193  }
194  }
195 
196 
197  // NOTE: you can add more attributes from a detail, such as Cd, uv, Alpha
198  // by repeating the process above.
199 
200  // Fetch N (point normal). This just generates normals for the tetras.
201  nml = myGeo->findCachedAttrib(r, nmlname, RE_GPU_FLOAT32, 3,
202  RE_ARRAY_POINT, true);
203  if(nml->getCacheVersion() != dp.geo_version)
204  {
205  UT_Vector3F *ndata = static_cast<UT_Vector3F *>(nml->map(r));
206  if(ndata)
207  {
208  UT_Vector3F n0, n1, n2, n3;
209 
210  // This just creates primitive normals for the tet. It's currently
211  // not 100% correct (FIXME).
212  for(int t=0; t<num_tets; t++)
213  {
214  n0 = -cross(pt(t*4+2)-pt(t*4), pt(t*4+1)-pt(t*4)).normalize();
215  n1 = cross(pt(t*4+3)-pt(t*4), pt(t*4+2)-pt(t*4)).normalize();
216  n2 = -cross(pt(t*4+3)-pt(t*4+1),pt(t*4+2)-pt(t*4+1)).normalize();
217  n3 = -cross(pt(t*4+1)-pt(t*4), pt(t*4+3)-pt(t*4)).normalize();
218 
219  ndata[0] = ndata[1] = ndata[2] = n0;
220  ndata[3] = ndata[4] = ndata[5] = n1;
221  ndata[6] = ndata[7] = ndata[8] = n2;
222  ndata[9] = ndata[10] = ndata[11] = n3;
223 
224  ndata += 12;
225  }
226 
227  nml->unmap(r);
228 
229  // Always set the cache version after assigning data.
230  nml->setCacheVersion(dp.geo_version);
231  }
232  }
233 
234 
235  // Extra constant inputs for the GL3 default shaders we are using.
236  // This isn't required unless
237  fpreal32 col[3] = { 1.0, 1.0, 1.0 };
238  fpreal32 uv[2] = { 0.0, 0.0 };
239  fpreal32 alpha = 1.0;
240  fpreal32 pnt = 0.0;
241 
242  myGeo->createConstAttribute(r, "Cd", RE_GPU_FLOAT32, 3, col);
243  myGeo->createConstAttribute(r, "uv", RE_GPU_FLOAT32, 2, uv);
244  myGeo->createConstAttribute(r, "Alpha", RE_GPU_FLOAT32, 1, &alpha);
245  myGeo->createConstAttribute(r, "pointSelection", RE_GPU_FLOAT32, 1,&pnt);
246 
247  myInstancedFlag =
248  GR_Utils::buildInstanceObjectMatrix(r, primh, p, myGeo,
249  p.instance_version, 0);
251  GR_Utils::buildInstanceIndex(r, myGeo, false, dummy, 0, 0);
252 
253  // Connectivity, for both shaded and wireframe
254  myGeo->connectAllPrims(r, RE_GEO_WIRE_IDX, RE_PRIM_LINES, NULL, true);
255  myGeo->connectAllPrims(r, RE_GEO_SHADED_IDX, RE_PRIM_TRIANGLES, NULL, true);
256 }
257 
258 
259 // GL3 shaders. These use some of the builtin Houdini shaders, which are
260 // described by the .prog file format - a simple container format for various
261 // shader stages and other information.
262 
263 static RE_ShaderHandle theNQShader("material/GL32/beauty_lit.prog");
264 static RE_ShaderHandle theNQFlatShader("material/GL32/beauty_flat_lit.prog");
265 static RE_ShaderHandle theNQUnlitShader("material/GL32/beauty_unlit.prog");
266 static RE_ShaderHandle theHQShader("material/GL32/beauty_material.prog");
267 static RE_ShaderHandle theLineShader("basic/GL32/wire_color.prog");
268 static RE_ShaderHandle theConstShader("material/GL32/constant.prog");
269 static RE_ShaderHandle theZCubeShader("basic/GL32/depth_cube.prog");
270 static RE_ShaderHandle theZLinearShader("basic/GL32/depth_linear.prog");
271 static RE_ShaderHandle theMatteShader("basic/GL32/matte.prog");
272 
273 
274 void
276  GR_RenderMode render_mode,
278  GR_DrawParms dp)
279 {
280  if(!myGeo)
281  return;
282 
283  bool need_wire = (render_mode == GR_RENDER_WIREFRAME ||
284  render_mode == GR_RENDER_HIDDEN_LINE ||
285  render_mode == GR_RENDER_GHOST_LINE ||
286  render_mode == GR_RENDER_MATERIAL_WIREFRAME ||
287  (flags & GR_RENDER_FLAG_WIRE_OVER));
288 
289  // Shaded mode rendering
290  if(render_mode == GR_RENDER_BEAUTY ||
291  render_mode == GR_RENDER_MATERIAL ||
292  render_mode == GR_RENDER_CONSTANT ||
293  render_mode == GR_RENDER_HIDDEN_LINE ||
294  render_mode == GR_RENDER_GHOST_LINE ||
295  render_mode == GR_RENDER_DEPTH ||
296  render_mode == GR_RENDER_DEPTH_LINEAR ||
297  render_mode == GR_RENDER_DEPTH_CUBE ||
298  render_mode == GR_RENDER_MATTE)
299  {
300  // enable polygon offset if doing a wireframe on top of shaded
301  bool polyoff = r->isPolygonOffset();
302  if(need_wire)
303  r->polygonOffset(true);
304 
305  r->pushShader();
306 
307  // GL3 requires the use of shaders. The fixed function pipeline
308  // GL builtins (which are deprecated, like gl_ModelViewMatrix)
309  // are not initialized in the GL3 renderer.
310 
311  if(render_mode == GR_RENDER_BEAUTY)
312  {
313  if(flags & GR_RENDER_FLAG_UNLIT)
314  r->bindShader(theNQUnlitShader);
315  else if(flags & GR_RENDER_FLAG_FLAT_SHADED)
316  r->bindShader(theNQFlatShader);
317  else
318  r->bindShader(theNQShader);
319  }
320  else if(render_mode == GR_RENDER_MATERIAL)
321  {
322  r->bindShader(theHQShader);
323  }
324  else if(render_mode == GR_RENDER_CONSTANT ||
325  render_mode == GR_RENDER_DEPTH ||
326  render_mode == GR_RENDER_HIDDEN_LINE ||
327  render_mode == GR_RENDER_GHOST_LINE)
328  {
329  // Reuse constant for depth-only since it's so lightweight.
330  r->bindShader(theConstShader);
331  }
332  else if(render_mode == GR_RENDER_DEPTH_LINEAR)
333  {
334  // Depth written to world-space Z instead of non-linear depth
335  // buffer Z ([0..1] near-far depth range)
336  r->bindShader(theZLinearShader);
337  }
338  else if(render_mode == GR_RENDER_DEPTH_CUBE)
339  {
340  // Linear depth written to
341  r->bindShader(theZCubeShader);
342  }
343  else if(render_mode == GR_RENDER_MATTE)
344  {
345  r->bindShader(theMatteShader);
346  }
347 
348 
349  // setup materials and lighting
350  if(dp.materials && (dp.materials->getDefaultMaterial() ||
352  {
353  RE_Shader *shader = r->getShader();
355  if(!mat)
356  mat = dp.materials->getFactoryMaterial();
357 
358  // Set up lighting for any GL3 lighting blocks
359  if(shader && dp.opts->getLightList())
360  dp.opts->getLightList()->glLights()->bindForShader(r, shader);
361 
362  // set up the main material block for GL3
363  mat->updateShaderForMaterial(r, 0, true,
364  RE_SHADER_TARGET_TRIANGLE, shader);
365  }
366 
367  // Draw call for the geometry
368  if(dp.draw_instanced)
370  else
371  myGeo->draw(r, RE_GEO_SHADED_IDX);
372 
373  if(r->getShader())
375  r->popShader();
376 
377  if(need_wire && !polyoff)
378  r->polygonOffset(polyoff);
379  }
380 
381 
382  // Wireframe rendering
383  if(need_wire)
384  {
385  // GL3 requires a shader even for simple wireframe rendering.
386  r->pushShader(theLineShader);
387 
388  if(dp.draw_instanced)
390  else
391  myGeo->draw(r, RE_GEO_WIRE_IDX);
392 
393  r->popShader();
394  }
395 }
396 
397 void
399  GR_Decoration decor,
400  const GR_DecorationParms &p)
401 {
402  drawDecorationForGeo(r, myGeo, decor, p.opts, p.render_flags,
405 
406 }
407 
408 int
410  const GR_DisplayOption *opt,
411  unsigned int pick_type,
412  GR_PickStyle pick_style,
413  bool has_pick_map)
414 {
415  // This example is not pickable.
416  return 0;
417 }
GLbitfield flags
Definition: glcorearb.h:1596
void unmap(RE_Render *r, int array_index=0)
GR_DecorationRender * myDecorRender
Definition: GR_Primitive.h:666
GA_API const UT_StringHolder uv
GU_ConstDetailHandle geometry
const GR_DisplayOption * opts
const GLdouble * v
Definition: glcorearb.h:837
RE_CacheVersion geo_version
A collection of vertex arrays defining a geometry object. This class acts as a wrapper around multipl...
Definition: RE_Geometry.h:53
int instance_group
Definition: GR_DrawParms.h:28
GT_API const UT_StringHolder cache_name
void draw(RE_Render *r, int connect_idx, RE_PrimType prim_type=RE_PRIM_AS_IS, RE_OverrideList *attrib_overrides=nullptr)
Definition: RE_Geometry.h:627
const RE_MaterialPtr & getDefaultMaterial() const
Definition: RE_Material.h:1054
SYS_FORCE_INLINE const GA_PrimitiveTypeId & getTypeId() const
Definition: GA_Primitive.h:177
void drawInstanceGroup(RE_Render *r, int connect_idx, int instance_group, RE_PrimType prim_type=RE_PRIM_AS_IS, RE_OverrideList *attrib_over=nullptr)
Draw an instance group using a given connectivity.
bool isPolygonOffset()
void renderDecoration(RE_RenderContext r, GR_Decoration decor, const GR_DecorationParms &parms) override
Definition: GR_PrimTetra.C:398
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
Definition: GA_Detail.h:185
RE_CacheVersion instance_version
GR_Decoration
Definition: GR_Defines.h:151
float fpreal32
Definition: SYS_Types.h:200
Temporary container for either a RV_Render and an RE_Render.
const char * getCacheName() const
The base GL cache name assigned to this primitive.
Definition: GR_Primitive.h:371
SIM_DerVector3 normalize() const
set of parameters sent to GR_Primitive::update()
GR_PrimAcceptResult acceptPrimitive(GT_PrimitiveType t, int geo_type, const GT_PrimitiveHandle &ph, const GEO_Primitive *prim) override
Definition: GR_PrimTetra.C:80
GR_RenderMode
Definition: GR_Defines.h:47
const GR_DisplayOption & dopts
GR_DecorRenderFlags render_flags
const GR_DisplayOption * opts
Definition: GR_DrawParms.h:22
int renderPick(RE_RenderContext r, const GR_DisplayOption *opt, unsigned int pick_type, GR_PickStyle pick_style, bool has_pick_map) override
Definition: GR_PrimTetra.C:409
const GR_LightList * getLightList() const
int pushShader()
void bindForShader(RE_Render *r, RE_Shader *sh) const
RE_Shader * getShader()
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CLI11.h:985
GR_API bool buildInstanceObjectMatrix(RE_Render *r, const GT_PrimitiveHandle &h, const GR_UpdateParms &p, RE_Geometry *geo, RE_CacheVersion version, int instance_group=0, UT_Matrix4D *transform=NULL)
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:112
SYS_FORCE_INLINE int get() const
SYS_FORCE_INLINE GA_Offset vertexPoint(GA_Offset vertex) const
Given a vertex, return the point it references.
Definition: GA_Detail.h:529
RE_CacheVersion getCacheVersion() const
GR_PrimAcceptResult
Definition: GR_Defines.h:345
void polygonOffset(bool onoff)
GR_RenderFlags
Definition: GR_Defines.h:85
exint append()
Definition: UT_Array.h:142
#define RE_GEO_SHADED_IDX
Definition: RE_Geometry.h:44
void render(RE_RenderContext r, GR_RenderMode render_mode, GR_RenderFlags flags, GR_DrawParms dp) override
Definition: GR_PrimTetra.C:275
GLdouble t
Definition: glad.h:2397
GT_PrimitiveType
const RE_MaterialAtlas * materials
Definition: GR_DrawParms.h:23
void setCacheVersion(RE_CacheVersion v)
GR_API void buildInstanceIndex(RE_Render *r, RE_Geometry *geo, bool has_partial_visibility, const UT_IntArray &inst_indices, int instance_group, int max_capacity)
GLuint shader
Definition: glcorearb.h:785
int connectAllPrims(RE_Render *r, int connect_index, RE_PrimType prim, const RE_MaterialPtr &mat=nullptr, bool replace=false, int vertices_per_patch=0)
Primitive Connectivity .
RE_VertexArray * createConstAttribute(RE_Render *r, const char *attrib_name, RE_GPUType data_format, int vectorsize, const void *data)
Create a constant attribute value Only RE_GPU_FLOAT32 and _FLOAT64 are supported for constant data...
const RE_MaterialPtr & getFactoryMaterial() const
Definition: RE_Material.h:1058
void update(RE_RenderContext r, const GT_PrimitiveHandle &primh, const GR_UpdateParms &p) override
Definition: GR_PrimTetra.C:93
#define RE_GEO_WIRE_IDX
Definition: RE_Geometry.h:43
GR_Primitive * createPrimitive(const GT_PrimitiveHandle &gt_prim, const GEO_Primitive *geo_prim, const GR_RenderInfo *info, const char *cache_name, GR_PrimAcceptResult &processed) override
Definition: GR_PrimTetra.C:54
virtual void removeOverrideBlocks()
Remove all override blocks from the shader.
Definition: RE_Shader.h:728
GR_DecorationOverride required_dec
SYS_FORCE_INLINE GA_Offset getVertexOffset(GA_Size primvertexnum) const
Definition: GA_Primitive.h:240
void * map(RE_Render *r, RE_BufferAccess access=RE_BUFFER_WRITE_ONLY, int array_index=0)
GR_PrimTetra(const GR_RenderInfo *info, const char *cache_name, const GEO_Primitive *prim)
Definition: GR_PrimTetra.C:63
bool cacheBuffers(const char *name)
Caching .
void setupFromDisplayOptions(const GR_DisplayOption &opts, GR_DecorationOverride select_dec, GR_UpdateParms &parms, const GR_Decoration *supported, GR_AttribMask mask)
GLboolean r
Definition: glcorearb.h:1222
void drawDecorationForGeo(RE_RenderContext r, RE_Geometry *geo, GR_Decoration dec, const GR_DisplayOption *opts, GR_DecorRenderFlags flags, bool overlay, bool override_vis, int instance_group, GR_SelectMode smode, GR_DecorationRender::PrimitiveType t=GR_DecorationRender::PRIM_TRIANGLE, RE_OverrideList *override_list=NULL)
bool setNumPoints(int num)
Number of points in the geometry. Number of points for the arrays declared as RE_ARRAY_POINT. This will clear the data in all point arrays and reset the connectivty.
RE_VertexArray * findCachedAttrib(RE_Render *r, const char *attrib_name, RE_GPUType data_format, int vectorsize, RE_ArrayType array_type, bool create_if_missing=false, int random_array_size=-1, const RE_CacheVersion *cv=nullptr, RE_BufferUsageHint h=RE_BUFFER_WRITE_FREQUENT, const char *cache_prefix=nullptr, int capacity=-1)
Find an attribute or array in the GL cache, possibly creating it Returns the cached array...
Definition: RE_Geometry.h:880
bool isVulkan() const
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
const GU_Detail * getGdp() const
void popShader(int *nest=nullptr)
void bindShader(RE_Shader *s)
bool draw_instanced
Definition: GR_DrawParms.h:27
Simple interface to building a shader from a .prog file.
const RE_LightList * glLights() const
Definition: GR_Light.h:127
GR_PickStyle
Definition: GR_Defines.h:240