LightsprintSDK 2021.08.08
rr::RRMesh Class Referenceabstract

#include <RRMesh.h>

Inheritance diagram for rr::RRMesh:
rr::RRUniformlyAllocatedNonCopyable rr::RRUniformlyAllocated rr::RRMeshArrays

Classes

struct  PreImportNumber
 
struct  TangentBasis
 
struct  Triangle
 
struct  TriangleBody
 
struct  TriangleMapping
 
struct  TriangleNormals
 

Public Types

enum  { UNDEFINED = UINT_MAX }
 
enum  TangentSpaceState {
  TSS_PERFECT ,
  TSS_NOT_ORTHOGONAL ,
  TSS_DENORMALIZED ,
  TSS_INVALID ,
  TSS_MISSING
}
 
enum  Format {
  UINT8 = 0 ,
  UINT16 = 1 ,
  UINT32 = 2 ,
  FLOAT32 = 4
}
 
enum  Flags {
  TRI_LIST = 0 ,
  TRI_STRIP = (1<<0) ,
  OPTIMIZED_VERTICES = (1<<1) ,
  OPTIMIZED_TRIANGLES = (1<<2)
}
 
typedef RRVec3 Vertex
 

Public Member Functions

 RRMesh ()
 
virtual ~RRMesh ()
 
virtual unsigned getNumVertices () const =0
 
virtual void getVertex (unsigned v, Vertex &out) const =0
 
virtual unsigned getNumTriangles () const =0
 
virtual void getTriangle (unsigned t, Triangle &out) const =0
 
virtual void getTriangleBody (unsigned t, TriangleBody &out) const
 
virtual bool getTrianglePlane (unsigned t, RRVec4 &out) const
 
virtual RRReal getTriangleArea (unsigned t) const
 
virtual void getTriangleNormals (unsigned t, TriangleNormals &out) const
 
virtual bool getTriangleMapping (unsigned t, TriangleMapping &out, unsigned channel) const
 
virtual PreImportNumber getPreImportVertex (unsigned postImportVertex, unsigned postImportTriangle) const
 
virtual unsigned getPostImportVertex (PreImportNumber preImportVertex, PreImportNumber preImportTriangle) const
 
virtual PreImportNumber getPreImportTriangle (unsigned postImportTriangle) const
 
virtual unsigned getPostImportTriangle (PreImportNumber preImportTriangle) const
 
unsigned getNumPreImportVertices () const
 
virtual void getUvChannels (RRVector< unsigned > &out) const
 
virtual void getAABB (RRVec3 *mini, RRVec3 *maxi, RRVec3 *center) const
 
virtual RRReal getAverageVertexDistance () const
 
virtual RRReal getMappingDensity (unsigned channel) const
 
virtual RRReal findGroundLevel () const
 
virtual RRHash getHash () const
 
TangentSpaceState checkNormals () const
 
TangentSpaceState checkTangents () const
 
virtual unsigned checkConsistency (unsigned lightmapTexcoord, const char *meshName, class NumReports *numReports=nullptr) const
 
RRMeshcreateTransformed (const RRMatrix3x4Ex *transform) const
 
const RRMeshcreateOptimizedVertices (float maxDistanceBetweenVerticesToMerge, float maxRadiansBetweenNormalsToMerge, float maxDistanceBetweenUvsToMerge, const RRVector< unsigned > *texcoords) const
 
const RRMeshcreateOptimizedTriangles () const
 
const RRMeshcreateAccelerated () const
 
RRMeshcreateVertexBufferRuler () const
 
class RRMeshArrayscreateArrays (bool indexed, const RRVector< unsigned > &texcoords, bool tangents) const
 
- Public Member Functions inherited from rr::RRUniformlyAllocated
void * operator new (std::size_t n)
 
void * operator new[] (std::size_t n)
 
void operator delete (void *p, std::size_t n)
 
void operator delete[] (void *p, std::size_t n)
 

Static Public Member Functions

static RRMeshcreate (unsigned flags, Format vertexFormat, void *vertexBuffer, unsigned vertexCount, unsigned vertexStride)
 
static RRMeshcreateIndexed (unsigned flags, Format vertexFormat, void *vertexBuffer, unsigned vertexCount, unsigned vertexStride, Format indexFormat, void *indexBuffer, unsigned indexCount, float vertexStitchMaxDistance=0)
 
