Example #1
0
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;
}
Example #3
0
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;
}