KiCad PCB EDA Suite
MODEL_3D Class Reference

#include <3d_model.h>

Classes

struct  MATERIAL
 
struct  VERTEX
 

Public Member Functions

 MODEL_3D (const S3DMODEL &a3DModel, MATERIAL_MODE aMaterialMode)
 Load a 3D model. More...
 
 ~MODEL_3D ()
 
void DrawOpaque (bool aUseSelectedMaterial, SFVEC3F aSelectionColor=SFVEC3F(0.0f)) const
 Render the model into the current context. More...
 
void DrawTransparent (float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor=SFVEC3F(0.0f)) const
 Render the model into the current context. More...
 
void Draw (bool aTransparent, float aOpacity, bool aUseSelectedMaterial, const SFVEC3F &aSelectionColor, const glm::mat4 *aModelWorldMatrix, const SFVEC3F *aCameraWorldPos) const
 Render the model into the current context. More...
 
bool HasOpaqueMeshes () const
 Return true if have opaque meshes to render. More...
 
bool HasTransparentMeshes () const
 Return true if have transparent mesh's to render. More...
 
void DrawBbox () const
 Draw main bounding box of the model. More...
 
void DrawBboxes () const
 Draw individual bounding boxes of each mesh. More...
 
const BBOX_3DGetBBox () const
 Get the main bounding box. More...
 

Static Public Member Functions

static void BeginDrawMulti (bool aUseColorInformation)
 Set some basic render states before drawing multiple models. More...
 
static void EndDrawMulti ()
 Cleanup render states after drawing multiple models. More...
 

Static Private Member Functions

static void MakeBbox (const BBOX_3D &aBox, unsigned int aIdxOffset, VERTEX *aVtxOut, GLuint *aIdxOut, const glm::vec4 &aColor)
 

Private Attributes

MATERIAL_MODE m_materialMode
 
BBOX_3D m_model_bbox
 global bounding box for this model More...
 
std::vector< BBOX_3Dm_meshes_bbox
 individual bbox for each mesh More...
 
GLuint m_vertex_buffer = 0
 
GLuint m_index_buffer = 0
 
GLenum m_index_buffer_type = GL_INVALID_ENUM
 
std::vector< MATERIALm_materials
 
bool m_have_opaque_meshes = false
 
bool m_have_transparent_meshes = false
 
GLuint m_bbox_vertex_buffer = 0
 
GLuint m_bbox_index_buffer = 0
 
GLenum m_bbox_index_buffer_type = GL_INVALID_ENUM
 

Static Private Attributes

static const wxChar * m_logTrace = wxT( "KI_TRACE_EDA_OGL_3DMODEL" )
 
static constexpr unsigned int bbox_vtx_count = 8
 
static constexpr unsigned int bbox_idx_count = 24
 

Detailed Description

Definition at line 37 of file 3d_model.h.

Constructor & Destructor Documentation

◆ MODEL_3D()

MODEL_3D::MODEL_3D ( const S3DMODEL a3DModel,
MATERIAL_MODE  aMaterialMode 
)

Load a 3D model.

Note
This must be called inside a gl context.
Parameters
a3DModela 3d model data to load.
aMaterialModea mode to render the materials of the model.

WARNING: Horrible hack here! Somehow, buffer values are being shared between pcbnew and the 3d viewer, which then frees the buffer, resulting in errors in pcbnew. To resolve this temporarily, we generate extra buffers in 3dviewer and use the higher numbers. These are freed on close. todo: Correctly separate the OpenGL contexts to prevent overlapping buffer vals

Definition at line 91 of file 3d_model.cpp.

