void Model::processMeshNormals(FbxMesh *mesh, Vertex *verts, int count) { int polCount = mesh->GetPolygonCount(); for (int polInd = 0; polInd < polCount; polInd++) { for (int vertInd = 0; vertInd < 3; vertInd++) { int cornerIndex = mesh->GetPolygonVertex(polInd, vertInd); FbxVector4 normal; mesh->GetPolygonVertexNormal(polInd, vertInd, normal); normal.Normalize(); verts[cornerIndex].normal.x = normal[0]; verts[cornerIndex].normal.y = normal[1]; verts[cornerIndex].normal.z = normal[2]; verts[cornerIndex].tangent = getTangent(verts[cornerIndex].normal); verts[cornerIndex].binormal = getBinormal(verts[cornerIndex].normal, verts[cornerIndex].tangent); } } }
Vec3f CylinderDistribution3D::generate(void) const { Vec3f Result; switch(getSurfaceOrVolume()) { case SURFACE: { std::vector<Real32> Areas; //Min Cap Areas.push_back(0.5*osgAbs(getMaxTheta() - getMinTheta())*(getOuterRadius()*getOuterRadius() - getInnerRadius()*getInnerRadius())); //Max Cap Areas.push_back(Areas.back() + 0.5*osgAbs(getMaxTheta() - getMinTheta())*(getOuterRadius()*getOuterRadius() - getInnerRadius()*getInnerRadius())); //Inner Tube Areas.push_back(Areas.back() + getInnerRadius()*osgAbs(getMaxTheta() - getMinTheta()) * getHeight()); //Outer Tube Areas.push_back(Areas.back() + getOuterRadius()*osgAbs(getMaxTheta() - getMinTheta()) * getHeight()); bool HasTubeSides(osgAbs(getMaxTheta() - getMinTheta()) - 6.283185 < -0.000001); if(HasTubeSides) { //MinTheta Tube Side Areas.push_back(Areas.back() + (getOuterRadius() - getInnerRadius()) * getHeight()); //MaxTheta Tube Side Areas.push_back(Areas.back() + (getOuterRadius() - getInnerRadius()) * getHeight()); } Real32 PickEdge(RandomPoolManager::getRandomReal32(0.0,1.0)); if(PickEdge < Areas[0]/Areas.back()) { //Max Cap Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0))); Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius())); Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) ); Result = getCenter().subZero() + (Radius*osgSin(Theta))*getTangent() + (Radius*osgCos(Theta))*getBinormal() + (getHeight()/static_cast<Real32>(2.0))*getNormal(); } else if(PickEdge < Areas[1]/Areas.back()) { //Min Cap Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0))); Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius())); Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) ); Result = getCenter().subZero() + (Radius*osgSin(Theta))*getTangent() + (Radius*osgCos(Theta))*getBinormal() + (-getHeight()/static_cast<Real32>(2.0))*getNormal(); } else if(PickEdge < Areas[2]/Areas.back()) { //Inner Tube Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) ); Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0)); Result = getCenter().subZero() + getInnerRadius()*osgSin(Theta)*getTangent() + getInnerRadius()*osgCos(Theta)*getBinormal() + Height*getNormal(); } else if(PickEdge < Areas[3]/Areas.back()) { //Outer Tube Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) ); Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0)); Result = getCenter().subZero() + getOuterRadius()*osgSin(Theta)*getTangent() + getOuterRadius()*osgCos(Theta)*getBinormal() + Height*getNormal(); } else if(HasTubeSides && PickEdge < Areas[4]/Areas.back()) { //MinTheta Tube Side Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0))); Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius())); Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0)); Result = getCenter().subZero() + (Radius*osgSin(getMinTheta()))*getTangent() + (Radius*osgCos(getMinTheta()))*getBinormal() + Height*getNormal(); } else if(HasTubeSides && PickEdge < Areas[5]/Areas.back()) { //MaxTheta Tube Side Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0))); Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius())); Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0)); Result = getCenter().subZero() + (Radius*osgSin(getMaxTheta()))*getTangent() + (Radius*osgCos(getMaxTheta()))*getBinormal() + Height*getNormal(); } else { assert(false && "Should never reach this point"); } break; } case VOLUME: default: { //To get a uniform distribution across the disc get a uniformly distributed allong 0.0 - 1.0 //Then Take the square root of that. This gives a square root distribution from 0.0 - 1.0 //This square root distribution is used for the random radius because the area of a disc is //dependant on the square of the radius, i.e it is a quadratic function Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0))); Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius())); Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0)); Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) ); Result = getCenter().subZero() + (Radius*osgSin(Theta))*getTangent() + (Radius*osgCos(Theta))*getBinormal() + Height*getNormal(); break; } } return Result; }
osg::ref_ptr<osg::Node> MeshManager::get(size_t idx) { /* Not sure if this cache is a good idea since it shares the whole model * tree. OSG can parent the same sub-tree to multiple points, which should * be okay as long as the individual sub-trees don't need changing. */ auto iter = mModelCache.find(idx); if(iter != mModelCache.end()) { osg::ref_ptr<osg::Node> node; if(iter->second.lock(node)) return node; } if(!mModelProgram) { mModelProgram = new osg::Program(); mModelProgram->addShader(osgDB::readShaderFile(osg::Shader::VERTEX, "shaders/object.vert")); mModelProgram->addShader(osgDB::readShaderFile(osg::Shader::FRAGMENT, "shaders/object.frag")); } DFOSG::Mesh *mesh = DFOSG::MeshLoader::get().load(idx); osg::ref_ptr<osg::Geode> geode(new osg::Geode()); for(auto iter = mesh->getPlanes().begin();iter != mesh->getPlanes().end();) { osg::ref_ptr<osg::Vec3Array> vtxs(new osg::Vec3Array()); osg::ref_ptr<osg::Vec3Array> nrms(new osg::Vec3Array()); osg::ref_ptr<osg::Vec3Array> binrms(new osg::Vec3Array()); osg::ref_ptr<osg::Vec2Array> texcrds(new osg::Vec2Array()); osg::ref_ptr<osg::Vec4ubArray> colors(new osg::Vec4ubArray()); osg::ref_ptr<osg::DrawElementsUShort> idxs(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES)); uint16_t texid = iter->getTextureId(); osg::ref_ptr<osg::Texture> tex = TextureManager::get().getTexture(texid); float width = tex->getTextureWidth(); float height = tex->getTextureHeight(); do { const std::vector<DFOSG::MdlPlanePoint> &pts = iter->getPoints(); size_t last_total = vtxs->size(); vtxs->resize(last_total + pts.size()); nrms->resize(last_total + pts.size()); binrms->resize(last_total + pts.size()); texcrds->resize(last_total + pts.size()); colors->resize(last_total + pts.size()); idxs->resize((last_total + pts.size() - 2) * 3); size_t j = last_total; for(const DFOSG::MdlPlanePoint &pt : pts) { uint32_t vidx = pt.getIndex(); (*vtxs)[j].x() = mesh->getPoints()[vidx].x() / 256.0f; (*vtxs)[j].y() = mesh->getPoints()[vidx].y() / 256.0f; (*vtxs)[j].z() = mesh->getPoints()[vidx].z() / 256.0f; (*nrms)[j].x() = iter->getNormal().x() / 256.0f; (*nrms)[j].y() = iter->getNormal().y() / 256.0f; (*nrms)[j].z() = iter->getNormal().z() / 256.0f; (*binrms)[j].x() = iter->getBinormal().x() / 256.0f; (*binrms)[j].y() = iter->getBinormal().y() / 256.0f; (*binrms)[j].z() = iter->getBinormal().z() / 256.0f; (*texcrds)[j].x() = pt.u() / width; (*texcrds)[j].y() = pt.v() / height; (*colors)[j] = osg::Vec4ub(255, 255, 255, 255); if(j >= last_total+2) { (*idxs)[(j-2)*3 + 0] = last_total; (*idxs)[(j-2)*3 + 1] = j-1; (*idxs)[(j-2)*3 + 2] = j; } ++j; } } while(++iter != mesh->getPlanes().end() && iter->getTextureId() == texid); osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject()); vtxs->setVertexBufferObject(vbo); nrms->setVertexBufferObject(vbo); texcrds->setVertexBufferObject(vbo); colors->setVertexBufferObject(vbo); colors->setNormalize(true); osg::ref_ptr<osg::ElementBufferObject> ebo(new osg::ElementBufferObject()); idxs->setElementBufferObject(ebo); osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry); geometry->setVertexArray(vtxs); geometry->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX); geometry->setTexCoordArray(1, binrms, osg::Array::BIND_PER_VERTEX); geometry->setTexCoordArray(0, texcrds, osg::Array::BIND_PER_VERTEX); geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); geometry->setUseDisplayList(false); geometry->setUseVertexBufferObjects(true); geometry->addPrimitiveSet(idxs); /* Cache the stateset used for this texture, so it can be reused for * multiple models (should help OSG batch together objects with similar * state). */ auto &stateiter = mStateSetCache[texid]; osg::ref_ptr<osg::StateSet> ss; if(stateiter.lock(ss) && ss) geometry->setStateSet(ss); else { ss = geometry->getOrCreateStateSet(); ss->setAttributeAndModes(mModelProgram); ss->addUniform(new osg::Uniform("diffuseTex", 0)); ss->setTextureAttribute(0, tex); stateiter = ss; } geode->addDrawable(geometry); } mModelCache[idx] = osg::ref_ptr<osg::Node>(geode); return geode; }