3D-Viewer: sort models and material models when rendering in transparent

Also enables transparency on model preview and small optimizations fixes

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14005
This commit is contained in:
Mario Luzeiro 2023-03-02 22:29:08 +00:00 committed by Seth Hillbrand
parent 0f5ee38ee2
commit 7bc976f3f4
9 changed files with 431 additions and 97 deletions

View File

@ -330,8 +330,16 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
m_ogl_3dmodel->BeginDrawMulti( true ); m_ogl_3dmodel->BeginDrawMulti( true );
m_ogl_3dmodel->DrawOpaque( false ); m_ogl_3dmodel->DrawOpaque( false );
glDepthMask( GL_FALSE );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
m_ogl_3dmodel->DrawTransparent( 1.0f, false ); m_ogl_3dmodel->DrawTransparent( 1.0f, false );
glDisable( GL_BLEND );
glDepthMask( GL_TRUE );
m_ogl_3dmodel->EndDrawMulti(); m_ogl_3dmodel->EndDrawMulti();
glPopMatrix(); glPopMatrix();

View File

@ -27,13 +27,14 @@
* @file c_ogl_3dmodel.cpp * @file c_ogl_3dmodel.cpp
* @brief * @brief
*/ */
#include <algorithm>
#include <stdexcept> #include <stdexcept>
#include <gal/opengl/kiglew.h> // Must be included first #include <gal/opengl/kiglew.h> // Must be included first
#include "3d_model.h" #include "3d_model.h"
#include "opengl_utils.h"
#include "../common_ogl/ogl_utils.h" #include "../common_ogl/ogl_utils.h"
#include "../3d_math.h" #include "../3d_math.h"
#include <utility>
#include <wx/debug.h> #include <wx/debug.h>
#include <wx/log.h> #include <wx/log.h>
#include <chrono> #include <chrono>
@ -177,9 +178,11 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
// use material color for mesh bounding box or some sort of average vertex color. // use material color for mesh bounding box or some sort of average vertex color.
glm::vec3 avg_color = material.m_Diffuse; glm::vec3 avg_color = material.m_Diffuse;
BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i];
for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i ) for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
{ {
m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] ); mesh_bbox.Union( mesh.m_Positions[vtx_i] );
VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i]; VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
@ -222,16 +225,19 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
} }
} }
if( m_meshes_bbox[mesh_i].IsInitialized() ) if( mesh_bbox.IsInitialized() )
{ {
// generate geometry for the bounding box // generate geometry for the bounding box
MakeBbox( m_meshes_bbox[mesh_i], ( mesh_i + 1 ) * bbox_vtx_count, MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count,
&bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count], &bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count],
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count], &bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
{ avg_color, 1.0f } ); { avg_color, 1.0f } );
// bump the outer bounding box // bump the outer bounding box
m_model_bbox.Union( m_meshes_bbox[mesh_i] ); m_model_bbox.Union( mesh_bbox );
// add to the material group
material.m_bbox.Union( mesh_bbox );
} }
@ -410,7 +416,9 @@ void MODEL_3D::EndDrawMulti()
void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial, void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
SFVEC3F& aSelectionColor ) const const SFVEC3F& aSelectionColor,
const glm::mat4 *aModelWorldMatrix,
const SFVEC3F *aCameraWorldPos ) const
{ {
if( aOpacity <= FLT_EPSILON ) if( aOpacity <= FLT_EPSILON )
return; return;
@ -439,8 +447,24 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)&param.x ); glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)&param.x );
std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
materialsToRender.reserve( m_materials.size() );
if( aModelWorldMatrix && aCameraWorldPos )
{
// Sort Material groups
std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
// Calculate the distance to the camera for each material group
for( const MODEL_3D::MATERIAL& mat : m_materials ) for( const MODEL_3D::MATERIAL& mat : m_materials )
{ {
if( mat.m_render_idx_count == 0 )
{
continue;
}
if( ( mat.IsTransparent() != aTransparent ) if( ( mat.IsTransparent() != aTransparent )
&& ( aOpacity >= 1.0f ) && ( aOpacity >= 1.0f )
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY ) && m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
@ -448,18 +472,77 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
continue; continue;
} }
const BBOX_3D& bBox = mat.m_bbox;
const SFVEC3F& bBoxCenter = bBox.GetCenter();
const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
materialsSorted.emplace_back( &mat, distanceToCamera );
}
// Sort from back to front
std::sort( materialsSorted.begin(), materialsSorted.end(),
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
std::pair<const MODEL_3D::MATERIAL*, float>& b ) {
// If A is inside B, then A is rendered first
if( b.first->m_bbox.Inside( a.first->m_bbox ) )
{
return true;
}
else
{
if( a.first->m_bbox.Inside( b.first->m_bbox ) )
{
return false;
}
}
return a.second > b.second;
} );
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
{
materialsToRender.push_back( mat.first );
}
}
else
{
for( const MODEL_3D::MATERIAL& mat : m_materials )
{
// There is at least one default material created in case a mesh has no declared materials.
// Most meshes have a material, so usually the first material will have nothing to render and is skip.
// See S3D::GetModel for more details.
if( mat.m_render_idx_count == 0 )
{
continue;
}
if( ( mat.IsTransparent() != aTransparent )
&& ( aOpacity >= 1.0f )
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
{
continue;
}
materialsToRender.push_back( &mat );
}
}
for( const MODEL_3D::MATERIAL* mat : materialsToRender )
{
switch( m_materialMode ) switch( m_materialMode )
{ {
case MATERIAL_MODE::NORMAL: case MATERIAL_MODE::NORMAL:
OglSetMaterial( mat, aOpacity, aUseSelectedMaterial, aSelectionColor ); OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
break; break;
case MATERIAL_MODE::DIFFUSE_ONLY: case MATERIAL_MODE::DIFFUSE_ONLY:
OglSetDiffuseMaterial( mat.m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor ); OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
break; break;
case MATERIAL_MODE::CAD_MODE: case MATERIAL_MODE::CAD_MODE:
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ), aOpacity, OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
aUseSelectedMaterial, aSelectionColor ); aUseSelectedMaterial, aSelectionColor );
break; break;
@ -467,9 +550,9 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
break; break;
} }
glDrawElements( GL_TRIANGLES, mat.m_render_idx_count, m_index_buffer_type, glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type,
reinterpret_cast<const void*>( reinterpret_cast<const void*>(
static_cast<uintptr_t>( mat.m_render_idx_buffer_offset ) ) ); static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
} }
} }