92{
93 wxLogTrace( m_logTrace, wxT( "MODEL_3D::MODEL_3D %u meshes %u materials" ),
94 static_cast<unsigned int>( a3DModel.m_MeshesSize ),
95 static_cast<unsigned int>( a3DModel.m_MaterialsSize ) );
96
97 auto start_time = std::chrono::high_resolution_clock::now();
98 GLuint buffers[8];
99
107 glGenBuffers( 6, buffers );
108 m_bbox_vertex_buffer = buffers[2];
109 m_bbox_index_buffer = buffers[3];
110 m_vertex_buffer = buffers[4];
111 m_index_buffer = buffers[5];
112
113 // Validate a3DModel pointers
114 wxASSERT( a3DModel.m_Materials != nullptr );
115 wxASSERT( a3DModel.m_Meshes != nullptr );
116 wxASSERT( a3DModel.m_MaterialsSize > 0 );
117 wxASSERT( a3DModel.m_MeshesSize > 0 );
118
119 m_materialMode = aMaterialMode;
120
121 if( a3DModel.m_Materials == nullptr || a3DModel.m_Meshes == nullptr
122 || a3DModel.m_MaterialsSize == 0 || a3DModel.m_MeshesSize == 0 )
123 return;
124
125 // create empty bbox for each mesh. it will be updated when the vertices are copied.
126 m_meshes_bbox.resize( a3DModel.m_MeshesSize );
127
128 // copy materials for later use during rendering.
129 m_materials.reserve( a3DModel.m_MaterialsSize );
130
131 for( unsigned int i = 0; i < a3DModel.m_MaterialsSize; ++i )
132 m_materials.emplace_back( a3DModel.m_Materials[i] );
133
134 // build temporary vertex and index buffers for bounding boxes.
135 // the first box is the outer box.
136 std::vector<VERTEX> bbox_tmp_vertices( ( m_meshes_bbox.size() + 1 ) * bbox_vtx_count );
137 std::vector<GLuint> bbox_tmp_indices( ( m_meshes_bbox.size() + 1 ) * bbox_idx_count );
138
139 // group all meshes by material.
140 // for each material create a combined vertex and index buffer.
141 // some models might have many sub-meshes. so iterate over the
142 // input meshes only once.
143 struct MESH_GROUP
144 {
145 std::vector<VERTEX> m_vertices;
146 std::vector<GLuint> m_indices;
147 };
148
149 std::vector<MESH_GROUP> mesh_groups( m_materials.size() );
150
151 for( unsigned int mesh_i = 0; mesh_i < a3DModel.m_MeshesSize; ++mesh_i )
152 {
153 const SMESH& mesh = a3DModel.m_Meshes[mesh_i];
154
155 // silently ignore meshes that have invalid material references or invalid geometry.
156 if( mesh.m_MaterialIdx >= m_materials.size()
157 || mesh.m_Positions == nullptr
158 || mesh.m_FaceIdx == nullptr
159 || mesh.m_Normals == nullptr
160 || mesh.m_FaceIdxSize == 0
161 || mesh.m_VertexSize == 0 )
162 {
163 continue;
164 }
165
166 MESH_GROUP& mesh_group = mesh_groups[mesh.m_MaterialIdx];
167 MATERIAL& material = m_materials[mesh.m_MaterialIdx];
168
169 if( material.IsTransparent() && m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
171 else
173
174 const unsigned int vtx_offset = mesh_group.m_vertices.size();
175 mesh_group.m_vertices.resize( mesh_group.m_vertices.size() + mesh.m_VertexSize );
176
177 // copy vertex data and update the bounding box.
178 // use material color for mesh bounding box or some sort of average vertex color.
179 glm::vec3 avg_color = material.m_Diffuse;
180
181 BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i];
182
183 for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
184 {
185 mesh_bbox.Union( mesh.m_Positions[vtx_i] );
186
187 VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
188
189 vtx_out.m_pos = mesh.m_Positions[vtx_i];
190 vtx_out.m_nrm = glm::clamp( glm::vec4( mesh.m_Normals[vtx_i], 1.0f ) * 127.0f,
191 -127.0f, 127.0f );
192
193 vtx_out.m_tex_uv = mesh.m_Texcoords != nullptr ? mesh.m_Texcoords[vtx_i]
194 : glm::vec2 (0);
195
196 if( mesh.m_Color != nullptr )
197 {
198 avg_color = ( avg_color + mesh.m_Color[vtx_i] ) * 0.5f;
199
200 vtx_out.m_color =
201 glm::clamp( glm::vec4( mesh.m_Color[vtx_i],
202 1 - material.m_Transparency ) * 255.0f,
203 0.0f, 255.0f );
204
205 vtx_out.m_cad_color =
206 glm::clamp( glm::vec4( MaterialDiffuseToColorCAD( mesh.m_Color[vtx_i] ),
207 1 ) * 255.0f, 0.0f, 255.0f );
208 }
209 else
210 {
211 // the mesh will be rendered with other meshes that might have
212 // vertex colors. thus, we can't enable/disable vertex colors
213 // for individual meshes during rendering.
214
215 // if there are no vertex colors, use material color instead.
216 vtx_out.m_color =
217 glm::clamp( glm::vec4( material.m_Diffuse,
218 1 - material.m_Transparency ) * 255.0f,
219 0.0f, 255.0f );
220
221 vtx_out.m_cad_color =
222 glm::clamp( glm::vec4 ( MaterialDiffuseToColorCAD( material.m_Diffuse ),
223 1 ) * 255.0f,
224 0.0f, 255.0f );
225 }
226 }
227
228 if( mesh_bbox.IsInitialized() )
229 {
230 // generate geometry for the bounding box
231 MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count,
232 &bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count],
233 &bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
234 { avg_color, 1.0f } );
235
236 // bump the outer bounding box
237 m_model_bbox.Union( mesh_bbox );
238
239 // add to the material group
240 material.m_bbox.Union( mesh_bbox );
241 }
242
243
244 // append indices of this mesh to the mesh group.
245 const unsigned int idx_offset = mesh_group.m_indices.size();
246 unsigned int use_idx_count = mesh.m_FaceIdxSize;
247
248 if( use_idx_count % 3 != 0 )
249 {
250 wxLogTrace( m_logTrace, wxT( " index count %u not multiple of 3, truncating" ),
251 static_cast<unsigned int>( use_idx_count ) );
252 use_idx_count = ( use_idx_count / 3 ) * 3;
253 }
254
255 mesh_group.m_indices.resize( mesh_group.m_indices.size() + use_idx_count );
256
257 for( unsigned int idx_i = 0; idx_i < use_idx_count; ++idx_i )
258 {
259 if( mesh.m_FaceIdx[idx_i] >= mesh.m_VertexSize )
260 {
261 wxLogTrace( m_logTrace, wxT( " index %u out of range (%u)" ),
262 static_cast<unsigned int>( mesh.m_FaceIdx[idx_i] ),
263 static_cast<unsigned int>( mesh.m_VertexSize ) );
264
265 // FIXME: should skip this triangle
266 }
267
268 mesh_group.m_indices[idx_offset + idx_i] = mesh.m_FaceIdx[idx_i] + vtx_offset;
269 }
270 }
271
272 // generate geometry for the outer bounding box
274 MakeBbox( m_model_bbox, 0, &bbox_tmp_vertices[0], &bbox_tmp_indices[0],
275 { 0.0f, 1.0f, 0.0f, 1.0f } );
276
277 // create bounding box buffers
278 glGenBuffers( 1, &m_bbox_vertex_buffer );
279 glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
280 glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * bbox_tmp_vertices.size(),
281 bbox_tmp_vertices.data(), GL_STATIC_DRAW );
282
283 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
284
285 if( bbox_tmp_vertices.size() <= std::numeric_limits<GLushort>::max() )
286 {
287 m_bbox_index_buffer_type = GL_UNSIGNED_SHORT;
288
289 auto u16buf = std::make_unique<GLushort[]>( bbox_tmp_indices.size() );
290
291 for( unsigned int i = 0; i < bbox_tmp_indices.size(); ++i )
292 u16buf[i] = static_cast<GLushort>( bbox_tmp_indices[i] );
293
294 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLushort ) * bbox_tmp_indices.size(),
295 u16buf.get(), GL_STATIC_DRAW );
296 }
297 else
298 {
299 m_bbox_index_buffer_type = GL_UNSIGNED_INT;
300 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( GLuint ) * bbox_tmp_indices.size(),
301 bbox_tmp_indices.data(), GL_STATIC_DRAW );
302 }
303
304 // merge the mesh group geometry data.
305 unsigned int total_vertex_count = 0;
306 unsigned int total_index_count = 0;
307
308 for( const MESH_GROUP& mg : mesh_groups )
309 {
310 total_vertex_count += mg.m_vertices.size();
311 total_index_count += mg.m_indices.size();
312 }
313
314 wxLogTrace( m_logTrace, wxT( " total %u vertices, %u indices" ),
315 total_vertex_count, total_index_count );
316
317 glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
318 glBufferData( GL_ARRAY_BUFFER, sizeof( VERTEX ) * total_vertex_count,
319 nullptr, GL_STATIC_DRAW );
320
321 unsigned int idx_size = 0;
322
323 if( total_vertex_count <= std::numeric_limits<GLushort>::max() )
324 {
325 m_index_buffer_type = GL_UNSIGNED_SHORT;
326 idx_size = sizeof( GLushort );
327 }
328 else
329 {
330 m_index_buffer_type = GL_UNSIGNED_INT;
331 idx_size = sizeof( GLuint );
332 }
333
334 // temporary index buffer which will contain either GLushort or GLuint
335 // type indices. allocate with a bit of meadow at the end.
336 auto tmp_idx = std::make_unique<GLuint[]>( ( idx_size * total_index_count + 8 ) / sizeof( GLuint ) );
337
338 unsigned int prev_vtx_count = 0;
339 unsigned int idx_offset = 0;
340 unsigned int vtx_offset = 0;
341
342 for( unsigned int mg_i = 0; mg_i < mesh_groups.size (); ++mg_i )
343 {
344 MESH_GROUP& mg = mesh_groups[mg_i];
345 MATERIAL& mat = m_materials[mg_i];
346 uintptr_t tmp_idx_ptr = reinterpret_cast<uintptr_t>( tmp_idx.get() );
347
348 if( m_index_buffer_type == GL_UNSIGNED_SHORT )
349 {
350 GLushort* idx_out = reinterpret_cast<GLushort*>( tmp_idx_ptr + idx_offset );
351
352 for( GLuint idx : mg.m_indices )
353 *idx_out++ = static_cast<GLushort>( idx + prev_vtx_count );
354 }
355 else if( m_index_buffer_type == GL_UNSIGNED_INT )
356 {
357 GLuint* idx_out = reinterpret_cast<GLuint*>( tmp_idx_ptr + idx_offset );
358
359 for( GLuint idx : mg.m_indices )
360 *idx_out++ = static_cast<GLuint>( idx + prev_vtx_count );
361 }
362
363 glBufferSubData( GL_ARRAY_BUFFER, vtx_offset, mg.m_vertices.size() * sizeof( VERTEX ),
364 mg.m_vertices.data() );
365
366 mat.m_render_idx_buffer_offset = idx_offset;
367 mat.m_render_idx_count = mg.m_indices.size();
368
369 prev_vtx_count += mg.m_vertices.size();
370 idx_offset += mg.m_indices.size() * idx_size;
371 vtx_offset += mg.m_vertices.size() * sizeof( VERTEX );
372 }
373
374 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
375 glBufferData( GL_ELEMENT_ARRAY_BUFFER, idx_size * total_index_count, tmp_idx.get(),
376 GL_STATIC_DRAW );
377
378 glBindBuffer( GL_ARRAY_BUFFER, 0 );
379 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
380
381 auto end_time = std::chrono::high_resolution_clock::now();
382
383 wxLogTrace( m_logTrace, wxT( " loaded in %u ms\n" ),
384 (unsigned int)std::chrono::duration_cast<std::chrono::milliseconds> (
385 end_time - start_time).count() );
386}
@ DIFFUSE_ONLY
Use only diffuse material properties.
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
Definition: 3d_math.h:147
Base material class that can be used to derive other material implementations.
Definition: material.h:240
GLuint m_vertex_buffer
Definition: 3d_model.h:138
bool m_have_opaque_meshes
Definition: 3d_model.h:160
GLenum m_index_buffer_type
Definition: 3d_model.h:140
std::vector< MATERIAL > m_materials
Definition: 3d_model.h:155
static void MakeBbox(const BBOX_3D &aBox, unsigned int aIdxOffset, VERTEX *aVtxOut, GLuint *aIdxOut, const glm::vec4 &aColor)
Definition: 3d_model.cpp:52
GLuint m_index_buffer
Definition: 3d_model.h:139
GLuint m_bbox_index_buffer
Definition: 3d_model.h:169
static constexpr unsigned int bbox_idx_count
Definition: 3d_model.h:166
MATERIAL_MODE m_materialMode
Definition: 3d_model.h:121
static const wxChar * m_logTrace
Definition: 3d_model.h:116
bool m_have_transparent_meshes
Definition: 3d_model.h:161
std::vector< BBOX_3D > m_meshes_bbox
individual bbox for each mesh
Definition: 3d_model.h:124
GLenum m_bbox_index_buffer_type
Definition: 3d_model.h:170
static constexpr unsigned int bbox_vtx_count
Definition: 3d_model.h:165
BBOX_3D m_model_bbox
global bounding box for this model
Definition: 3d_model.h:123
GLuint m_bbox_vertex_buffer
Definition: 3d_model.h:168
Manage a bounding box defined by two SFVEC3F min max points.
Definition: bbox_3d.h:42
void Union(const SFVEC3F &aPoint)
Recalculate the bounding box adding a point.
Definition: bbox_3d.cpp:102
bool IsInitialized() const
Check if this bounding box is already initialized.
Definition: bbox_3d.cpp:88
SMATERIAL * m_Materials
The materials list of this model.
Definition: c3dmodel.h:96
unsigned int m_MeshesSize
Number of meshes in the array.
Definition: c3dmodel.h:92
SMESH * m_Meshes
The meshes list of this model.
Definition: c3dmodel.h:93
unsigned int m_MaterialsSize
Number of materials in the material array.
Definition: c3dmodel.h:95
Per-vertex normal/color/texcoors structure.
Definition: c3dmodel.h:77
unsigned int * m_FaceIdx
Triangle Face Indexes.
Definition: c3dmodel.h:84
SFVEC3F * m_Normals
Vertex normals array.
Definition: c3dmodel.h:80
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
Definition: c3dmodel.h:85
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition: c3dmodel.h:78
SFVEC2F * m_Texcoords
Vertex texture coordinates array, can be NULL.
Definition: c3dmodel.h:81
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
Definition: c3dmodel.h:83
SFVEC3F * m_Color
Vertex color array, can be NULL.
Definition: c3dmodel.h:82
SFVEC3F * m_Positions
Vertex position array.
Definition: c3dmodel.h:79

