ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TextureRenderManager.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <CVLog.h>
11 #include <ecvMaterialSet.h>
12 
17 
18 // VTK
19 #include <vtkActor.h>
20 #include <vtkLODActor.h>
21 #include <vtkPolyData.h>
22 #include <vtkRenderer.h>
23 
24 namespace PclUtils {
25 namespace renders {
26 
27 TextureRenderManager::TextureRenderManager() { InitializeRenderers(); }
28 
30 
31 void TextureRenderManager::InitializeRenderers() {
32  // Register all available renderers in priority order
33  // Higher priority renderers are checked first
34  // Note: PBRRenderer now handles both PBR textures and material-only cases
35  // (VtkMultiTextureRenderer::ApplyPBRMaterial automatically detects the
36  // mode)
37  renderers_.push_back(std::make_unique<PBRRenderer>());
38  renderers_.push_back(std::make_unique<MultiTextureRenderer>());
39 
40  CVLog::PrintDebug("[TextureRenderManager] Initialized %zu renderers",
41  renderers_.size());
42 }
43 
44 TextureRenderManager::MaterialAnalysis TextureRenderManager::AnalyzeMaterials(
45  const ccMaterialSet* materials) const {
46  MaterialAnalysis analysis;
47 
48  if (!materials || materials->empty()) {
49  return analysis;
50  }
51 
52  analysis.material_count = materials->size();
53 
54  // Check first material for PBR encoding
55  auto firstMaterial = materials->at(0);
56  if (firstMaterial) {
57  analysis.has_pbr_textures =
58  MaterialConverter::HasPBREncoding(firstMaterial.data());
59  }
60 
61  // Check for multiple map_Kd textures
62  analysis.has_multiple_map_kd =
64 
65  // Check if any material has PBR textures (not just encoding)
66  if (!analysis.has_pbr_textures) {
67  auto pbr_material = MaterialConverter::FromMaterialSet(materials);
68  analysis.has_pbr_textures = pbr_material.hasPBRTextures();
69  }
70 
71  // Also check if any material has any texture files at all
72  // This helps determine if materials have textures or are material-only
73  // PBRRenderer now handles both cases (with and without textures)
74  analysis.has_any_texture = HasAnyTextureFiles(materials);
75 
77  "[TextureRenderManager::AnalyzeMaterials] Analysis complete: "
78  "count=%zu, has_pbr=%d, has_multiple_map_kd=%d, has_any_texture=%d",
79  analysis.material_count, analysis.has_pbr_textures,
80  analysis.has_multiple_map_kd, analysis.has_any_texture);
81 
82  return analysis;
83 }
84 
86  const ccMaterialSet* materials) const {
87  if (!materials || materials->empty()) {
89  "[TextureRenderManager::SelectRenderer] No materials "
90  "provided");
91  return nullptr;
92  }
93 
94  MaterialAnalysis analysis = AnalyzeMaterials(materials);
95 
97  "[TextureRenderManager::SelectRenderer] Analysis: count=%zu, "
98  "has_pbr=%d, has_multiple_map_kd=%d",
99  analysis.material_count, analysis.has_pbr_textures,
100  analysis.has_multiple_map_kd);
101 
102  // Try each renderer in order until one can handle the materials
103  for (auto& renderer : renderers_) {
104  if (renderer->CanHandle(analysis.material_count,
105  analysis.has_pbr_textures,
106  analysis.has_multiple_map_kd)) {
108  "[TextureRenderManager::SelectRenderer] Selected: %s",
109  renderer->GetName().c_str());
110  return renderer.get();
111  }
112  }
113 
115  "[TextureRenderManager::SelectRenderer] No renderer can handle "
116  "materials");
117  return nullptr;
118 }
119 
121  RenderingMode mode) const {
122  for (auto& renderer : renderers_) {
123  if (renderer->GetMode() == mode) {
124  return renderer.get();
125  }
126  }
127  return nullptr;
128 }
129 
130 bool TextureRenderManager::HasAnyTextureFiles(
131  const ccMaterialSet* materials) const {
132  if (!materials || materials->empty()) {
133  return false;
134  }
135 
136  for (size_t i = 0; i < materials->size(); ++i) {
137  auto mat = materials->at(i);
138  if (!mat) continue;
139 
140  // Check if material has any texture file (not just texture map type)
141  using TexType = ccMaterial::TextureMapType;
142  for (int type = 0; type < 15; ++type) { // All texture types
143  if (mat->hasTextureMap(static_cast<TexType>(type))) {
144  // Check if this texture type has actual files
145  std::vector<QString> textureFiles =
146  mat->getTextureFilenames(static_cast<TexType>(type));
147  for (const auto& file : textureFiles) {
148  if (!file.isEmpty()) {
149  return true; // Found at least one texture file
150  }
151  }
152  }
153  }
154  }
155 
156  return false; // No texture files found
157 }
158 
159 bool TextureRenderManager::Apply(vtkLODActor* actor,
160  const ccMaterialSet* materials,
161  vtkPolyData* polydata,
162  vtkRenderer* renderer) {
163  if (!actor) {
164  CVLog::Error("[TextureRenderManager::Apply] Actor is null");
165  return false;
166  }
167 
168  TextureRendererBase* selected_renderer = SelectRenderer(materials);
169  if (!selected_renderer) {
170  CVLog::Error(
171  "[TextureRenderManager::Apply] Cannot select renderer for "
172  "materials");
173  return false;
174  }
175 
177  "[TextureRenderManager::Apply] Applying rendering using %s",
178  selected_renderer->GetName().c_str());
179 
180  return selected_renderer->Apply(actor, materials, polydata, renderer);
181 }
182 
183 bool TextureRenderManager::Update(vtkActor* actor,
184  const ccMaterialSet* materials,
185  vtkPolyData* polydata,
186  vtkRenderer* renderer) {
187  if (!actor) {
188  CVLog::Error("[TextureRenderManager::Update] Actor is null");
189  return false;
190  }
191 
192  TextureRendererBase* selected_renderer = SelectRenderer(materials);
193  if (!selected_renderer) {
194  CVLog::Error(
195  "[TextureRenderManager::Update] Cannot select renderer for "
196  "materials");
197  return false;
198  }
199 
201  "[TextureRenderManager::Update] Updating rendering using %s",
202  selected_renderer->GetName().c_str());
203 
204  return selected_renderer->Update(actor, materials, polydata, renderer);
205 }
206 
207 } // namespace renders
208 } // namespace PclUtils
char type
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
Definition: CVLog.cpp:153
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
static bool HasPBREncoding(const ccMaterial *material)
Detect if material has PBR encoding.
static bool HasMultipleMapKd(const ccMaterialSet *materials)
Detect if material set has multiple map_Kd textures.
static VtkUtils::VtkMultiTextureRenderer::PBRMaterial FromMaterialSet(const ccMaterialSet *materials)
Convert first material from ccMaterialSet to PBRMaterial.
TextureRendererBase * SelectRenderer(const ccMaterialSet *materials) const
Detect and select appropriate renderer for materials.
bool Update(vtkActor *actor, const ccMaterialSet *materials, vtkPolyData *polydata, vtkRenderer *renderer)
Update existing actor with new materials.
TextureRendererBase * GetRenderer(RenderingMode mode) const
Get renderer by mode.
bool Apply(vtkLODActor *actor, const ccMaterialSet *materials, vtkPolyData *polydata, vtkRenderer *renderer)
Apply rendering to actor.
Base class for all texture renderers.
virtual bool Apply(vtkLODActor *actor, const class ccMaterialSet *materials, vtkPolyData *polydata, vtkRenderer *renderer)=0
Apply rendering to actor.
virtual bool Update(vtkActor *actor, const class ccMaterialSet *materials, vtkPolyData *polydata, vtkRenderer *renderer)=0
Update existing actor with new materials.
virtual std::string GetName() const =0
Get renderer name for logging.
Mesh (triangle) material.
TextureMapType
Texture map types for PBR materials.
Definition: ecvMaterial.h:176
RenderingMode
Rendering mode enumeration.