View File

@ -54,7 +54,7 @@ public:
*/ */
void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
{ {
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor ); Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
} }
/** /**
@ -63,9 +63,19 @@ public:
void DrawTransparent( float aOpacity, bool aUseSelectedMaterial, void DrawTransparent( float aOpacity, bool aUseSelectedMaterial,
SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
{ {
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor ); Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
} }
/**
* Render the model into the current context.
* if aModelWorldMatrix and aCameraWorldPos is provided,
* it renders the material groups sorted.
*/
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
const SFVEC3F& aSelectionColor,
const glm::mat4 *aModelWorldMatrix,
const SFVEC3F *aCameraWorldPos ) const;
/** /**
* Return true if have opaque meshes to render. * Return true if have opaque meshes to render.
*/ */
@ -136,6 +146,8 @@ private:
unsigned int m_render_idx_buffer_offset = 0; unsigned int m_render_idx_buffer_offset = 0;
unsigned int m_render_idx_count = 0; unsigned int m_render_idx_count = 0;
BBOX_3D m_bbox; ///< bounding box for this material group, used for transparent material ordering
MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { } MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { }
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; } bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
}; };
@ -159,9 +171,6 @@ private:
static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut, static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
GLuint* aIdxOut, const glm::vec4& aColor ); GLuint* aIdxOut, const glm::vec4& aColor );
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
SFVEC3F& aSelectionColor ) const;
}; };
#endif // _MODEL_3D_H_ #endif // _MODEL_3D_H_

View File

