MorphTransformHardware using TBO added

This commit is contained in:
Julien Valentin 2017-08-28 04:51:52 +02:00
parent ed04e2735e
commit 2b2a8f3d2e
3 changed files with 259 additions and 0 deletions

View File

@ -0,0 +1,60 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_MORPH_TRANSFORM_HARDWARE
#define OSGANIMATION_MORPH_TRANSFORM_HARDWARE 1
#include <osgAnimation/Export>
#include <osgAnimation/RigTransform>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Bone>
#include <osg/Matrix>
#include <osg/Array>
namespace osgAnimation
{
class MorphGeometry;
/// This class manage format for hardware morphing
class OSGANIMATION_EXPORT MorphTransformHardware : public MorphTransform
{
public:
MorphTransformHardware();
MorphTransformHardware(const MorphTransformHardware& rth, const osg::CopyOp& copyop);
META_Object(osgAnimation,MorphTransformHardware);
virtual void operator()(MorphGeometry&);
void setShader(osg::Shader*);
protected:
bool init(MorphGeometry&);
osg::ref_ptr<osg::Uniform> _uniformTargetsWeight;
osg::ref_ptr<osg::Shader> _shader;
bool _needInit;
};
}
#endif

View File

@ -34,6 +34,7 @@ SET(TARGET_H
${HEADER_PATH}/RigTransform
${HEADER_PATH}/RigTransformHardware
${HEADER_PATH}/RigTransformSoftware
${HEADER_PATH}/MorphTransformHardware
${HEADER_PATH}/MorphTransformSoftware
${HEADER_PATH}/Sampler
${HEADER_PATH}/Skeleton
@ -76,6 +77,7 @@ SET(TARGET_SRC
RigGeometry.cpp
RigTransformHardware.cpp
RigTransformSoftware.cpp
MorphTransformHardware.cpp
MorphTransformSoftware.cpp
Skeleton.cpp
StackedMatrixElement.cpp

View File

@ -0,0 +1,197 @@
/* -*-c++-*-
* Copyleft 2016 Valentin Julien
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <osgAnimation/MorphTransformHardware>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/TextureBuffer>
#include <sstream>
///texture unit reserved for morphtarget TBO
#define MORPHTEXTUREUNIT 7
using namespace osgAnimation;
MorphTransformHardware::MorphTransformHardware()
{
_needInit = true;
}
MorphTransformHardware::MorphTransformHardware(const MorphTransformHardware& rth, const osg::CopyOp& copyop):
MorphTransform(rth, copyop),
_uniformTargetsWeight(rth._uniformTargetsWeight),
_shader(rth._shader),
_needInit(rth._needInit)
{
}
void MorphTransformHardware::setShader(osg::Shader* shader)
{
_shader = shader;
}
bool MorphTransformHardware::init(MorphGeometry& morphGeometry)
{
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry.getVertexArray());
osg::Vec3Array * vertexSource = (morphGeometry.getVertexSource());
osg::Vec3Array * normalSource = (morphGeometry.getNormalSource());
morphGeometry.setDataVariance(osg::Object::STATIC);
///check for correct morph configuration
///(blender osgexport doesn't set sources so assume morphgeom arrays are sources)
if(pos)
{
///check if source is setted correctly
if (!vertexSource|| vertexSource->size() != pos->size())
{
vertexSource =(static_cast<osg::Vec3Array*>( pos->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));//osg::Vec3Array(pos->begin(),pos->end());
pos->setDataVariance(osg::Object::DYNAMIC);
}
osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry.getNormalArray());
bool normalmorphable = morphGeometry.getMorphNormals() && normal;
if(!normalmorphable) {
OSG_WARN << "MorphTransformHardware::morph geometry "<<morphGeometry.getName()<<" without normal morphing not supported! " << std::endl;
return false;
}
if (normalmorphable && (!normalSource || normalSource->size() != normal->size()))
{
normalSource =(static_cast<osg::Vec3Array*>( normal->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));//osg::Vec3Array(normal->begin(),normal->end());
normal->setDataVariance(osg::Object::DYNAMIC);
}
}
///end check
morphGeometry.setVertexArray(morphGeometry.getVertexSource());
morphGeometry.setNormalArray(morphGeometry.getNormalSource(),osg::Array::BIND_PER_VERTEX);
morphGeometry.setDataVariance(osg::Object::STATIC);
//create one TBO for all morphtargets (pack vertex/normal)
osg::Vec3Array * morphTargets=new osg::Vec3Array ;
MorphGeometry::MorphTargetList & morphlist=morphGeometry.getMorphTargetList();
for(MorphGeometry::MorphTargetList::const_iterator curmorph=morphlist.begin(); curmorph!=morphlist.end(); ++curmorph) {
const osg::Geometry * morphtargetgeom= curmorph->getGeometry() ;
const osg::Vec3Array *varray=(osg::Vec3Array*)morphtargetgeom->getVertexArray();
const osg::Vec3Array *narray=(osg::Vec3Array*)morphtargetgeom->getNormalArray();
if(morphGeometry.getMethod()==MorphGeometry::RELATIVE){
for(unsigned int i=0; i<morphGeometry.getVertexArray()->getNumElements(); ++i) {
morphTargets->push_back( (*varray)[i]);
morphTargets->push_back( (*narray)[i]);
}
}else{
//convert to RELATIVE as it involve less math in the VS than NORMALIZED
const osg::Vec3Array *ovarray=(osg::Vec3Array*)morphGeometry.getVertexArray();
const osg::Vec3Array *onarray=(osg::Vec3Array*)morphGeometry.getNormalArray();
for(unsigned int i=0; i<morphGeometry.getVertexArray()->getNumElements(); ++i) {
morphTargets->push_back( (*varray)[i]- (*ovarray)[i] );
morphTargets->push_back( (*narray)[i]- (*onarray)[i] );
}
}
}
osg::TextureBuffer * morphTargetsTBO=new osg::TextureBuffer();
morphTargetsTBO->setBufferData(morphTargets);
morphTargetsTBO->setInternalFormat( GL_RGB32F_ARB );
//create TBO Texture handle
osg::Uniform * morphTBOHandle=new osg::Uniform(osg::Uniform::SAMPLER_BUFFER,"morphTargets");
morphTBOHandle->set(MORPHTEXTUREUNIT);
//create dynamic uniform for morphtargets animation weights
_uniformTargetsWeight=new osg::Uniform(osg::Uniform::FLOAT,"morphWeights",morphlist.size());
osg::ref_ptr<osg::Program> program ;
osg::ref_ptr<osg::Shader> vertexshader;
osg::ref_ptr<osg::StateSet> stateset = morphGeometry.getOrCreateStateSet();
//grab geom source program and vertex shader if _shader is not setted
if(!_shader.valid() && (program = (osg::Program*)stateset->getAttribute(osg::StateAttribute::PROGRAM)))
{
for(unsigned int i=0;i<program->getNumShaders();++i)
if(program->getShader(i)->getType()==osg::Shader::VERTEX){
// vertexshader=program->getShader(i);
program->removeShader(vertexshader);
}
}else {
} program = new osg::Program;
program->setName("HardwareMorphing");
//set default source if _shader is not user setted
if (!vertexshader.valid()){
if (!_shader.valid())
vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"morphing.vert");
else vertexshader=_shader;
}
if (!vertexshader.valid()) {
OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl;
return false;
}
// replace max matrix by the value from uniform
{
std::string str = vertexshader->getShaderSource();
std::string toreplace = std::string("MAX_MORPHWEIGHT");
std::size_t start = str.find(toreplace);
if (std::string::npos == start){
///perhaps remanance from previous init (if saved after init) so reload shader
vertexshader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"morphing.vert");
if (!vertexshader.valid()) {
OSG_WARN << "RigTransformHardware can't load VertexShader" << std::endl;
return false;
}
str = vertexshader->getShaderSource();
start = str.find(toreplace);
}
if (std::string::npos != start) {
std::stringstream ss;
ss << _uniformTargetsWeight->getNumElements();
str.replace(start, toreplace.size(), ss.str());
vertexshader->setShaderSource(str);
}
else
{
OSG_WARN << "MAX_MORPHWEIGHT not found in Shader! " << str << std::endl;
}
OSG_INFO << "Shader " << str << std::endl;
}
program->addShader(vertexshader.get());
//morphGeometry.setStateSet((osg::StateSet *) osg::CopyOp()(source.getOrCreateStateSet()));
osg::ref_ptr<osg::StateSet> ss = morphGeometry.getOrCreateStateSet();
ss->addUniform(_uniformTargetsWeight);
ss->setTextureAttribute(MORPHTEXTUREUNIT,morphTargetsTBO);
ss->addUniform( morphTBOHandle);
ss->addUniform(new osg::Uniform("nbMorphVertex", morphGeometry.getVertexArray()->getNumElements()));
ss->setAttributeAndModes(program.get());
_needInit = false;
return true;
}
void MorphTransformHardware::operator()(MorphGeometry& geom)
{
if (_needInit)
if (!init(geom))
return;
///upload new morph weights each update via uniform
int curimorph=0;
MorphGeometry::MorphTargetList & morphlist=geom.getMorphTargetList();
for(MorphGeometry::MorphTargetList::const_iterator curmorph=morphlist.begin(); curmorph!=morphlist.end(); ++curmorph)
_uniformTargetsWeight->setElement(curimorph++, curmorph->getWeight());
_uniformTargetsWeight->dirty();
}