static const RRMeshcreateMultiMesh (const RRMesh *const *meshes, unsigned numMeshes, bool fast)
 

Protected Attributes

struct AABBCache * aabbCache
 

Additional Inherited Members

- Protected Member Functions inherited from rr::RRUniformlyAllocatedNonCopyable
 RRUniformlyAllocatedNonCopyable ()
 
 ~RRUniformlyAllocatedNonCopyable ()
 

Detailed Description

Common interface for any standard or proprietary triangle mesh structure.

RRMesh is typically only several bytes big adaptor, it provides unified interface to your mesh, but it uses your mesh data, no data need to be duplicated.

Thread safe: yes, may be accessed by any number of threads simultaneously.

Creating instances

RRMesh has built-in support for standard mesh formats used by rendering APIs - vertex and index buffers using triangle lists or triangle strips. See create() and createIndexed().

RRMesh has built-in support for baking multiple meshes into one mesh (without need for additional memory). This may simplify mesh oprations or improve performance in some situations. See createMultiMesh().

RRMesh has built-in support for creating self-contained mesh copies. See createCopy(). While importers created from vertex buffer doesn't allocate more memory and depend on vertex buffer, self-contained copy contains all mesh data and doesn't depend on any other objects.

For other mesh formats (heightfield, realtime generated etc), you may easily derive from RRMesh and create your own mesh adaptor.

Optimizations

RRMesh may help you with mesh optimizations if requested, for example by removing duplicate vertices or degenerated triangles.

Constancy

All data provided by RRMesh must be constant in time. Built-in importers guarantee constancy if you don't change their vertex/index buffers. Constancy of mesh copy is guaranteed always.

Indexing

RRMesh operates with two types of vertex and triangle indices.

  1. PostImport indices, always 0..num-1 (where num=getNumTriangles or getNumVertices), these are used in most calls. When not stated otherwise, index is PostImport.
    Example: with 100-triangle mesh, triangle indices are 0..99.
  2. PreImport indices, optional, arbitrary numbers provided by importer for your convenience.
    Example: could be offsets into your vertex buffer.
    Pre<->Post mapping is defined by RRMesh implementation and is arbitrary, but constant.

All Pre-Post conversion functions must accept all unsigned values. When query makes no sense, they return UNDEFINED. This is because

  1. valid PreImport numbers may be spread across whole unsigned range and caller could be unaware of their validity.
  2. such queries are rare and not performance critical.

All other function use PostImport numbers and may support only their 0..num-1 range. When called with out of range value, result is undefined. Debug version may return arbitrary number or throw assert. Release version may return arbitrary number or crash. This is because

  1. valid PostImport numbers are easy to ensure on caller side.
  2. such queries are very critical for performance.

Front/back side

For correct lighting, it's important to know where front and back sides of triangle are. Materials (see RRMaterial) define some properties separately for both sides of triangle. Renderers render both sides of triangle differently.

When you see triangle vertices in CCW order, you see triangle's front side. In this situation triangle's normal must point to your (front) hemisphere.

Some applications are known to define front/back differently:

  • 3DS MAX
  • Quake3

How to swap front/back sides, when importing data from such applications?

  • Negate positions and normals in any 1 axis. If you don't provide normals in your mesh, negate positions only. See example in RRObjectBSP.cpp, getVertex.
  • Or swap any 2 vertices in triangle.

Member Typedef Documentation

◆ Vertex

One vertex 3d space.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
Enumerator
UNDEFINED 

Index value reserved for situations where result is undefined, for example because of invalid inputs.

◆ TangentSpaceState

Tangent space issues sorted by seriousness.

Enumerator
TSS_PERFECT 
TSS_NOT_ORTHOGONAL 
TSS_DENORMALIZED 
TSS_INVALID 
TSS_MISSING 

◆ Format

Identifiers of data formats.

Enumerator
UINT8 

Id of uint8_t.

UINT16 

Id of uint16_t.

UINT32 

Id of uint32_t.

FLOAT32 

Id of float.

◆ Flags

Flags that help to specify your create() or createIndexed() request.

Enumerator
TRI_LIST 

Interpret data as triangle list.

TRI_STRIP 

Interpret data as triangle strip.