@ -22,14 +22,19 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <cstdint>
#include <gal/opengl/kiglew.h> // Must be included first #include <gal/opengl/kiglew.h> // Must be included first
#include "plugins/3dapi/xv3d_types.h"
#include "render_3d_opengl.h" #include "render_3d_opengl.h"
#include "opengl_utils.h" #include "opengl_utils.h"
#include "common_ogl/ogl_utils.h" #include "common_ogl/ogl_utils.h"
#include <footprint.h> #include <footprint.h>
#include <3d_math.h> #include <3d_math.h>
#include <glm/geometric.hpp>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <utility>
#include <vector>
#include <wx/log.h> #include <wx/log.h>
#include <base_units.h> #include <base_units.h>
@ -858,9 +863,12 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
glPopMatrix(); glPopMatrix();
} }
glm::mat4 cameraViewMatrix;
glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
// Render 3D Models (Non-transparent) // Render 3D Models (Non-transparent)
render3dModels( false, false ); renderOpaqueModels( cameraViewMatrix );
render3dModels( true, false );
// Display board body // Display board body
if( m_boardAdapter.m_Cfg->m_Render.show_board_body ) if( m_boardAdapter.m_Cfg->m_Render.show_board_body )
@ -922,8 +930,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT ); glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA ); glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
render3dModels( false, true ); renderTransparentModels( cameraViewMatrix );
render3dModels( true, true );
glDisable( GL_BLEND ); glDisable( GL_BLEND );
OglResetTextureState(); OglResetTextureState();
@ -1143,14 +1150,15 @@ void RENDER_3D_OPENGL::renderSolderMaskLayer( PCB_LAYER_ID aLayerID, float aZPos
} }
void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly, void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
bool aRenderSelectedOnly ) bool aRenderSelectedOnly )
{ {
wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
if( !m_boardAdapter.GetBoard() ) if( !m_boardAdapter.GetBoard() )
return; return;
MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
// Go for all footprints // Go for all footprints
for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() ) for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
{ {
@ -1175,54 +1183,52 @@ void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRende
{ {
if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) ) if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
{ {
if( aRenderTopOrBot == !fp->IsFlipped() ) const bool isFlipped = fp->IsFlipped();
renderFootprint( fp, aRenderTransparentOnly, highlight );
}
}
}
MODEL_3D::EndDrawMulti(); if( ( aGetTop == !isFlipped ) ||
( aGetBot == isFlipped ) )
get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight );
}
}
}
} }
void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly ) void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
{ const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
if( m_boardAdapter.m_IsBoardView )
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
}
void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
bool aIsSelected ) bool aIsSelected )
{ {
if( !aFootprint->Models().empty() ) if( !aFootprint->Models().empty() )
{ {
const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() ); const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
glPushMatrix();
VECTOR2I pos = aFootprint->GetPosition(); VECTOR2I pos = aFootprint->GetPosition();
glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(), glm::mat4 fpMatrix( 1.0f );
zpos );
fpMatrix = glm::translate( fpMatrix,
SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
-pos.y * m_boardAdapter.BiuTo3dUnits(),
zpos ) );
if( !aFootprint->GetOrientation().IsZero() ) if( !aFootprint->GetOrientation().IsZero() )
glRotated( aFootprint->GetOrientation().AsDegrees(), 0.0, 0.0, 1.0 ); {
fpMatrix = glm::rotate( fpMatrix,
(float) aFootprint->GetOrientation().AsRadians(),
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
}
if( aFootprint->IsFlipped() ) if( aFootprint->IsFlipped() )
{ {
glRotatef( 180.0f, 0.0f, 1.0f, 0.0f ); fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
glRotatef( 180.0f, 0.0f, 0.0f, 1.0f ); fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
} }
double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB; const double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() *
UNITS3D_TO_UNITSPCB;
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor, fpMatrix = glm::scale( fpMatrix,
modelunit_to_3d_units_factor ); SFVEC3F( modelunit_to_3d_units_factor ) );
// Get the list of model files for this model // Get the list of model files for this model
for( const FP_3DMODEL& sM : aFootprint->Models() ) for( const FP_3DMODEL& sM : aFootprint->Models() )
@ -1243,66 +1249,232 @@ void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRende
if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) || if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) ) ( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
{ {
glPushMatrix(); glm::mat4 modelworldMatrix = fpMatrix;
std::vector<double> key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z, const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z, const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z );
sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z }; const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
std::vector<float> key = { offset.x, offset.y, offset.z,
rotation.x, rotation.y, rotation.z,
scale.x, scale.y, scale.z };
auto it = m_3dModelMatrixMap.find( key ); auto it = m_3dModelMatrixMap.find( key );
if( it != m_3dModelMatrixMap.end() ) if( it != m_3dModelMatrixMap.end() )
{ {
glMultMatrixf( glm::value_ptr( it->second ) ); modelworldMatrix *= it->second;
} }
else else
{ {
glm::mat4 mtx( 1 ); glm::mat4 mtx( 1.0f );
mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } ); mtx = glm::translate( mtx, offset );
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } ); mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } ); mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } ); mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } ); mtx = glm::scale( mtx, scale );
m_3dModelMatrixMap[ key ] = mtx; m_3dModelMatrixMap[ key ] = mtx;
glMultMatrixf( glm::value_ptr( mtx ) ); modelworldMatrix *= mtx;
} }
if( aRenderTransparentOnly ) if( aRenderTransparentOnly )
{ {
modelPtr->DrawTransparent( sM.m_Opacity, aDstRenderList.emplace_back( modelworldMatrix,
aFootprint->IsSelected() || aIsSelected, modelPtr,
selColor ); sM.m_Opacity,
true,
aFootprint->IsSelected() || aIsSelected );
} }
else else
{ {
modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor ); aDstRenderList.emplace_back( modelworldMatrix,
modelPtr,
1.0f,
false,
aFootprint->IsSelected() || aIsSelected );
} }
}
}
}
}
}
void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
{
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
glPushMatrix();
std::list<MODELTORENDER> renderList;
if( m_boardAdapter.m_IsBoardView )
{
renderList.clear();
get3dModelsSelected( renderList, true, true, false, true );
if( !renderList.empty() )
{
MODEL_3D::BeginDrawMulti( false );
for( const MODELTORENDER& mtr : renderList )
{
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
}
MODEL_3D::EndDrawMulti();
}
}
renderList.clear();
get3dModelsSelected( renderList, true, true, false, false );
if( !renderList.empty() )
{
MODEL_3D::BeginDrawMulti( true );
for( const MODELTORENDER& mtr : renderList )
{
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
}
MODEL_3D::EndDrawMulti();
}
glPopMatrix();
}
void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
{
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
if( m_boardAdapter.m_IsBoardView )
{
// Get Transparent Selected
get3dModelsSelected( renderListModels, true, true, true, true );
}
// Get Transparent Not Selected
get3dModelsSelected( renderListModels, true, true, true, false );
if( renderListModels.empty() )
return;
std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
transparentModelList.reserve( renderListModels.size() );
// Calculate the distance to the camera for each model
const SFVEC3F &cameraPos = m_camera.GetPos();
for( const MODELTORENDER& mtr : renderListModels )
{
const BBOX_3D& bBox = mtr.m_model->GetBBox();
const SFVEC3F& bBoxCenter = bBox.GetCenter();
const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
transparentModelList.emplace_back( &mtr, distanceToCamera );
}
// Sort from back to front
std::sort( transparentModelList.begin(), transparentModelList.end(),
[&]( std::pair<const MODELTORENDER *, float>& a,
std::pair<const MODELTORENDER *, float>& b ) {
return a.second > b.second;
} );
// Start rendering calls
glPushMatrix();
bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
m_boardAdapter.m_IsBoardView );
MODEL_3D::BeginDrawMulti( isUsingColorInformation );
for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
{
if( m_boardAdapter.m_IsBoardView )
{
// Toggle between using model color or the select color
if( !isUsingColorInformation && !mtr.first->m_isSelected )
{
isUsingColorInformation = true;
glEnableClientState( GL_COLOR_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glEnable( GL_COLOR_MATERIAL );
}
else
{
if( isUsingColorInformation && mtr.first->m_isSelected )
{
isUsingColorInformation = false;
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisable( GL_COLOR_MATERIAL );
}
}
}
// Render model, sort each individuall material group
// by passing cameraPos
renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
}
MODEL_3D::EndDrawMulti();
glPopMatrix();
}
void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
const MODELTORENDER &aModelToRender,
const SFVEC3F &aSelColor,
const SFVEC3F *aCameraWorldPos )
{
const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
aModelToRender.m_model->Draw( aModelToRender.m_isTransparent,
aModelToRender.m_opacity,
aModelToRender.m_isSelected,
aSelColor,
&aModelToRender.m_modelWorldMat,
aCameraWorldPos );
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox ) if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
{
const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
if( !wasBlendEnabled )
{ {
glEnable( GL_BLEND ); glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
glDisable( GL_LIGHTING ); glDisable( GL_LIGHTING );
glLineWidth( 1 ); glLineWidth( 1 );
modelPtr->DrawBboxes(); aModelToRender.m_model->DrawBboxes();
glLineWidth( 4 ); glLineWidth( 4 );
modelPtr->DrawBbox(); aModelToRender.m_model->DrawBbox();
glEnable( GL_LIGHTING ); glEnable( GL_LIGHTING );
if( !wasBlendEnabled )
{
glDisable( GL_BLEND ); glDisable( GL_BLEND );
} }
glPopMatrix();
}
}
}
glPopMatrix();
} }
} }