References bbox_idx_count, bbox_vtx_count, DIFFUSE_ONLY, BBOX_3D::IsInitialized(), MODEL_3D::MATERIAL::IsTransparent(), MODEL_3D::MATERIAL::m_bbox, m_bbox_index_buffer, m_bbox_index_buffer_type, m_bbox_vertex_buffer, MODEL_3D::VERTEX::m_cad_color, MODEL_3D::VERTEX::m_color, SMESH::m_Color, SMATERIAL::m_Diffuse, SMESH::m_FaceIdx, SMESH::m_FaceIdxSize, m_have_opaque_meshes, m_have_transparent_meshes, m_index_buffer, m_index_buffer_type, m_logTrace, SMESH::m_MaterialIdx, m_materialMode, m_materials, S3DMODEL::m_Materials, S3DMODEL::m_MaterialsSize, S3DMODEL::m_Meshes, m_meshes_bbox, S3DMODEL::m_MeshesSize, m_model_bbox, SMESH::m_Normals, MODEL_3D::VERTEX::m_nrm, MODEL_3D::VERTEX::m_pos, SMESH::m_Positions, MODEL_3D::MATERIAL::m_render_idx_buffer_offset, MODEL_3D::MATERIAL::m_render_idx_count, MODEL_3D::VERTEX::m_tex_uv, SMESH::m_Texcoords, SMATERIAL::m_Transparency, m_vertex_buffer, SMESH::m_VertexSize, MakeBbox(), MaterialDiffuseToColorCAD(), and BBOX_3D::Union().

