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