OPTIMIZED_VERTICES 

Remove identical and unused vertices.

OPTIMIZED_TRIANGLES 

Remove degenerated triangles.

Constructor & Destructor Documentation

◆ RRMesh()

rr::RRMesh::RRMesh ( )

◆ ~RRMesh()

virtual rr::RRMesh::~RRMesh ( )
virtual

Member Function Documentation

◆ getNumVertices()

virtual unsigned rr::RRMesh::getNumVertices ( ) const
pure virtual

Returns number of vertices in mesh.

Implemented in rr::RRMeshArrays.

◆ getVertex()

virtual void rr::RRMesh::getVertex ( unsigned  v,
Vertex out 
) const
pure virtual

Writes position of v-th vertex in mesh to out.

Make sure you provide valid v is in range <0..getNumVertices()-1>. Implementations are allowed to expect valid v, result is undefined for invalid v (possible assert in debug, crash in release).

What exactly is vertex, do boxes have 8 or 24 vertices?
RRMesh, RRCollider and RRObject create no constraints, you are free to use your favorite approach - create box with 8 or 24 or any other number of vertices greater than 8, collisions and illumination will be computed correctly. (24 because each one of 8 vertices is used by 3 sides with different normal)
RRSolver depends on vertex list defined here. If you request vertex buffer with per-vertex illumination, vertex buffer will have getNumVertices() items. So when writing new RRMesh implementations, create vertex list so that vertex buffers with the same size and vertex order are compatible with your renderer.

Implemented in rr::RRMeshArrays.

◆ getNumTriangles()

virtual unsigned rr::RRMesh::getNumTriangles ( ) const
pure virtual

Returns number of triangles in mesh.

Implemented in rr::RRMeshArrays.

◆ getTriangle()

virtual void rr::RRMesh::getTriangle ( unsigned  t,
Triangle out 
) const
pure virtual

Writes t-th triangle in mesh to out.

Make sure you provide valid t in range <0..getNumTriangles()-1>. Implementators are allowed to expect valid t (performance reasons, may be called very often), so result is completely undefined for invalid t (possible crash).

Order of vertices in triangle has influence on what side of triangle is front, which is important for lighting. See more details in Front/back side.

Implemented in rr::RRMeshArrays.

◆ getTriangleBody()

virtual void rr::RRMesh::getTriangleBody ( unsigned  t,
TriangleBody out 
) const
virtual

Writes t-th triangle in mesh to out.

Make sure you provide valid t in range <0..getNumTriangles()-1>. Implementators are allowed to expect valid t, so result is completely undefined for invalid t (possible crash).
There is default implementation, but if you know format of your data well, you may provide faster one.
Speed of this function is important for intersection tests performance.

Reimplemented in rr::RRMeshArrays.

◆ getTrianglePlane()

virtual bool rr::RRMesh::getTrianglePlane ( unsigned  t,
RRVec4 out 
) const
virtual

Writes t-th triangle plane to out.

Be sure to provide valid t is in range <0..getNumTriangles()-1>. Implementators are allowed to expect valid t, so result is completely undefined for invalid t (possible crash).
There is default implementation, but if you know format of your data well, you may provide faster one.

◆ getTriangleArea()

virtual RRReal rr::RRMesh::getTriangleArea ( unsigned  t) const
virtual

Returns area of t-th triangle.

Be sure to provide valid t is in range <0..getNumTriangles()-1>. Implementators are allowed to expect valid t, so result is completely undefined for invalid t (possible crash).
There is default implementation, but if you know format of your data well, you may provide faster one.

◆ getTriangleNormals()

virtual void rr::RRMesh::getTriangleNormals ( unsigned  t,
TriangleNormals out 
) const
virtual

Writes tangent bases in triangle vertices to out. Normals are part of bases.

Tangent bases are used by global illumination solver and renderer. Normals should point to front side hemisphere, see Front/back side.
Default implementation writes all vertex normals equal to triangle plane normal and constructs appropriate tangent space.

Parameters
tIndex of triangle. Valid t is in range <0..getNumTriangles()-1>.
outCaller provided storage for result. For valid t, requested normals are written to out. For invalid t, out stays unmodified.

Reimplemented in rr::RRMeshArrays.

◆ getTriangleMapping()