◆ ~MODEL_3D()

MODEL_3D::~MODEL_3D ( )

Definition at line 560 of file 3d_model.cpp.

561{
562 if( glDeleteBuffers )
563 {
564 glDeleteBuffers( 1, &m_vertex_buffer );
565 glDeleteBuffers( 1, &m_index_buffer );
566 glDeleteBuffers( 1, &m_bbox_vertex_buffer );
567 glDeleteBuffers( 1, &m_bbox_index_buffer );
568 }
569}

References m_bbox_index_buffer, m_bbox_vertex_buffer, m_index_buffer, and m_vertex_buffer.

Member Function Documentation

◆ BeginDrawMulti()

void MODEL_3D::BeginDrawMulti ( bool  aUseColorInformation)
static

Set some basic render states before drawing multiple models.

Definition at line 389 of file 3d_model.cpp.

390{
391 glEnableClientState( GL_VERTEX_ARRAY );
392 glEnableClientState( GL_NORMAL_ARRAY );
393
394 if( aUseColorInformation )
395 {
396 glEnableClientState( GL_COLOR_ARRAY );
397 glEnableClientState( GL_TEXTURE_COORD_ARRAY );
398 glEnable( GL_COLOR_MATERIAL );
399 }
400
401 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
402}

Referenced by EDA_3D_MODEL_VIEWER::OnPaint(), RENDER_3D_OPENGL::renderOpaqueModels(), and RENDER_3D_OPENGL::renderTransparentModels().

