From 8e7bc5666b78ae5ddb04fed50056e97d6b2912f3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Mar 2015 21:15:41 +0100 Subject: [PATCH] 3d viewer: fix current shading issues with some models. --- 3d-viewer/3d_canvas.cpp | 2 +- 3d-viewer/3d_draw.cpp | 13 +-- 3d-viewer/3d_frame.cpp | 22 ++-- 3d-viewer/3d_mesh_model.cpp | 202 +++++++++++++++++++++++++----------- 3d-viewer/3d_mesh_model.h | 3 + 3d-viewer/3d_toolbar.cpp | 13 ++- 3d-viewer/3d_viewer_id.h | 3 +- 3d-viewer/info3d_visu.h | 3 +- 8 files changed, 180 insertions(+), 81 deletions(-) diff --git a/3d-viewer/3d_canvas.cpp b/3d-viewer/3d_canvas.cpp index f86924a4ca..33f540c193 100644 --- a/3d-viewer/3d_canvas.cpp +++ b/3d-viewer/3d_canvas.cpp @@ -563,7 +563,7 @@ void EDA_3D_CANVAS::InitGL() void EDA_3D_CANVAS::SetLights() { // activate light. the source is above the xy plane, at source_pos - GLfloat source_pos[4] = { 0.0, 0.0, 30.0, 0.0 }; + GLfloat source_pos[4] = { 0.0, 0.0, 1000.0, 0.0 }; GLfloat light_color[4]; // color of lights (RGBA values) light_color[3] = 1.0; diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index d7fef89ab3..b436cea3a6 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -342,16 +342,9 @@ void EDA_3D_CANVAS::Redraw() glClearStencil( 0 ); glClearDepth( 1.0 ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); - - if( isEnabled( FL_RENDER_SMOOTH ) ) - { - glShadeModel( GL_SMOOTH ); - } - else - { - glShadeModel( GL_FLAT ); - } - + + glShadeModel( GL_SMOOTH ); + // Draw background glMatrixMode( GL_PROJECTION ); glLoadIdentity(); diff --git a/3d-viewer/3d_frame.cpp b/3d-viewer/3d_frame.cpp index d9c403e485..59fcb982bb 100644 --- a/3d-viewer/3d_frame.cpp +++ b/3d-viewer/3d_frame.cpp @@ -54,7 +54,8 @@ static const wxChar keyShowRealisticMode[] = wxT( "ShowRealisticMode" ); static const wxChar keyRenderShadows[] = wxT( "Render_Shadows" ); static const wxChar keyRenderRemoveHoles[] = wxT( "Render_RemoveHoles" ); static const wxChar keyRenderTextures[] = wxT( "Render_Textures" ); -static const wxChar keyRenderSmooth[] = wxT( "Render_Smooth" ); +static const wxChar keyRenderSmoothNormals[] = wxT( "Render_Smooth_Normals" ); +static const wxChar keyRenderUseModelNormals[] =wxT( "Render_Use_Model_Normals" ); static const wxChar keyRenderMaterial[] = wxT( "Render_Material" ); static const wxChar keyShowAxis[] = wxT( "ShowAxis" ); @@ -247,8 +248,11 @@ void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg ) aCfg->Read( keyRenderTextures, &tmp, false ); prms.SetFlag( FL_RENDER_TEXTURES, tmp ); - aCfg->Read( keyRenderSmooth, &tmp, false ); - prms.SetFlag( FL_RENDER_SMOOTH, tmp ); + aCfg->Read( keyRenderSmoothNormals, &tmp, false ); + prms.SetFlag( FL_RENDER_SMOOTH_NORMALS, tmp ); + + aCfg->Read( keyRenderUseModelNormals, &tmp, false ); + prms.SetFlag( FL_RENDER_USE_MODEL_NORMALS, tmp ); aCfg->Read( keyRenderMaterial, &tmp, false ); prms.SetFlag( FL_RENDER_MATERIAL, tmp ); @@ -312,7 +316,8 @@ void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg ) aCfg->Write( keyRenderShadows, prms.GetFlag( FL_RENDER_SHADOWS ) ); aCfg->Write( keyRenderRemoveHoles, prms.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) ); aCfg->Write( keyRenderTextures, prms.GetFlag( FL_RENDER_TEXTURES ) ); - aCfg->Write( keyRenderSmooth, prms.GetFlag( FL_RENDER_SMOOTH ) ); + aCfg->Write( keyRenderSmoothNormals, prms.GetFlag( FL_RENDER_SMOOTH_NORMALS ) ); + aCfg->Write( keyRenderUseModelNormals, prms.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) ); aCfg->Write( keyRenderMaterial, prms.GetFlag( FL_RENDER_MATERIAL ) ); aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) ); @@ -488,8 +493,13 @@ void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event ) NewDisplay(GL_ID_TECH_LAYERS); return; - case ID_MENU3D_FL_RENDER_SMOOTH: - GetPrm3DVisu().SetFlag( FL_RENDER_SMOOTH, isChecked ); + case ID_MENU3D_FL_RENDER_SMOOTH_NORMALS: + GetPrm3DVisu().SetFlag( FL_RENDER_SMOOTH_NORMALS, isChecked ); + NewDisplay(); + return; + + case ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS: + GetPrm3DVisu().SetFlag( FL_RENDER_USE_MODEL_NORMALS, isChecked ); NewDisplay(); return; diff --git a/3d-viewer/3d_mesh_model.cpp b/3d-viewer/3d_mesh_model.cpp index 5bf66f5b1c..e5a28b0df9 100644 --- a/3d-viewer/3d_mesh_model.cpp +++ b/3d-viewer/3d_mesh_model.cpp @@ -40,6 +40,7 @@ S3D_MESH::S3D_MESH() isPerFaceNormalsComputed = false; isPointNormalizedComputed = false; isPerPointNormalsComputed = false; + isPerVertexNormalsVerified = false; m_Materials = NULL; childs.clear(); @@ -91,10 +92,7 @@ void S3D_MESH::openGL_Render() //DBG( printf( "openGL_Render" ) ); bool useMaterial = g_Parm_3D_Visu.GetFlag( FL_RENDER_MATERIAL ); bool smoothShapes = g_Parm_3D_Visu.IsRealisticMode() - && g_Parm_3D_Visu.GetFlag( FL_RENDER_SMOOTH ); - - if( m_Materials ) - m_Materials->SetOpenGLMaterial( 0, useMaterial ); + && g_Parm_3D_Visu.GetFlag( FL_RENDER_SMOOTH_NORMALS ); if( m_CoordIndex.size() == 0 ) return; @@ -109,19 +107,23 @@ void S3D_MESH::openGL_Render() calcPointNormalized(); calcPerFaceNormals(); - if( m_PerVertexNormalsNormalized.size() == 0 ) + if( smoothShapes ) { - if( smoothShapes ) + if( (m_PerVertexNormalsNormalized.size() > 0) && + g_Parm_3D_Visu.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) ) + perVertexNormalsVerify_and_Repair(); + else calcPerPointNormals(); + } for( unsigned int idx = 0; idx < m_CoordIndex.size(); idx++ ) { - if( m_MaterialIndex.size() > 1 ) - { + if( m_MaterialIndex.size() == 0 ) + m_Materials->SetOpenGLMaterial( 0, useMaterial ); + else if( m_Materials ) m_Materials->SetOpenGLMaterial( m_MaterialIndex[idx], useMaterial ); - } switch( m_CoordIndex[idx].size() ) @@ -138,42 +140,69 @@ void S3D_MESH::openGL_Render() } - if( m_PerVertexNormalsNormalized.size() > 0 ) + if( smoothShapes ) { - for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + if( (m_PerVertexNormalsNormalized.size() > 0) && + g_Parm_3D_Visu.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) ) { - glm::vec3 normal = m_PerVertexNormalsNormalized[m_NormalIndex[idx][ii]]; - glNormal3fv( &normal.x ); + for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + { + glm::vec3 normal = m_PerVertexNormalsNormalized[m_NormalIndex[idx][ii]]; + glNormal3fv( &normal.x ); - glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; - glVertex3fv( &point.x ); + // Flag error vertices + if ((normal.x == 0.0) && (normal.y == 0.0) && (normal.z == 0.0)) + glColor3f( 1.0, 0.0, 0.0 ); + + glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; + glVertex3fv( &point.x ); + } } - } - else if( smoothShapes ) - { - std::vector< glm::vec3 > normals_list; - normals_list = m_PerFaceVertexNormals[idx]; - - for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + else { - glm::vec3 normal = normals_list[ii]; - glNormal3fv( &normal.x ); + std::vector< glm::vec3 > normals_list; + normals_list = m_PerFaceVertexNormals[idx]; - glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; - glVertex3fv( &point.x ); + for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + { + glm::vec3 normal = normals_list[ii]; + glNormal3fv( &normal.x ); + + // Flag error vertices + if ((normal.x == 0.0) && (normal.y == 0.0) && (normal.z == 0.0)) + glColor3f( 1.0, 0.0, 0.0 ); + + glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; + glVertex3fv( &point.x ); + } } } else { // Flat - glm::vec3 normal = m_PerFaceNormalsNormalized[idx]; - - for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + if( m_PerFaceNormalsNormalized.size() > 0 ) { - glNormal3fv( &normal.x ); + glm::vec3 normal = m_PerFaceNormalsNormalized[idx]; - glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; - glVertex3fv( &point.x ); + for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + { + glNormal3fv( &normal.x ); + + // Flag error vertices + if ((normal.x == 0.0) && (normal.y == 0.0) && (normal.z == 0.0)) + glColor3f( 1.0, 0.0, 0.0 ); + + glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; + glVertex3fv( &point.x ); + } + } + else + { + for( unsigned int ii = 0; ii < m_CoordIndex[idx].size(); ii++ ) + { + glm::vec3 point = m_Point[m_CoordIndex[idx][ii]]; + glVertex3fv( &point.x ); + } } } @@ -184,6 +213,68 @@ void S3D_MESH::openGL_Render() } +void S3D_MESH::perVertexNormalsVerify_and_Repair() +{ + if( isPerVertexNormalsVerified == true ) + return; + + isPerVertexNormalsVerified = true; + + //DBG( printf( "perVertexNormalsVerify_and_Repair\n" ) ); + + for( unsigned int idx = 0; idx < m_PerVertexNormalsNormalized.size(); idx++ ) + { + glm::vec3 normal = m_PerVertexNormalsNormalized[idx]; + + if( (normal.x == 1.0) && ((normal.y != 0.0) || (normal.z != 0.0)) ) + { + normal.y = 0.0; + normal.z = 0.0; + } + else + if( (normal.y == 1.0) && ((normal.x != 0.0) || (normal.z != 0.0)) ) + { + normal.x = 0.0; + normal.z = 0.0; + } + else + if( (normal.z == 1.0) && ((normal.x != 0.0) || (normal.y != 0.0)) ) + { + normal.x = 0.0; + normal.y = 0.0; + } + else + if( (normal.x < FLT_EPSILON) && (normal.x > -FLT_EPSILON) ) + { + normal.x = 0.0; + } + else + if( (normal.y < FLT_EPSILON) && (normal.y > -FLT_EPSILON) ) + { + normal.y = 0.0; + } + else + if( (normal.z < FLT_EPSILON) && (normal.z > -FLT_EPSILON) ) + { + normal.z = 0.0; + } + + float l = glm::length( normal ); + + if( l > FLT_EPSILON ) // avoid division by zero + { + normal = normal / l; + } + else + { + //DBG( printf( "idx:%u\n", idx ) ); + } + + m_PerVertexNormalsNormalized[idx] = normal; + } +} + + void S3D_MESH::calcPointNormalized() { //DBG( printf( "calcPointNormalized\n" ) ); @@ -193,13 +284,10 @@ void S3D_MESH::calcPointNormalized() isPointNormalizedComputed = true; - if( m_PerVertexNormalsNormalized.size() > 0 ) - return; - m_PointNormalized.clear(); float biggerPoint = 0.0f; - for( unsigned int i = 0; i< m_Point.size(); i++ ) + for( unsigned int i = 0; i < m_Point.size(); i++ ) { if( fabs( m_Point[i].x ) > biggerPoint ) biggerPoint = fabs( m_Point[i].x ); @@ -245,20 +333,17 @@ void S3D_MESH::calcPerFaceNormals() isPerFaceNormalsComputed = true; - if( m_PerVertexNormalsNormalized.size() > 0 ) - return; - bool haveAlreadyNormals_from_model_file = false; - if( m_PerFaceNormalsNormalized.size() > 0 ) + if( ( m_PerFaceNormalsNormalized.size() > 0 ) && + g_Parm_3D_Visu.GetFlag( FL_RENDER_USE_MODEL_NORMALS ) ) haveAlreadyNormals_from_model_file = true; + else + m_PerFaceNormalsNormalized.clear(); m_PerFaceNormalsRaw.clear(); m_PerFaceSquaredArea.clear(); - //DBG( printf("m_CoordIndex.size %u\n", m_CoordIndex.size()) ); - //DBG( printf("m_PointNormalized.size %u\n", m_PointNormalized.size()) ); - // There are no points defined for the coordIndex if( m_PointNormalized.size() == 0 ) { @@ -273,13 +358,6 @@ void S3D_MESH::calcPerFaceNormals() glm::vec3 v1 = m_PointNormalized[m_CoordIndex[idx][1]]; glm::vec3 v2 = m_PointNormalized[m_CoordIndex[idx][m_CoordIndex[idx].size() - 1]]; - /* - // !TODO: improove and check what is best to calc the normal (check what have more resolution) - glm::vec3 v0 = m_Point[m_CoordIndex[idx][0]]; - glm::vec3 v1 = m_Point[m_CoordIndex[idx][1]]; - glm::vec3 v2 = m_Point[m_CoordIndex[idx][m_CoordIndex[idx].size() - 1]]; - */ - glm::vec3 cross_prod; /* @@ -317,11 +395,11 @@ void S3D_MESH::calcPerFaceNormals() } else { - // Cannot calc normal + //DBG( printf( "Cannot calc normal idx: %u", idx ) ); if( ( cross_prod.x > cross_prod.y ) && ( cross_prod.x > cross_prod.z ) ) { - cross_prod.x = 1.0; - cross_prod.y = 0.0; + cross_prod.x = 0.0; + cross_prod.y = 1.0; cross_prod.z = 0.0; } else if( ( cross_prod.y > cross_prod.x ) && ( cross_prod.y > cross_prod.z ) ) @@ -355,9 +433,6 @@ void S3D_MESH::calcPerPointNormals() isPerPointNormalsComputed = true; - if( m_PerVertexNormalsNormalized.size() > 0 ) - return; - m_PerFaceVertexNormals.clear(); // Pre-allocate space for the entire vector of vertex normals so we can do parallel writes @@ -389,9 +464,18 @@ void S3D_MESH::calcPerPointNormals() //if A != B { // ignore self if( each_face_A_idx != each_face_B_idx ) { - if( (m_CoordIndex[each_face_B_idx][0] == vertexIndex) - || (m_CoordIndex[each_face_B_idx][1] == vertexIndex) - || (m_CoordIndex[each_face_B_idx][2] == vertexIndex) ) + bool addThisVertex = false; + + for( unsigned int ii = 0; ii < m_CoordIndex[each_face_B_idx].size(); ii++ ) + { + if( m_CoordIndex[each_face_B_idx][ii] == vertexIndex ) + { + addThisVertex = true; + break; + } + } + + if( addThisVertex ) { glm::vec3 vector_face_B = m_PerFaceNormalsNormalized[each_face_B_idx]; diff --git a/3d-viewer/3d_mesh_model.h b/3d-viewer/3d_mesh_model.h index ab92903f41..abbc070c83 100644 --- a/3d-viewer/3d_mesh_model.h +++ b/3d-viewer/3d_mesh_model.h @@ -95,6 +95,9 @@ private: bool isPerPointNormalsComputed; void calcPerPointNormals(); + + bool isPerVertexNormalsVerified; + void perVertexNormalsVerify_and_Repair(); }; diff --git a/3d-viewer/3d_toolbar.cpp b/3d-viewer/3d_toolbar.cpp index 1213c11c6d..0c2b6edfd6 100644 --- a/3d-viewer/3d_toolbar.cpp +++ b/3d-viewer/3d_toolbar.cpp @@ -175,9 +175,13 @@ void EDA_3D_FRAME::CreateMenuBar() _( "Apply a grid/cloud textures to Board, Solder Mask and Silkscreen" ), KiBitmap( green_xpm ), wxITEM_CHECK ); - AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SMOOTH, + AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_SMOOTH_NORMALS, _( "Render Smooth Normals" ), KiBitmap( green_xpm ), wxITEM_CHECK ); + + AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS, + _( "Use Model Normals" ), + KiBitmap( green_xpm ), wxITEM_CHECK ); AddMenuItem( renderOptionsMenu, ID_MENU3D_FL_RENDER_MATERIAL, _( "Render Material Properties" ), @@ -287,8 +291,11 @@ void EDA_3D_FRAME::SetMenuBarOptionsState() item = menuBar->FindItem( ID_MENU3D_FL_RENDER_TEXTURES ); item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_TEXTURES ) ); - item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SMOOTH ); - item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SMOOTH ) ); + item = menuBar->FindItem( ID_MENU3D_FL_RENDER_SMOOTH_NORMALS ); + item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_SMOOTH_NORMALS ) ); + + item = menuBar->FindItem( ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS ); + item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_USE_MODEL_NORMALS ) ); item = menuBar->FindItem( ID_MENU3D_FL_RENDER_MATERIAL ); item->Check( GetPrm3DVisu().GetFlag( FL_RENDER_MATERIAL ) ); diff --git a/3d-viewer/3d_viewer_id.h b/3d-viewer/3d_viewer_id.h index 41cd31db49..da948141db 100644 --- a/3d-viewer/3d_viewer_id.h +++ b/3d-viewer/3d_viewer_id.h @@ -49,7 +49,8 @@ enum id_3dview_frm ID_MENU3D_FL_RENDER_SHADOWS, ID_MENU3D_FL_RENDER_SHOW_HOLES_IN_ZONES, ID_MENU3D_FL_RENDER_TEXTURES, - ID_MENU3D_FL_RENDER_SMOOTH, + ID_MENU3D_FL_RENDER_SMOOTH_NORMALS, + ID_MENU3D_FL_RENDER_USE_MODEL_NORMALS, ID_MENU3D_FL_RENDER_MATERIAL, ID_END_COMMAND_3D, diff --git a/3d-viewer/info3d_visu.h b/3d-viewer/info3d_visu.h index ffb8523910..8a5067363b 100644 --- a/3d-viewer/info3d_visu.h +++ b/3d-viewer/info3d_visu.h @@ -75,7 +75,8 @@ enum DISPLAY3D_FLG { FL_RENDER_SHADOWS, FL_RENDER_SHOW_HOLES_IN_ZONES, FL_RENDER_TEXTURES, - FL_RENDER_SMOOTH, + FL_RENDER_SMOOTH_NORMALS, + FL_RENDER_USE_MODEL_NORMALS, FL_RENDER_MATERIAL, FL_LAST };