virtual bool rr::RRMesh::getTriangleMapping ( unsigned  t,
TriangleMapping out,
unsigned  channel 
) const
virtual

Writes t-th triangle's uv mapping to out.

Parameters
tIndex of triangle. Valid t is in range <0..getNumTriangles()-1>.
outCaller provided storage for result. For valid t, requested mapping is written to out. For invalid t, out stays unmodified.
channelTexcoord channel to use, RRMaterial::diffuseReflectance.texcoord for diffuse texture mapping, RRMaterial::lightmap.texcoord for unwrap used by lightmaps etc.
Note that for proper lighting, unwrap must have all coordinates in <0..1> range and triangles must not overlap. Unwrap may be imported or automatically generated by RRObjects::buildUnwrap().
Returns
True for valid t and supported channel, result was written to out. False for invalid t or unsupported channel, out stays unmodified.

Reimplemented in rr::RRMeshArrays.

◆ getPreImportVertex()

virtual PreImportNumber rr::RRMesh::getPreImportVertex ( unsigned  postImportVertex,
unsigned  postImportTriangle 
) const
inlinevirtual

Returns PreImport index of given vertex or UNDEFINED for invalid inputs.

◆ getPostImportVertex()

virtual unsigned rr::RRMesh::getPostImportVertex ( PreImportNumber  preImportVertex,
PreImportNumber  preImportTriangle 
) const
inlinevirtual

Returns PostImport index of given vertex or UNDEFINED for invalid inputs.

◆ getPreImportTriangle()

virtual PreImportNumber rr::RRMesh::getPreImportTriangle ( unsigned  postImportTriangle) const
inlinevirtual

Returns PreImport index of given triangle or UNDEFINED for invalid inputs.

◆ getPostImportTriangle()

virtual unsigned rr::RRMesh::getPostImportTriangle ( PreImportNumber  preImportTriangle) const
inlinevirtual

Returns PostImport index of given triangle or UNDEFINED for invalid inputs.

◆ getNumPreImportVertices()

unsigned rr::RRMesh::getNumPreImportVertices ( ) const

Returns highest PreImport vertex number+1.

PreImport numbers are used as positions of vertices in vertex buffer, so returned number is also size of vertex buffer. Very slow (checks all vertices).

◆ getUvChannels()

virtual void rr::RRMesh::getUvChannels ( RRVector< unsigned > &  out) const
virtual

Fills out with uv channels provided by mesh, in ascending order. Default implementation queries presence of channels 0 to 100, ignores higher channels.

Reimplemented in rr::RRMeshArrays.

◆ getAABB()

virtual void rr::RRMesh::getAABB ( RRVec3 mini,
RRVec3 maxi,
RRVec3 center 
) const
virtual

Returns axis aligned bounding box and center of mesh. Fast (cached).

Parameters
mininullptr or pointer to vec3 to be filled with minimum of computed AABB.
maxinullptr or pointer to vec3 to be filled with maximum of computed AABB.
centernullptr or pointer to vec3 to be filled with average vertex position.

Reimplemented in rr::RRMeshArrays.

◆ getAverageVertexDistance()

virtual RRReal rr::RRMesh::getAverageVertexDistance ( ) const
virtual

Returns average distance between two vertices. Slow (not cached).

◆ getMappingDensity()

virtual RRReal rr::RRMesh::getMappingDensity ( unsigned  channel) const
virtual

Returns median of (edge_length / edge_length_in_texture_space). Slow (not cached).

◆ findGroundLevel()

virtual RRReal rr::RRMesh::findGroundLevel ( ) const
virtual

Returns y coordinate of plane where triangles facing straight up have the biggest total area. In CG scenes, this is usually flat ground. Slow (not cached).

◆ getHash()

virtual RRHash rr::RRMesh::getHash ( ) const
virtual

Returns hash of mesh geometry (positions, not normals and uvs). Slow (not cached).

◆ checkNormals()

TangentSpaceState rr::RRMesh::checkNormals ( ) const

◆ checkTangents()

TangentSpaceState rr::RRMesh::checkTangents ( ) const

◆ checkConsistency()

virtual unsigned rr::RRMesh::checkConsistency ( unsigned  lightmapTexcoord,
const char *  meshName,
class NumReports *  numReports = nullptr 
) const
virtual

Reports inconsistencies found in mesh.

