DART 6.12.2
Loading...
Searching...
No Matches
HeightmapShapeNode.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011-2021, The DART development contributors
3 * All rights reserved.
4 *
5 * The list of contributors can be found at:
6 * https://github.com/dartsim/dart/blob/master/LICENSE
7 *
8 * This file is provided under the following "BSD-style" License:
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
11 * conditions are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#ifndef DART_GUI_OSG_RENDER_HEIGHTMAPSHAPENODE_HPP_
34#define DART_GUI_OSG_RENDER_HEIGHTMAPSHAPENODE_HPP_
35
36#include <osg/CullFace>
37#include <osg/Geode>
38#include <osg/Geometry>
39#include <osg/Light>
40#include <osg/Material>
41#include <osg/MatrixTransform>
42#include <osg/ShapeDrawable>
43
44#include "dart/config.hpp"
49
50namespace dart {
51namespace gui {
52namespace osg {
53namespace render {
54
55template <typename S>
56class HeightmapShapeGeode;
57
58template <typename S_>
59class HeightmapShapeNode : public ShapeNode, public ::osg::MatrixTransform
60{
61public:
62 using S = S_;
63
65 std::shared_ptr<dynamics::HeightmapShape<S>> shape,
66 ShapeFrameNode* parent);
67
68 void refresh() override;
69 void extractData(bool firstTime);
70
71protected:
72 virtual ~HeightmapShapeNode() override;
73
74 std::shared_ptr<dynamics::HeightmapShape<S>> mHeightmapShape;
76 std::size_t mHeightmapVersion;
77};
78
79//==============================================================================
80template <typename S>
81class HeightmapShapeDrawable : public ::osg::Geometry
82{
83public:
84 using Vector3 = Eigen::Matrix<S, 3, 1>;
85
86 using osgVec3 = typename std::conditional<
87 std::is_same<S, float>::value,
88 ::osg::Vec3f,
89 ::osg::Vec3d>::type;
90 using Vec3Array = typename std::conditional<
91 std::is_same<S, float>::value,
92 ::osg::Vec3Array,
93 ::osg::Vec3dArray>::type;
94 using Vec4Array = typename std::conditional<
95 std::is_same<S, float>::value,
96 ::osg::Vec4Array,
97 ::osg::Vec4dArray>::type;
98
103
104 void refresh(bool firstTime);
105
106protected:
107 ~HeightmapShapeDrawable() override = default;
108
112
113private:
114 ::osg::ref_ptr<Vec3Array> mVertices;
115 ::osg::ref_ptr<::osg::DrawElementsUInt> mElements;
116 ::osg::ref_ptr<Vec3Array> mNormals;
117 ::osg::ref_ptr<::osg::Vec4Array> mColors;
118};
119
120//==============================================================================
121template <typename S>
122class HeightmapShapeGeode : public ShapeNode, public ::osg::Geode
123{
124public:
127 ShapeFrameNode* parentShapeFrame,
128 HeightmapShapeNode<S>* parentNode);
129
130 void refresh();
131 void extractData();
132
133protected:
134 virtual ~HeightmapShapeGeode();
135
139};
140
141//==============================================================================
142template <typename S>
144 std::shared_ptr<dynamics::HeightmapShape<S>> shape, ShapeFrameNode* parent)
145 : ShapeNode(shape, parent, this),
146 mHeightmapShape(shape),
147 mGeode(nullptr),
148 mHeightmapVersion(dynamics::INVALID_INDEX)
149{
150 extractData(true);
151 setNodeMask(mVisualAspect->isHidden() ? 0x0u : ~0x0u);
152}
153
154//==============================================================================
155template <typename S>
157{
158 mUtilized = true;
159
160 setNodeMask(mVisualAspect->isHidden() ? 0x0u : ~0x0u);
161
162 if (mShape->getDataVariance() == dynamics::Shape::STATIC
163 && mHeightmapVersion == mHeightmapShape->getVersion())
164 return;
165
166 extractData(false);
167
168 mHeightmapVersion = mHeightmapShape->getVersion();
169}
170
171//==============================================================================
172template <typename S>
174{
175 if (nullptr == mGeode)
176 {
177 mGeode = new HeightmapShapeGeode<S>(
178 mHeightmapShape.get(), mParentShapeFrameNode, this);
179 addChild(mGeode);
180 return;
181 }
182
183 mGeode->refresh();
184}
185
186//==============================================================================
187template <typename S>
189{
190 // Do nothing
191}
192
193//==============================================================================
194template <typename S>
197 ShapeFrameNode* parentShapeFrame,
198 HeightmapShapeNode<S>* parentNode)
199 : ShapeNode(parentNode->getShape(), parentShapeFrame, this),
200 mParentNode(parentNode),
201 mHeightmapShape(shape),
202 mDrawable(nullptr)
203{
204 getOrCreateStateSet()->setMode(GL_BLEND, ::osg::StateAttribute::ON);
205 getOrCreateStateSet()->setRenderingHint(::osg::StateSet::TRANSPARENT_BIN);
206 getOrCreateStateSet()->setAttributeAndModes(
207 new ::osg::CullFace(::osg::CullFace::BACK));
208 getOrCreateStateSet()->setMode(GL_LIGHTING, ::osg::StateAttribute::ON);
209 extractData();
210}
211
212//==============================================================================
213template <typename S>
215{
216 mUtilized = true;
217
218 extractData();
219}
220
221//==============================================================================
222template <typename S>
224{
225 if (nullptr == mDrawable)
226 {
227 mDrawable
228 = new HeightmapShapeDrawable<S>(mHeightmapShape, mVisualAspect, this);
229 addDrawable(mDrawable);
230 return;
231 }
232
233 mDrawable->refresh(false);
234}
235
236//==============================================================================
237template <typename S>
242
243//==============================================================================
244template <typename S>
249 : mHeightmapShape(shape), mVisualAspect(visualAspect), mParent(parent)
250{
251 static_assert(
252 std::is_same<S, float>::value || std::is_same<S, double>::value,
253 "Scalar type should be float or double");
254
255 // See:
256 // https://osg-users.openscenegraph.narkive.com/VY16YIMs/crash-due-to-triangle-functor-does-not-support-vec3d-vertex-arrays
257 // https://github.com/openscenegraph/OpenSceneGraph/blob/5b688eb99dd5db94f7068ee18fb94f120720e3d1/include/osg/TriangleFunctor#L73
258 static_assert(
259 !std::is_same<S, double>::value,
260 "OpenSceneGraph currently doesn't support double precision for "
261 "Heightmap");
262
263 mVertices = new Vec3Array;
264 mNormals = new Vec3Array;
265 mColors = new Vec4Array;
266 // TODO(JS): Switch to TRIANGLE_STRIP to save storage for indicies
267 mElements = new ::osg::DrawElementsUInt(::osg::PrimitiveSet::TRIANGLES);
269 refresh(true);
270}
271
272//==============================================================================
273template <typename S>
274Eigen::Matrix<S, 3, 1> getNormal(
275 const Eigen::Matrix<S, 3, 1>& p1,
276 const Eigen::Matrix<S, 3, 1>& p2,
277 const Eigen::Matrix<S, 3, 1>& p3)
278{
279 return (p2 - p1).cross(p3 - p1).normalized();
280}
281
282//==============================================================================
283inline ::osg::Vec3f getNormal(
284 const ::osg::Vec3f& p1, const ::osg::Vec3f& p2, const ::osg::Vec3f& p3)
285{
286 auto normal = (p2 - p1) ^ (p3 - p1);
287 normal.normalize();
288 return normal;
289}
290
291//==============================================================================
292inline ::osg::Vec3d getNormal(
293 const ::osg::Vec3d& p1, const ::osg::Vec3d& p2, const ::osg::Vec3d& p3)
294{
295 auto normal = (p2 - p1) ^ (p3 - p1);
296 normal.normalize();
297 return normal;
298}
299
300//==============================================================================
301template <typename S>
303 const typename dynamics::HeightmapShape<S>::HeightField& heightmap,
304 typename HeightmapShapeDrawable<S>::Vec3Array& vertices,
305 ::osg::DrawElementsUInt& faces,
306 typename HeightmapShapeDrawable<S>::Vec3Array& normals,
308{
309 // Returns an index array for a GL_TRIANGLES heightmap
310
311 const auto rows = heightmap.rows();
312 const auto cols = heightmap.cols();
313
314 faces.clear();
315 normals.clear();
316 if (rows < 2 || cols < 2)
317 {
318 vertices.clear();
319 return;
320 }
321
322 vertices.resize(static_cast<std::size_t>(heightmap.size()));
323
324 // Note that heightmap(i, j) represents the height value at (j, -i) in XY
325 // coordinates.
326 for (auto i = 0; i < rows; ++i)
327 {
328 for (auto j = 0; j < cols; ++j)
329 {
330 const auto index = cols * i + j;
331 vertices[index].set(
332 j * scale.x(), -(i * scale.y()), heightmap(i, j) * scale.z());
333 }
334 }
335
336 //
337 // X
338 // +----------------------------------------------->
339 // |
340 // | | | |
341 // | | | |
342 // | -----o-----------o------------o-----
343 // | p1(i-1,j-1) | upper / | p2(i-1,j) |
344 // | | / | |
345 // | | / | |
346 // | | / | |
347 // | | / lower | |
348 // | -----o-----------o------------o-----
349 // | p3(i, j-1)| | curr(i, j) | p4(i,j+1)
350 // | | | |
351 // | | | |
352 // | | | |
353 // | | | |
354 // | -----o-----------o------------o-----
355 // | | | p5(i+1,j) |
356 // -Y | | | |
357 // V
358 //
359 //
360
361 // For row-major matrix
362 faces.reserve(6 * (rows - 1) * (cols - 1));
363 for (auto i = 1; i < rows; ++i)
364 {
365 for (auto j = 1; j < cols; ++j)
366 {
367 // Indices for matrix
368 const auto p1i = i - 1;
369 const auto p1j = j - 1;
370
371 const auto p2i = i - 1;
372 const auto p2j = j;
373
374 const auto p3i = i;
375 const auto p3j = j - 1;
376
377 // Indices for vector
378 const auto p1 = p1i * cols + p1j;
379 const auto p2 = p2i * cols + p2j;
380 const auto p3 = p3i * cols + p3j;
381 const auto curr = i * cols + j;
382
383 // Upper triangle
384 faces.push_back(p1);
385 faces.push_back(p3);
386 faces.push_back(p2);
387
388 // Lower triangle
389 faces.push_back(p2);
390 faces.push_back(p3);
391 faces.push_back(curr);
392 }
393 }
394
395 normals.reserve(heightmap.size());
396 for (auto i = 0; i < rows; ++i)
397 {
398 for (auto j = 0; j < cols; ++j)
399 {
400 // Indices for matrix
401 const auto p2i = i - 1;
402 const auto p2j = j;
403
404 const auto p3i = i;
405 const auto p3j = j - 1;
406
407 const auto p4i = i;
408 const auto p4j = j + 1;
409
410 const auto p5i = i + 1;
411 const auto p5j = j;
412
413 // Indices for vector
414 const auto p2 = p2i * cols + p2j;
415 const auto p3 = p3i * cols + p3j;
416 const auto p4 = p4i * cols + p4j;
417 const auto p5 = p5i * cols + p5j;
418 const auto curr = i * cols + j;
419
420 const auto& ptCurr = vertices[curr];
421
422 auto sum = typename HeightmapShapeDrawable<S>::osgVec3();
423
424 if (i > 0 && j > 0)
425 sum += getNormal(ptCurr, vertices[p2], vertices[p3]);
426
427 if (i + 1 < rows && j > 0)
428 sum += getNormal(ptCurr, vertices[p3], vertices[p5]);
429
430 if (i + 1 < rows && j + 1 < cols)
431 sum += getNormal(ptCurr, vertices[p5], vertices[p4]);
432
433 if (i > 0 && j + 1 < cols)
434 sum += getNormal(ptCurr, vertices[p4], vertices[p2]);
435
436 sum.normalize();
437
438 normals.push_back(sum);
439 }
440 }
441}
442
443//==============================================================================
444template <typename S>
446{
447 if (mHeightmapShape->getDataVariance() == dynamics::Shape::STATIC)
448 setDataVariance(::osg::Object::STATIC);
449 else
450 setDataVariance(::osg::Object::DYNAMIC);
451
452 // Row major matrix where top left corner is the height at (0, 0), and bottom
453 // right corner is the height at (rows, -cols) in (x, y) coordinates.
454 const auto& heightmap = mHeightmapShape->getHeightField();
455
456 // This function is called whenever the heightmap version is increased, and
457 // the heightmap could be updated in the version up. So we always update the
458 // heightmap.
459 {
460 assert(mElements);
461 assert(mNormals);
463 heightmap,
464 *mVertices,
465 *mElements,
466 *mNormals,
467 mHeightmapShape->getScale());
468 addPrimitiveSet(mElements);
469
470 setVertexArray(mVertices);
471 setNormalArray(mNormals, ::osg::Array::BIND_PER_VERTEX);
472 }
473
474 // This function is called whenever the heightmap version is increased, and
475 // the color could be updated in the version up. So we always update the
476 // color.
477 {
478 if (mColors->size() != 1)
479 mColors->resize(1);
480
481 (*mColors)[0] = eigToOsgVec4d(mVisualAspect->getRGBA());
482
483 setColorArray(mColors, ::osg::Array::BIND_OVERALL);
484 }
485}
486
487} // namespace render
488} // namespace osg
489} // namespace gui
490} // namespace dart
491
492#endif // DART_GUI_OSG_RENDER_HEIGHTMAPSHAPENODE_HPP_
std::string type
Definition SdfParser.cpp:82
std::size_t index
Definition SkelParser.cpp:1672
Shape for a height map.
Definition HeightmapShape.hpp:47
Eigen::Matrix< S, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > HeightField
Definition HeightmapShape.hpp:53
@ STATIC
Definition Shape.hpp:83
Definition ShapeFrame.hpp:54
bool isHidden() const
True iff the ShapeNode is set to be hidden.
Definition ShapeFrame.cpp:177
Definition ShapeFrameNode.hpp:61
Definition HeightmapShapeNode.hpp:82
Eigen::Matrix< S, 3, 1 > Vector3
Definition HeightmapShapeNode.hpp:84
typename std::conditional< std::is_same< S, float >::value, ::osg::Vec3f, ::osg::Vec3d >::type osgVec3
Definition HeightmapShapeNode.hpp:89
void refresh(bool firstTime)
Definition HeightmapShapeNode.hpp:445
dynamics::VisualAspect * mVisualAspect
Definition HeightmapShapeNode.hpp:110
HeightmapShapeGeode< S > * mParent
Definition HeightmapShapeNode.hpp:111
typename std::conditional< std::is_same< S, float >::value, ::osg::Vec4Array, ::osg::Vec4dArray >::type Vec4Array
Definition HeightmapShapeNode.hpp:97
dynamics::HeightmapShape< S > * mHeightmapShape
Definition HeightmapShapeNode.hpp:109
::osg::ref_ptr<::osg::DrawElementsUInt > mElements
Definition HeightmapShapeNode.hpp:115
::osg::ref_ptr< Vec3Array > mNormals
Definition HeightmapShapeNode.hpp:116
::osg::ref_ptr<::osg::Vec4Array > mColors
Definition HeightmapShapeNode.hpp:117
HeightmapShapeDrawable(dynamics::HeightmapShape< S > *shape, dynamics::VisualAspect *visualAspect, HeightmapShapeGeode< S > *parent)
Definition HeightmapShapeNode.hpp:245
typename std::conditional< std::is_same< S, float >::value, ::osg::Vec3Array, ::osg::Vec3dArray >::type Vec3Array
Definition HeightmapShapeNode.hpp:93
::osg::ref_ptr< Vec3Array > mVertices
Definition HeightmapShapeNode.hpp:114
Definition HeightmapShapeNode.hpp:123
dynamics::HeightmapShape< S > * mHeightmapShape
Definition HeightmapShapeNode.hpp:137
HeightmapShapeDrawable< S > * mDrawable
Definition HeightmapShapeNode.hpp:138
void refresh()
Update all rendering data for this ShapeNode.
Definition HeightmapShapeNode.hpp:214
void extractData()
Definition HeightmapShapeNode.hpp:223
virtual ~HeightmapShapeGeode()
Definition HeightmapShapeNode.hpp:238
HeightmapShapeNode< S > * mParentNode
Definition HeightmapShapeNode.hpp:136
HeightmapShapeGeode(dynamics::HeightmapShape< S > *shape, ShapeFrameNode *parentShapeFrame, HeightmapShapeNode< S > *parentNode)
Definition HeightmapShapeNode.hpp:195
Definition HeightmapShapeNode.hpp:60
HeightmapShapeNode(std::shared_ptr< dynamics::HeightmapShape< S > > shape, ShapeFrameNode *parent)
Definition HeightmapShapeNode.hpp:143
void extractData(bool firstTime)
Definition HeightmapShapeNode.hpp:173
S_ S
Definition HeightmapShapeNode.hpp:62
std::shared_ptr< dynamics::HeightmapShape< S > > mHeightmapShape
Definition HeightmapShapeNode.hpp:74
virtual ~HeightmapShapeNode() override
Definition HeightmapShapeNode.hpp:188
HeightmapShapeGeode< S > * mGeode
Definition HeightmapShapeNode.hpp:75
void refresh() override
Update all rendering data for this ShapeNode.
Definition HeightmapShapeNode.hpp:156
std::size_t mHeightmapVersion
Definition HeightmapShapeNode.hpp:76
Definition ShapeNode.hpp:60
dart::dynamics::VisualAspect * mVisualAspect
Pointer to the VisualAspect associated with this ShapeNode.
Definition ShapeNode.hpp:107
::osg::Vec4d eigToOsgVec4d(const Eigen::MatrixBase< Derived > &vec)
Definition Utils.hpp:137
Eigen::Matrix< S, 3, 1 > getNormal(const Eigen::Matrix< S, 3, 1 > &p1, const Eigen::Matrix< S, 3, 1 > &p2, const Eigen::Matrix< S, 3, 1 > &p3)
Definition HeightmapShapeNode.hpp:274
void setVertices(const typename dynamics::HeightmapShape< S >::HeightField &heightmap, typename HeightmapShapeDrawable< S >::Vec3Array &vertices, ::osg::DrawElementsUInt &faces, typename HeightmapShapeDrawable< S >::Vec3Array &normals, typename HeightmapShapeDrawable< S >::Vector3 scale)
Definition HeightmapShapeNode.hpp:302
Definition BulletCollisionDetector.cpp:60