◆ Draw()

void MODEL_3D::Draw ( bool  aTransparent,
float  aOpacity,
bool  aUseSelectedMaterial,
const SFVEC3F aSelectionColor,
const glm::mat4 *  aModelWorldMatrix,
const SFVEC3F aCameraWorldPos 
) const

Render the model into the current context.

if aModelWorldMatrix and aCameraWorldPos is provided, it renders the material groups sorted.

Definition at line 418 of file 3d_model.cpp.

422{
423 if( aOpacity <= FLT_EPSILON )
424 return;
425
426 if( !glBindBuffer )
427 throw std::runtime_error( "The OpenGL context no longer exists: unable to draw" );
428
429 glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer );
430 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer );
431
432 glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
433 reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
434
435 glNormalPointer( GL_BYTE, sizeof( VERTEX ),
436 reinterpret_cast<const void*>( offsetof( VERTEX, m_nrm ) ) );
437
438 glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
439 reinterpret_cast<const void*>( m_materialMode == MATERIAL_MODE::CAD_MODE
440 ? offsetof( VERTEX, m_cad_color )
441 : offsetof( VERTEX, m_color ) ) );
442
443 glTexCoordPointer( 2, GL_FLOAT, sizeof( VERTEX ),
444 reinterpret_cast<const void*>( offsetof( VERTEX, m_tex_uv ) ) );
445
446 const SFVEC4F param = SFVEC4F( 1.0f, 1.0f, 1.0f, aOpacity );
447
448 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)&param.x );
449
450 std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
451
452 materialsToRender.reserve( m_materials.size() );
453
454 if( aModelWorldMatrix && aCameraWorldPos )
455 {
456 // Sort Material groups
457
458 std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
459
460 // Calculate the distance to the camera for each material group
461 for( const MODEL_3D::MATERIAL& mat : m_materials )
462 {
463 if( mat.m_render_idx_count == 0 )
464 {
465 continue;
466 }
467
468 if( ( mat.IsTransparent() != aTransparent )
469 && ( aOpacity >= 1.0f )
471 {
472 continue;
473 }
474
475 const BBOX_3D& bBox = mat.m_bbox;
476 const SFVEC3F& bBoxCenter = bBox.GetCenter();
477 const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
478
479 const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
480
481 materialsSorted.emplace_back( &mat, distanceToCamera );
482 }
483
484 // Sort from back to front
485 std::sort( materialsSorted.begin(), materialsSorted.end(),
486 [&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
487 std::pair<const MODEL_3D::MATERIAL*, float>& b ) {
488 // If A is inside B, then A is rendered first
489 if( b.first->m_bbox.Inside( a.first->m_bbox ) )
490 {
491 return true;
492 }
493 else
494 {
495 if( a.first->m_bbox.Inside( b.first->m_bbox ) )
496 {
497 return false;
498 }
499 }
500
501 return a.second > b.second;
502 } );
503
504 for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
505 {
506 materialsToRender.push_back( mat.first );
507 }
508 }
509 else
510 {
511 for( const MODEL_3D::MATERIAL& mat : m_materials )
512 {
513 // There is at least one default material created in case a mesh has no declared materials.
514 // Most meshes have a material, so usually the first material will have nothing to render and is skip.
515 // See S3D::GetModel for more details.
516 if( mat.m_render_idx_count == 0 )
517 {
518 continue;
519 }
520
521 if( ( mat.IsTransparent() != aTransparent )
522 && ( aOpacity >= 1.0f )
524 {
525 continue;
526 }
527
528 materialsToRender.push_back( &mat );
529 }
530 }
531
532 for( const MODEL_3D::MATERIAL* mat : materialsToRender )
533 {
534 switch( m_materialMode )
535 {
537 OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
538 break;
539
541 OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
542 break;
543
545 OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
546 aUseSelectedMaterial, aSelectionColor );
547 break;
548
549 default:
550 break;
551 }
552
553 glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type,
554 reinterpret_cast<const void*>(
555 static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
556 }
557}
@ NORMAL
Use all material properties from model file.
@ CAD_MODE
Use a gray shading based on diffuse material.
void OglSetDiffuseMaterial(const SFVEC3F &aMaterialDiffuse, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Sets only the diffuse color and keep other parameters with default values.
Definition: ogl_utils.cpp:143
void OglSetMaterial(const SMATERIAL &aMaterial, float aOpacity, bool aUseSelectedMaterial, SFVEC3F aSelectionColor)
Set OpenGL materials.
Definition: ogl_utils.cpp:119
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition: bbox_3d.cpp:132
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
glm::vec4 SFVEC4F
Definition: xv3d_types.h:46

References CAD_MODE, DIFFUSE_ONLY, BBOX_3D::GetCenter(), m_index_buffer, m_materialMode, m_materials, and m_vertex_buffer.

Referenced by DrawOpaque(), DrawTransparent(), and RENDER_3D_OPENGL::renderModel().

◆ DrawBbox()

void MODEL_3D::DrawBbox ( ) const

Draw main bounding box of the model.

Definition at line 572 of file 3d_model.cpp.

573{
574 if( !glBindBuffer )
575 throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bbox" );
576
577 glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
578 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
579
580 glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
581 reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
582
583 glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
584 reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
585
586 glDrawElements( GL_LINES, bbox_idx_count, m_bbox_index_buffer_type,
587 reinterpret_cast<const void*>( 0 ) );
588}

References bbox_idx_count, m_bbox_index_buffer, m_bbox_index_buffer_type, and m_bbox_vertex_buffer.

Referenced by RENDER_3D_OPENGL::renderModel().

◆ DrawBboxes()

void MODEL_3D::DrawBboxes ( ) const

Draw individual bounding boxes of each mesh.

Definition at line 591 of file 3d_model.cpp.

592{
593 if( !glBindBuffer )
594 throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bboxes" );
595
596 glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer );
597 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer );
598
599 glVertexPointer( 3, GL_FLOAT, sizeof( VERTEX ),
600 reinterpret_cast<const void*>( offsetof( VERTEX, m_pos ) ) );
601
602 glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( VERTEX ),
603 reinterpret_cast<const void*>( offsetof( VERTEX, m_color ) ) );
604
605 unsigned int idx_size = m_bbox_index_buffer_type == GL_UNSIGNED_SHORT ? sizeof( GLushort )
606 : sizeof( GLuint );
607
608 glDrawElements( GL_LINES, bbox_idx_count * m_meshes_bbox.size(), m_bbox_index_buffer_type,
609 reinterpret_cast<const void*>(
610 static_cast<uintptr_t>( bbox_idx_count * idx_size ) ) );
611}