Parameters
lightmapTexcoordOptional lightmap texcoord channel (it is stored in RRMaterial::lightmap.texcoord). UINT_MAX disables unwrap check.
meshNameOptional mesh name included in report if inconsistency is found. May be nullptr.
numReportsReserved, keep it nullptr.
Returns
Number of problem reported, 0 for valid mesh.

◆ create()

static RRMesh * rr::RRMesh::create ( unsigned  flags,
Format  vertexFormat,
void *  vertexBuffer,
unsigned  vertexCount,
unsigned  vertexStride 
)
static

Creates RRMesh from your vertex buffer.

Parameters
flagsSee Flags. Note that optimizations are not implemented for triangle lists, OPTIMIZE_XXX flags will be silently ignored.
vertexFormatFormat of data in your vertex buffer. See Format. Currently only FLOAT32 is supported.
vertexBufferYour vertex buffer.
vertexCountNumber of vertices in your vertex buffer.
vertexStrideDistance (in bytes) between n-th and (n+1)th vertex in your vertex buffer.
Returns
Newly created instance of RRMesh or nullptr in case of unsupported or invalid inputs.

◆ createIndexed()

static RRMesh * rr::RRMesh::createIndexed ( unsigned  flags,
Format  vertexFormat,
void *  vertexBuffer,
unsigned  vertexCount,
unsigned  vertexStride,
Format  indexFormat,
void *  indexBuffer,
unsigned  indexCount,
float  vertexStitchMaxDistance = 0 
)
static

Creates RRMesh from your vertex and index buffers.

Parameters
flagsSee Flags.
vertexFormatFormat of data in your your vertex buffer. See Format. Currently only FLOAT32 is supported.
vertexBufferYour vertex buffer.
vertexCountNumber of vertices in your vertex buffer.
vertexStrideDistance (in bytes) between n-th and (n+1)th vertex in your vertex buffer.
indexFormatFormat of data in your index buffer. See Format. Only UINT8, UINT16 and UINT32 is supported.
indexBufferYour index buffer.
indexCountNumber of indices in your index buffer.
vertexStitchMaxDistanceMax distance for vertex stitching. For default 0, vertices with equal coordinates are stitched and get equal vertex index (number of vertices returned by getNumVertices() is then lower). For negative value, no stitching is performed. For positive value, also vertices in lower or equal distance will be stitched.
Returns
Newly created instance of RRMesh or nullptr in case of unsupported or invalid inputs.

◆ createTransformed()

RRMesh * rr::RRMesh::createTransformed ( const RRMatrix3x4Ex transform) const

Creates and returns transformed mesh.

Created instance doesn't require additional memory, but it depends on 'this' mesh and 'transform' matrix, both must stay alive for whole life of created instance. You can even modify 'this' and 'transform' later and created mesh gets modified too.

Usually used when mesh in world space is needed and we have mesh in local space. In this case, world space matrix (the one that transforms from local to world) should be passed in transform.

Only positions/normals/tangent space are transformed, custom channels are left untouched.

Non-uniform transformations break tangent space orthogonality.

◆ createMultiMesh()

static const RRMesh * rr::RRMesh::createMultiMesh ( const RRMesh *const *  meshes,
unsigned  numMeshes,
bool  fast 
)
static

Creates and returns union of multiple meshes (contains vertices and triangles of all meshes).

Created instance (MultiMesh) doesn't require additional memory, but it depends on all meshes from array, they must stay alive for whole life of MultiMesh.
This can be used to accelerate calculations, as one big object is nearly always faster than multiple small objects.
This can be used to simplify calculations, as processing one object may be simpler than processing array of objects.
For array with 1 element, pointer to that element may be returned.

If you need to locate original triangles and vertices in MultiMesh, you have two choices:

  1. Use PreImpport<->PostImport conversions. PreImport number for MultiMesh is defined as PreImportNumber. If you want to access triangle 2 in meshes[1], calculate index of triangle in MultiMesh as indexOfTriangle = multiMesh->getPostImportTriangle(PreImportNumber(1,2)).
  2. Convert indices yourself. It is granted, that both indices and vertices preserve order of meshes in array: lowest indices belong to meshes[0], meshes[1] follow etc. If you create MultiMesh from 2 meshes, first with 3 vertices and second with 5 vertices, they will transform into 0,1,2 and 3,4,5,6,7 vertices in MultiMesh.
    Parameters
    meshesArray of meshes, source data for MultiMesh.
    numMeshesLength of 'meshes' array.
    fastWith false, multimesh has fixed size of several bytes. With true, multimesh allocates 8 bytes per triangle, but it is faster, especially in scenes made of hundreds of small meshes.