View File

@ -129,17 +129,43 @@ private:
*/ */
void load3dModels( REPORTER* aStatusReporter ); void load3dModels( REPORTER* aStatusReporter );
/** struct MODELTORENDER
* @param aRenderTopOrBot true will render Top, false will render bottom {
* @param aRenderTransparentOnly true will render only the transparent objects, false will glm::mat4 m_modelWorldMat;
* render opaque const MODEL_3D* m_model;
*/ float m_opacity;
void render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly ); bool m_isTransparent;
bool m_isSelected;
void render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly, MODELTORENDER( glm::mat4 aModelWorldMat,
const MODEL_3D* aNodel,
float aOpacity,
bool aIsTransparent,
bool aIsSelected ) :
m_modelWorldMat( std::move( aModelWorldMat ) ),
m_model( aNodel ),
m_opacity( aOpacity ),
m_isTransparent( aIsTransparent ),
m_isSelected( aIsSelected )
{
}
};
void renderOpaqueModels( const glm::mat4 &aCameraViewMatrix );
void renderTransparentModels( const glm::mat4 &aCameraViewMatrix );
void renderModel( const glm::mat4 &aCameraViewMatrix,
const MODELTORENDER &aModelToRender,
const SFVEC3F &aSelColor,
const SFVEC3F *aCameraWorldPos );
void get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
bool aRenderSelectedOnly ); bool aRenderSelectedOnly );
void renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly, void get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
bool aIsSelected ); bool aIsSelected );
void setLightFront( bool enabled ); void setLightFront( bool enabled );
@ -210,7 +236,7 @@ private:
// Caches // Caches
std::map< wxString, MODEL_3D* > m_3dModelMap; std::map< wxString, MODEL_3D* > m_3dModelMap;
std::map< std::vector<double>, glm::mat4 > m_3dModelMatrixMap; std::map< std::vector<float>, glm::mat4 > m_3dModelMatrixMap;
BOARD_ITEM* m_currentRollOverItem; BOARD_ITEM* m_currentRollOverItem;