References bbox_idx_count, m_bbox_index_buffer, m_bbox_index_buffer_type, m_bbox_vertex_buffer, and m_meshes_bbox.

Referenced by RENDER_3D_OPENGL::renderModel().

◆ DrawOpaque()

void MODEL_3D::DrawOpaque ( bool  aUseSelectedMaterial,
SFVEC3F  aSelectionColor = SFVEC3F( 0.0f ) 
) const
inline

Render the model into the current context.

Definition at line 55 of file 3d_model.h.

56 {
57 Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
58 }
void Draw(bool aTransparent, float aOpacity, bool aUseSelectedMaterial, const SFVEC3F &aSelectionColor, const glm::mat4 *aModelWorldMatrix, const SFVEC3F *aCameraWorldPos) const
Render the model into the current context.
Definition: 3d_model.cpp:418

References Draw().

Referenced by EDA_3D_MODEL_VIEWER::OnPaint().

◆ DrawTransparent()

void MODEL_3D::DrawTransparent ( float  aOpacity,
bool  aUseSelectedMaterial,
SFVEC3F  aSelectionColor = SFVEC3F( 0.0f ) 
) const
inline

Render the model into the current context.

Definition at line 63 of file 3d_model.h.

65 {
66 Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
67 }

References Draw().

Referenced by EDA_3D_MODEL_VIEWER::OnPaint().