◆ createOptimizedVertices()

const RRMesh * rr::RRMesh::createOptimizedVertices ( float  maxDistanceBetweenVerticesToMerge,
float  maxRadiansBetweenNormalsToMerge,
float  maxDistanceBetweenUvsToMerge,
const RRVector< unsigned > *  texcoords 
) const

Creates and returns nearly identical mesh with optimized set of vertices (removes unused and redundant ones).

Merges identical or similar vertices so that number of vertices in returned mesh decreases. Only vertex positions, normals and uvs are tested, so vertices with completely different tangents may be merged.

Created instance requires only small amount of additional memory, but it depends on 'this' mesh, 'this' must stay alive for whole life of created instance. If no vertex can be removed, 'this' is returned.

Parameters
maxDistanceBetweenVerticesToMergeVertices are not merged if their positions differ more. If negative, vertices are never merged, but unused ones can still be removed.
maxRadiansBetweenNormalsToMergeVertices are not merged if their normals differ more. If negative, vertices are never merged, but unused ones can still be removed.
maxDistanceBetweenUvsToMergeVertices are not merged if their uvs from texcoords differ more.
texcoordsVertices are not merged if their uvs from texcoords differ more than maxDistanceBetweenUvsToMerge. May be nullptr. Uvs not listed in texcoords are ignored, differences in such channels don't prevent merging.

◆ createOptimizedTriangles()

const RRMesh * rr::RRMesh::createOptimizedTriangles ( ) const

Creates and returns identical mesh with optimized set of triangles (removes degenerated triangles).

Created instance requires only small amount of additional memory, but it depends on 'this' mesh, 'this' must stay alive for whole life of created instance. If 'this' is already optimal, 'this' is returned. Note that after removal of degenrated triangles, there might be unused vertices in mesh; you can use createOptimizedVertices() to remove them.

◆ createAccelerated()

const RRMesh * rr::RRMesh::createAccelerated ( ) const

Creates and returns accelerated mesh.

Created instance caches all TriangleBase and TriangleNormals for whole mesh, so it allocates 144 bytes per triangle. It still depends on 'this' mesh, 'this' must stay alive for whole life of created instance.

It is very efficient when applied on multimesh made of hundreds of smaller meshes. It accelerates getTriangleBase() and getTriangleNormals(). These functions are critical for performance of BSP_COMPACT and BSP_FAST colliders. Colliders are critical for performance of lightmap building.

In practice, this function is not needed for lightmap building, use collider types BSP_COMPACT, BSP_FAST, BSP_FASTER, BSP_FASTEST in RRSolver::setStaticObjects() to trade performance / memory.

◆ createVertexBufferRuler()

RRMesh * rr::RRMesh::createVertexBufferRuler ( ) const

Creates and returns identical mesh with all optimizations and filters previously applied baked.

Created instance doesn't require additional memory, but it depends on 'this' mesh, 'this' must stay alive for whole life of created instance.

All other mesh filters and optimizers let you convert between original and new triangle and vertex numbers using getPreImportVertex() and getPreImportTriangle(). This filter only erases original (preImport) numbers and sets them equal to current (postImport) numbers. PreImport numbers are used by RRSolver for vertex buffer layout, so this filter adjusts layout of generated vertex buffers to use current vertex numbers.

◆ createArrays()

class RRMeshArrays * rr::RRMesh::createArrays ( bool  indexed,
const RRVector< unsigned > &  texcoords,
bool  tangents 
) const

Creates mesh with direct read-write access to internal data arrays.

Created mesh does not depend on the old one, it's safe to delete the old one.
Note that created mesh contains reduced set of data

  • only selected texcoords
  • if indexed=true, shared vertex can't have different normal/tangents/mappings in different triangles
  • Pre/PostImportNumbers are lost

Member Data Documentation

◆ aabbCache

struct AABBCache* rr::RRMesh::aabbCache
protected