00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <sofa/gui/qt/viewer/qtogre/OgreVisualModel.h>
00028
00029 #include <sofa/core/ObjectFactory.h>
00030 #include <sofa/helper/io/Mesh.h>
00031 #include <sofa/simulation/tree/GNode.h>
00032
00033 #include <sofa/core/componentmodel/topology/BaseMeshTopology.h>
00034 #include <sofa/core/componentmodel/behavior/BaseMechanicalMapping.h>
00035 #include <sofa/core/BaseMapping.h>
00036
00037 #include <iostream>
00038
00039 namespace sofa
00040 {
00041
00042 namespace component
00043 {
00044
00045 namespace visualmodel
00046 {
00047
00048 SOFA_DECL_CLASS(OgreVisualModel)
00049
00050 int OgreVisualModel::counter;
00051
00052 OgreVisualModel::OgreVisualModel()
00053 : materialname(initData(&materialname, "materialname", "material name")),scale(1.0)
00054 , ogreMesh(NULL), ogreEntity(NULL), ogreNode(NULL)
00055 {
00056 }
00057
00058
00059 std::string OgreVisualModel::uniqueName(void)
00060 {
00061 std::ostringstream s;
00062 s << getOgreName() + "_" << ++OgreVisualModel::counter;
00063 return s.str();
00064 }
00065
00066
00067 std::string OgreVisualModel::getOgreName()
00068 {
00069 return "SOFA"+static_cast<sofa::simulation::tree::GNode*>(getContext())->getPathName()+"/"+getName();
00070 }
00071
00072 void OgreVisualModel::parse(core::objectmodel::BaseObjectDescription* arg)
00073 {
00074
00075 if (arg->getAttribute("scale")!=NULL) {
00076
00077 scale=atof(arg->getAttribute("scale","1.0"));
00078 }
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 if (arg->getAttribute("dx")!=NULL || arg->getAttribute("dy")!=NULL || arg->getAttribute("dz")!=NULL) {
00090
00091 dx=atof(arg->getAttribute("dx","0.0"));
00092 dy=atof(arg->getAttribute("dy","0.0"));
00093 dz=atof(arg->getAttribute("dz","0.0"));
00094 }
00095
00096 VisualModelImpl::parse(arg);
00097 }
00098 bool OgreVisualModel::lightSwitched;
00099
00100 void OgreVisualModel::attach(Ogre::SceneManager* sceneMgr)
00101 {
00102
00103
00104 ogreMesh = Ogre::MeshManager::getSingleton().getByName(getOgreName()+".mesh");
00105 if (!ogreMesh.isNull()) setName(uniqueName());
00106 ogreMesh = Ogre::MeshManager::getSingleton().createManual(getOgreName()+".mesh", "General");
00107
00108 if (3*this->vertices.size() > sceneMgr->getShadowIndexBufferSize())
00109 sceneMgr->setShadowIndexBufferSize(3*this->vertices.size());
00110
00111 Ogre::SubMesh *submesh = ogreMesh->createSubMesh();
00112 Ogre::VertexData* vertexData = ogreMesh->sharedVertexData = new Ogre::VertexData();
00113 Ogre::VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
00114 size_t currOffset[2] = {0, 0};
00115
00116 vertexDecl->addElement(0, currOffset[0], Ogre::VET_FLOAT3, Ogre::VES_POSITION);
00117 currOffset[0] += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00118
00119 vertexDecl->addElement(0, currOffset[0], Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
00120 currOffset[0] += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00121 if (!this->texturename.getValue().empty())
00122 {
00123
00124 vertexDecl->addElement(1, currOffset[1], Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
00125 currOffset[1] += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
00126 }
00127
00128 vertexData->vertexCount = this->vertices.size();
00129 vBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), (vertexData->vertexCount>0?vertexData->vertexCount:1), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
00130 Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
00131 binding->setBinding(0, vBuffer);
00132
00133 uploadVertices();
00134
00135 if (!this->texturename.getValue().empty())
00136 {
00137 Ogre::HardwareVertexBufferSharedPtr vBuffer2 = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(1), (vertexData->vertexCount>0?vertexData->vertexCount:1), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
00138 Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
00139 binding->setBinding(1, vBuffer2);
00140
00141 for (unsigned int i=0;i<this->vtexcoords.size();++i) this->vtexcoords[i][1] =1- this->vtexcoords[i][1];
00142 vBuffer2->writeData(0, this->vtexcoords.size() * sizeof(this->vtexcoords[0]), this->vtexcoords.getData());
00143 }
00144 submesh->useSharedVertices = true;
00145
00146 submesh->indexData->indexCount = 3 * getNbTriangles();
00147 iBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer((this->vertices.size() < 0x10000) ? Ogre::HardwareIndexBuffer::IT_16BIT : Ogre::HardwareIndexBuffer::IT_32BIT, (submesh->indexData->indexCount>0?submesh->indexData->indexCount:1), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
00148 submesh->indexData->indexBuffer = iBuffer;
00149 uploadIndices();
00150 computeBounds();
00151
00152
00153 submesh_material = std::string("Sofa/") + uniqueName();
00154 Ogre::MaterialPtr mat;
00155 if (!materialname.getValue().empty()) {
00156 Ogre::MaterialPtr mat_mem = Ogre::MaterialManager::getSingleton().getByName(materialname.getValue());
00157 mat = mat_mem->clone(submesh_material);
00158 }
00159 else
00160 {
00161 mat = Ogre::MaterialManager::getSingleton().create(submesh_material, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
00162
00163 mat->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE);
00164
00165 if (!this->texturename.getValue().empty())
00166 {
00167 Ogre::TextureUnitState *ogre_texture = mat->getTechnique(0)->getPass(0)->createTextureUnitState(getOgreName()+std::string("_texture"));
00168 ogre_texture->setTextureName(this->texturename.getValue());
00169
00170
00171 }
00172 }
00173 submesh->setMaterialName(submesh_material);
00174 updateMaterial(mat);
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 ogreMesh->load();
00185
00186 ogreEntity = sceneMgr->createEntity( getOgreName(), getOgreName()+".mesh" );
00187
00188 ogreEntity->setNormaliseNormals(true);
00189
00190 ogreNode = sceneMgr->getRootSceneNode()->createChildSceneNode();
00191
00192 ogreNode->attachObject(ogreEntity);
00193
00194 ogreNode->setInitialState();
00195
00196
00197 }
00198
00199
00200 void OgreVisualModel::reinit()
00201 {
00202 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName(submesh_material);
00203 if (!mat.isNull())
00204 {
00205 updateMaterial(mat);
00206 }
00207 updateVisual();
00208 }
00209
00210 void OgreVisualModel::updateMaterial(Ogre::MaterialPtr &mat)
00211 {
00212 if (this->material.getValue().useDiffuse)
00213 mat->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(this->material.getValue().diffuse[0],this->material.getValue().diffuse[1],this->material.getValue().diffuse[2],this->material.getValue().diffuse[3]));
00214 else
00215 mat->getTechnique(0)->getPass(0)->setDiffuse(Ogre::ColourValue(0,0,0,0));
00216
00217 if (this->material.getValue().useAmbient)
00218 mat->getTechnique(0)->getPass(0)->setAmbient(Ogre::ColourValue(this->material.getValue().ambient[0],this->material.getValue().ambient[1],this->material.getValue().ambient[2],this->material.getValue().ambient[3]));
00219 else
00220 mat->getTechnique(0)->getPass(0)->setAmbient(Ogre::ColourValue(0,0,0,0));
00221
00222 if (this->material.getValue().useEmissive)
00223 mat->getTechnique(0)->getPass(0)->setSelfIllumination(Ogre::ColourValue(this->material.getValue().emissive[0],this->material.getValue().emissive[1],this->material.getValue().emissive[2],this->material.getValue().emissive[3]));
00224 else
00225 mat->getTechnique(0)->getPass(0)->setSelfIllumination(Ogre::ColourValue(0,0,0,0));
00226
00227 if (this->material.getValue().useSpecular)
00228 mat->getTechnique(0)->getPass(0)->setSpecular(Ogre::ColourValue(this->material.getValue().specular[0],this->material.getValue().specular[1],this->material.getValue().specular[2],this->material.getValue().specular[3]));
00229 else
00230 mat->getTechnique(0)->getPass(0)->setSpecular(Ogre::ColourValue(0,0,0,0));
00231
00232 if (this->material.getValue().useShininess)
00233 mat->getTechnique(0)->getPass(0)->setShininess(Ogre::Real(this->material.getValue().shininess));
00234 else
00235 mat->getTechnique(0)->getPass(0)->setShininess(Ogre::Real(45));
00236 mat->compile();
00237 }
00238
00239 void OgreVisualModel::updateVisual()
00240 {
00241 if (ogreMesh.isNull()) return;
00242 sofa::core::componentmodel::topology::BaseMeshTopology* topology = dynamic_cast<sofa::core::componentmodel::topology::BaseMeshTopology*>(getContext()->getTopology());
00243 if (topology && topology->getRevision() != meshRevision)
00244 uploadIndices();
00245
00246
00247 if (this->modified
00248 )
00249 {
00250 uploadVertices();
00251 computeNormals();
00252 computeBounds();
00253 lightSwitched = false;
00254 }
00255 }
00256
00257
00258 void OgreVisualModel::uploadVertices()
00259 {
00260 this->modified = false;
00261 Ogre::VertexData* vertexData = ogreMesh->sharedVertexData;
00262 Ogre::VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
00263
00264 if (!ogreMesh->isPreparedForShadowVolumes())
00265 {
00266 if (this->vertices.size() > vertexData->vertexCount)
00267 {
00268
00269 if (this->vertices.size() >= 2* vertexData->vertexCount)
00270 vertexData->vertexCount = this->vertices.size();
00271 else
00272 vertexData->vertexCount *= 2;
00273
00274 vBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), (vertexData->vertexCount>0?vertexData->vertexCount:1),
00275 Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
00276
00277 Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
00278
00279 binding->setBinding(0, vBuffer);
00280 }
00281 if (this->vnormals.size() == 0) computeNormals();
00282 Coord* pVertex = static_cast<Coord*>(vBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00283 for (unsigned int i=0; i < this->vertices.size(); i++)
00284 {
00285 *(pVertex++) = this->vertices[i];
00286 if (this->vnormals.size() <= i) ;
00287 else
00288 *(pVertex++) = this->vnormals[i];
00289 }
00290 dx = dy = dz = 0;
00291 scale = 1;
00292 vBuffer->unlock();
00293 }
00294 else
00295 {
00296
00297
00298 const Ogre::VertexElement* posElem = ogreMesh->sharedVertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
00299 Ogre::HardwareVertexBufferSharedPtr vBufferPos = ogreMesh->sharedVertexData->vertexBufferBinding->getBuffer(posElem->getSource());
00300
00301 const Ogre::VertexElement* normElem = ogreMesh->sharedVertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);
00302 Ogre::HardwareVertexBufferSharedPtr vBufferNorm = ogreMesh->sharedVertexData->vertexBufferBinding->getBuffer(normElem->getSource());
00303
00304 if (this->vertices.size() > vertexData->vertexCount)
00305 {
00306
00307 if (this->vertices.size() >= 2* vertexData->vertexCount)
00308 vertexData->vertexCount = this->vertices.size();
00309 else
00310 vertexData->vertexCount *= 2;
00311 vBufferPos = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(posElem->getSource()), 2*(vertexData->vertexCount>0?vertexData->vertexCount:1), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
00312 vBufferNorm = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(normElem->getSource()), (vertexData->vertexCount>0?vertexData->vertexCount:1), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
00313 Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
00314 binding->setBinding(posElem->getSource(), vBufferPos);
00315 binding->setBinding(normElem->getSource(), vBufferNorm);
00316 }
00317
00318 Coord* pVertex = static_cast<Coord*>(vBufferPos->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00319
00320 memcpy(pVertex, this->vertices.getData(), this->vertices.size()*sizeof(Coord));
00321 memcpy(pVertex+this->vertices.size(), this->vertices.getData(), this->vertices.size()*sizeof(Coord));
00322 vBufferPos->unlock();
00323 Coord* pNormal = static_cast<Coord*>(vBufferNorm->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00324 memcpy(pNormal, this->vnormals.getData(), this->vnormals.size()*sizeof(Coord));
00325 vBufferNorm->unlock();
00326
00327
00328
00329 ogreMesh->getEdgeList()->updateFaceNormals(0,vBufferPos);
00330 }
00331 }
00332
00333 void OgreVisualModel::uploadIndices()
00334 {
00335 unsigned int nindices = 3*getNbTriangles();
00336 if (iBuffer->getNumIndexes() < nindices)
00337 {
00338 unsigned int nalloc;
00339
00340 if (nindices >= 2* iBuffer->getNumIndexes())
00341 nalloc = nindices;
00342 else
00343 nalloc = 2*iBuffer->getNumIndexes();
00344 iBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer((nalloc < 0x10000) ? Ogre::HardwareIndexBuffer::IT_16BIT : Ogre::HardwareIndexBuffer::IT_32BIT, (nalloc>0?nalloc:1), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
00345 ogreMesh->getSubMesh(0)->indexData->indexBuffer = iBuffer;
00346 }
00347 ogreMesh->getSubMesh(0)->indexData->indexCount = 3 * getNbTriangles();
00348 sofa::core::componentmodel::topology::BaseMeshTopology* topology = dynamic_cast<sofa::core::componentmodel::topology::BaseMeshTopology*>(getContext()->getTopology());
00349
00350 if (this->useTopology && topology)
00351 {
00352 const sofa::core::componentmodel::topology::BaseMeshTopology::SeqTriangles& triangles = topology->getTriangles();
00353 const sofa::core::componentmodel::topology::BaseMeshTopology::SeqQuads& quads = topology->getQuads();
00354 if (iBuffer->getType() == Ogre::HardwareIndexBuffer::IT_32BIT)
00355 {
00356 unsigned int* pIndices = static_cast<unsigned int*>(iBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00357 for (unsigned int i=0; i < triangles.size(); ++i)
00358 {
00359 *(pIndices++) = static_cast<unsigned int>(triangles[i][0]);
00360 *(pIndices++) = static_cast<unsigned int>(triangles[i][1]);
00361 *(pIndices++) = static_cast<unsigned int>(triangles[i][2]);
00362 }
00363 for (unsigned int i = 0; i < quads.size() ; i++)
00364 {
00365 *(pIndices++) = static_cast<unsigned int>(quads[i][0]);
00366 *(pIndices++) = static_cast<unsigned int>(quads[i][1]);
00367 *(pIndices++) = static_cast<unsigned int>(quads[i][2]);
00368 *(pIndices++) = static_cast<unsigned int>(quads[i][0]);
00369 *(pIndices++) = static_cast<unsigned int>(quads[i][2]);
00370 *(pIndices++) = static_cast<unsigned int>(quads[i][3]);
00371 }
00372 iBuffer->unlock();
00373 }
00374 else
00375 {
00376 unsigned short* pIndices = static_cast<unsigned short*>(iBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00377 for (unsigned int i=0; i < triangles.size(); ++i)
00378 {
00379 *(pIndices++) = static_cast<unsigned short>(triangles[i][0]);
00380 *(pIndices++) = static_cast<unsigned short>(triangles[i][1]);
00381 *(pIndices++) = static_cast<unsigned short>(triangles[i][2]);
00382 }
00383 for (unsigned int i = 0; i < quads.size() ; i++)
00384 {
00385 *(pIndices++) = static_cast<unsigned short>(quads[i][0]);
00386 *(pIndices++) = static_cast<unsigned short>(quads[i][1]);
00387 *(pIndices++) = static_cast<unsigned short>(quads[i][2]);
00388 *(pIndices++) = static_cast<unsigned short>(quads[i][0]);
00389 *(pIndices++) = static_cast<unsigned short>(quads[i][2]);
00390 *(pIndices++) = static_cast<unsigned short>(quads[i][3]);
00391 }
00392 iBuffer->unlock();
00393 }
00394 meshRevision = topology->getRevision();
00395 }
00396 else
00397 {
00398 if (iBuffer->getType() == Ogre::HardwareIndexBuffer::IT_32BIT)
00399 {
00400 iBuffer->writeData(0, this->triangles.size() * sizeof(Triangle), this->triangles.getData());
00401 }
00402 else
00403 {
00404
00405 unsigned short* pIndices = static_cast<unsigned short*>(iBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00406 for (unsigned int i=0; i < triangles.size(); ++i)
00407 {
00408 *(pIndices++) = static_cast<unsigned short>(triangles[i][0]);
00409 *(pIndices++) = static_cast<unsigned short>(triangles[i][1]);
00410 *(pIndices++) = static_cast<unsigned short>(triangles[i][2]);
00411 }
00412 for (unsigned int i = 0; i < quads.size() ; i++)
00413 {
00414 *(pIndices++) = static_cast<unsigned short>(this->quads[i][0]);
00415 *(pIndices++) = static_cast<unsigned short>(this->quads[i][1]);
00416 *(pIndices++) = static_cast<unsigned short>(this->quads[i][2]);
00417 *(pIndices++) = static_cast<unsigned short>(this->quads[i][0]);
00418 *(pIndices++) = static_cast<unsigned short>(this->quads[i][2]);
00419 *(pIndices++) = static_cast<unsigned short>(this->quads[i][3]);
00420 }
00421 iBuffer->unlock();
00422 }
00423
00424 }
00425
00426 }
00427
00428 void OgreVisualModel::computeNormals()
00429 {
00430 if (this->vertNormIdx.size() != this->vertices.size())
00431 {
00432
00433 this->vertNormIdx.resize(this->vertices.size());
00434 for (unsigned int i = 0; i < this->vertices.size(); i++)
00435 this->vertNormIdx[i] = i;
00436 }
00437 if (this->vertices.size() == 0) return;
00438 this->vnormals.resize(this->vertices.size());
00439 for (unsigned int i = 0; i < this->vnormals.size(); i++)
00440 this->vnormals[i].clear();
00441 if (this->useTopology)
00442 {
00443
00444 sofa::core::componentmodel::topology::BaseMeshTopology* topology = dynamic_cast<sofa::core::componentmodel::topology::BaseMeshTopology*>(getContext()->getTopology());
00445 if (topology != NULL)
00446 {
00447 const sofa::core::componentmodel::topology::BaseMeshTopology::SeqTriangles& triangles = topology->getTriangles();
00448 const sofa::core::componentmodel::topology::BaseMeshTopology::SeqQuads& quads = topology->getQuads();
00449 for (unsigned int i = 0; i < triangles.size() ; i++)
00450 {
00451 const Coord & v1 = this->vertices[triangles[i][0]];
00452 const Coord & v2 = this->vertices[triangles[i][1]];
00453 const Coord & v3 = this->vertices[triangles[i][2]];
00454 Coord n = cross(v2-v1, v3-v1);
00455 n.normalize();
00456 this->vnormals[vertNormIdx[triangles[i][0]]] += n;
00457 this->vnormals[vertNormIdx[triangles[i][1]]] += n;
00458 this->vnormals[vertNormIdx[triangles[i][2]]] += n;
00459 }
00460 for (unsigned int i = 0; i < quads.size() ; i++)
00461 {
00462 const Coord & v1 = this->vertices[quads[i][0]];
00463 const Coord & v2 = this->vertices[quads[i][1]];
00464 const Coord & v3 = this->vertices[quads[i][3]];
00465 Coord n = cross(v2-v1, v3-v1);
00466 n.normalize();
00467 this->vnormals[vertNormIdx[quads[i][0]]] += n;
00468 this->vnormals[vertNormIdx[quads[i][1]]] += n;
00469 this->vnormals[vertNormIdx[quads[i][2]]] += n;
00470 this->vnormals[vertNormIdx[quads[i][3]]] += n;
00471 }
00472 }
00473 }
00474 else
00475 {
00476 for (unsigned int i = 0; i < triangles.size() ; i++)
00477 {
00478 const Coord & v1 = this->vertices[triangles[i][0]];
00479 const Coord & v2 = this->vertices[triangles[i][1]];
00480 const Coord & v3 = this->vertices[triangles[i][2]];
00481 Coord n = cross(v2-v1, v3-v1);
00482 n.normalize();
00483 this->vnormals[vertNormIdx[triangles[i][0]]] += n;
00484 this->vnormals[vertNormIdx[triangles[i][1]]] += n;
00485 this->vnormals[vertNormIdx[triangles[i][2]]] += n;
00486 }
00487 }
00488 for (int i = this->vnormals.size()-1; i >=0 ; i--)
00489 {
00490 Coord n = this->vnormals[vertNormIdx[i]];
00491 n.normalize();
00492 this->vnormals[i] = n;
00493 }
00494 }
00495
00496 void OgreVisualModel::computeBounds()
00497 {
00498 Ogre::Vector3 bbmin, bbmax;
00499 float r2max = 0;
00500 if (this->vertices.size()>0)
00501 {
00502 bbmin = conv(this->vertices[0]);
00503 bbmax = bbmin;
00504 r2max = this->vertices[0].norm2();
00505 for (unsigned int i=1; i<this->vertices.size(); i++)
00506 {
00507 Ogre::Vector3 p = conv(this->vertices[i]);
00508 bbmin.makeFloor(p);
00509 bbmax.makeCeil(p);
00510 float r2 = p.squaredLength();
00511 if (r2 > r2max) r2max = r2;
00512 }
00513 }
00514 else
00515 {
00516 bbmin = Ogre::Vector3(0,0,0);
00517 bbmax = Ogre::Vector3(0,0,0);
00518 }
00519 ogreMesh->_setBounds( Ogre::AxisAlignedBox( bbmin, bbmax ), false );
00520 ogreMesh->_setBoundingSphereRadius(Ogre::Math::Sqrt(r2max));
00521 if (ogreNode)
00522 ogreNode->_updateBounds();
00523 }
00524
00525 int OgreVisualModelClass = sofa::core::RegisterObject("OGRE 3D Visual Model")
00526 .add < OgreVisualModel >()
00527 ;
00528 }
00529 }
00530 }