◆ EndDrawMulti()

void MODEL_3D::EndDrawMulti ( )
static

Cleanup render states after drawing multiple models.

Definition at line 405 of file 3d_model.cpp.

406{
407 glDisable( GL_COLOR_MATERIAL );
408 glDisableClientState( GL_VERTEX_ARRAY );
409 glDisableClientState( GL_NORMAL_ARRAY );
410 glDisableClientState( GL_COLOR_ARRAY );
411 glDisableClientState( GL_TEXTURE_COORD_ARRAY );
412
413 glBindBuffer( GL_ARRAY_BUFFER, 0 );
414 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
415}

Referenced by EDA_3D_MODEL_VIEWER::OnPaint(), RENDER_3D_OPENGL::renderOpaqueModels(), and RENDER_3D_OPENGL::renderTransparentModels().

◆ GetBBox()

const BBOX_3D & MODEL_3D::GetBBox ( ) const
inline

Get the main bounding box.

Returns
the main model bounding box.

Definition at line 103 of file 3d_model.h.

103{ return m_model_bbox; }

References m_model_bbox.

Referenced by EDA_3D_MODEL_VIEWER::OnPaint().

◆ HasOpaqueMeshes()

bool MODEL_3D::HasOpaqueMeshes ( ) const
inline

Return true if have opaque meshes to render.

Definition at line 82 of file 3d_model.h.

82{ return m_have_opaque_meshes; }

References m_have_opaque_meshes.

◆ HasTransparentMeshes()

bool MODEL_3D::HasTransparentMeshes ( ) const
inline

Return true if have transparent mesh's to render.

Definition at line 87 of file 3d_model.h.

References m_have_transparent_meshes.

◆ MakeBbox()

void MODEL_3D::MakeBbox ( const BBOX_3D aBox,
unsigned int  aIdxOffset,
VERTEX aVtxOut,
GLuint *  aIdxOut,
const glm::vec4 &  aColor 
)
staticprivate

Definition at line 52 of file 3d_model.cpp.