View File

@ -229,6 +229,16 @@ bool BBOX_2D::Inside( const SFVEC2F& aPoint ) const
} }
bool BBOX_2D::Inside( const BBOX_2D& aBBox ) const
{
wxASSERT( IsInitialized() );
wxASSERT( aBBox.IsInitialized() );
return Inside( aBBox.Min() ) &&
Inside( aBBox.Max() );
}
float BBOX_2D::Area() const float BBOX_2D::Area() const
{ {
SFVEC2F extent = GetExtent(); SFVEC2F extent = GetExtent();

View File

@ -132,6 +132,14 @@ public:
*/ */
bool Inside( const SFVEC2F& aPoint ) const; bool Inside( const SFVEC2F& aPoint ) const;
/**
* Check if a bounding box is inside this bounding box.
*
* @param aBBox the bounding box to test if it is inside
* @return true if aBBox is smaller and all points are inside
*/
bool Inside( const BBOX_2D& aBBox ) const;
/** /**
* Calculate the area of a bounding box. * Calculate the area of a bounding box.
* *

View File

@ -238,6 +238,16 @@ bool BBOX_3D::Inside( const SFVEC3F& aPoint ) const
} }
bool BBOX_3D::Inside( const BBOX_3D& aBBox ) const
{
wxASSERT( IsInitialized() );
wxASSERT( aBBox.IsInitialized() );
return Inside( aBBox.Min() ) &&
Inside( aBBox.Max() );
}
float BBOX_3D::Volume() const float BBOX_3D::Volume() const
{ {
wxASSERT( IsInitialized() ); wxASSERT( IsInitialized() );

View File

@ -125,6 +125,14 @@ public:
*/ */
bool Inside( const SFVEC3F& aPoint ) const; bool Inside( const SFVEC3F& aPoint ) const;
/**
* Check if a bounding box is inside this bounding box.
*
* @param aBBox the bounding box to test if it is inside
* @return true if aBBox is smaller and all points are inside
*/
bool Inside( const BBOX_3D& aBBox ) const;
/** /**
* Apply a transformation matrix to the box points. * Apply a transformation matrix to the box points.
* *