54{
55 aVtxOut[0].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Min().z };
56 aVtxOut[1].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Min().z };
57 aVtxOut[2].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Min().z };
58 aVtxOut[3].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Min().z };
59
60 aVtxOut[4].m_pos = { aBox.Min().x, aBox.Min().y, aBox.Max().z };
61 aVtxOut[5].m_pos = { aBox.Max().x, aBox.Min().y, aBox.Max().z };
62 aVtxOut[6].m_pos = { aBox.Max().x, aBox.Max().y, aBox.Max().z };
63 aVtxOut[7].m_pos = { aBox.Min().x, aBox.Max().y, aBox.Max().z };
64
65 for( unsigned int i = 0; i < 8; ++i )
66 aVtxOut[i].m_color = aVtxOut[i].m_cad_color = glm::clamp( aColor * 255.0f, 0.0f, 255.0f );
67
68 #define bbox_line( vtx_a, vtx_b )\
69 do { *aIdxOut++ = vtx_a + aIdxOffset; \
70 *aIdxOut++ = vtx_b + aIdxOffset; } while( 0 )
71
72 bbox_line( 0, 1 );
73 bbox_line( 1, 2 );
74 bbox_line( 2, 3 );
75 bbox_line( 3, 0 );
76
77 bbox_line( 4, 5 );
78 bbox_line( 5, 6 );
79 bbox_line( 6, 7 );
80 bbox_line( 7, 4 );
81
82 bbox_line( 0, 4 );
83 bbox_line( 1, 5 );
84 bbox_line( 2, 6 );
85 bbox_line( 3, 7 );
86
87 #undef bbox_line
88}
#define bbox_line(vtx_a, vtx_b)
const SFVEC3F & Min() const
Return the minimum vertex pointer.
Definition: bbox_3d.h:191
const SFVEC3F & Max() const
Return the maximum vertex pointer.
Definition: bbox_3d.h:198

References bbox_line, MODEL_3D::VERTEX::m_pos, BBOX_3D::Max(), and BBOX_3D::Min().

Referenced by MODEL_3D().

Member Data Documentation

◆ bbox_idx_count

constexpr unsigned int MODEL_3D::bbox_idx_count = 24
staticconstexprprivate

Definition at line 166 of file 3d_model.h.

Referenced by DrawBbox(), DrawBboxes(), and MODEL_3D().

◆ bbox_vtx_count

constexpr unsigned int MODEL_3D::bbox_vtx_count = 8
staticconstexprprivate

Definition at line 165 of file 3d_model.h.

Referenced by MODEL_3D().

◆ m_bbox_index_buffer

GLuint MODEL_3D::m_bbox_index_buffer = 0
private

Definition at line 169 of file 3d_model.h.

Referenced by DrawBbox(), DrawBboxes(), MODEL_3D(), and ~MODEL_3D().

◆ m_bbox_index_buffer_type

GLenum MODEL_3D::m_bbox_index_buffer_type = GL_INVALID_ENUM
private

Definition at line 170 of file 3d_model.h.

Referenced by DrawBbox(), DrawBboxes(), and MODEL_3D().

◆ m_bbox_vertex_buffer

GLuint MODEL_3D::m_bbox_vertex_buffer = 0
private

Definition at line 168 of file 3d_model.h.

Referenced by DrawBbox(), DrawBboxes(), MODEL_3D(), and ~MODEL_3D().

◆ m_have_opaque_meshes

bool MODEL_3D::m_have_opaque_meshes = false
private

Definition at line 160 of file 3d_model.h.

Referenced by HasOpaqueMeshes(), and MODEL_3D().

◆ m_have_transparent_meshes

bool MODEL_3D::m_have_transparent_meshes = false
private

Definition at line 161 of file 3d_model.h.

Referenced by HasTransparentMeshes(), and MODEL_3D().

◆ m_index_buffer

GLuint MODEL_3D::m_index_buffer = 0
private

Definition at line 139 of file 3d_model.h.

Referenced by Draw(), MODEL_3D(), and ~MODEL_3D().

◆ m_index_buffer_type

GLenum MODEL_3D::m_index_buffer_type = GL_INVALID_ENUM
private

Definition at line 140 of file 3d_model.h.

Referenced by MODEL_3D().

◆ m_logTrace

const wxChar * MODEL_3D::m_logTrace = wxT( "KI_TRACE_EDA_OGL_3DMODEL" )
staticprivate

Definition at line 116 of file 3d_model.h.

Referenced by MODEL_3D().

◆ m_materialMode

MATERIAL_MODE MODEL_3D::m_materialMode
private

Definition at line 121 of file 3d_model.h.

Referenced by Draw(), and MODEL_3D().

◆ m_materials

std::vector<MATERIAL> MODEL_3D::m_materials
private

Definition at line 155 of file 3d_model.h.

Referenced by Draw(), and MODEL_3D().

◆ m_meshes_bbox

std::vector<BBOX_3D> MODEL_3D::m_meshes_bbox
private

individual bbox for each mesh

Definition at line 124 of file 3d_model.h.

Referenced by DrawBboxes(), and MODEL_3D().

◆ m_model_bbox

BBOX_3D MODEL_3D::m_model_bbox
private

global bounding box for this model

Definition at line 123 of file 3d_model.h.

Referenced by GetBBox(), and MODEL_3D().

◆ m_vertex_buffer

GLuint MODEL_3D::m_vertex_buffer = 0
private

Definition at line 138 of file 3d_model.h.

Referenced by Draw(), MODEL_3D(), and ~MODEL_3D().


The documentation for this class was generated from the following files: