Updates gles from sketchfab
* fixes bbox issue for animated scenes * fixes geometry split (perf + line/point primitive management) * removes degenerated faces
This commit is contained in:
@@ -62,7 +62,7 @@ void ComputeAABBOnBoneVisitor::computeBoundingBoxOnBones() {
|
||||
}
|
||||
|
||||
// Compare initial and actual boundingBox if (no change) => no box on bone
|
||||
if(bb == osg::BoundingBox() || bb._min.x() == bb._max.x() || bb._min.y() == bb._max.y() || bb._min.z() == bb._max.z()) {
|
||||
if(bb == osg::BoundingBox() || (bb._min.x() == bb._max.x() && bb._min.y() == bb._max.y() && bb._min.z() == bb._max.z())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ SET(TARGET_SRC
|
||||
BindPerVertexVisitor.cpp
|
||||
DetachPrimitiveVisitor.cpp
|
||||
GeometryIndexSplitter.cpp
|
||||
GeometrySplitterVisitor.cpp
|
||||
SubGeometry.cpp
|
||||
OpenGLESGeometryOptimizer.cpp
|
||||
RemapGeometryVisitor.cpp
|
||||
RigAnimationVisitor.cpp
|
||||
RigAttributesVisitor.cpp
|
||||
TriangleMeshSmoother.cpp
|
||||
@@ -25,9 +25,11 @@ SET(TARGET_H
|
||||
DrawArrayVisitor
|
||||
EdgeIndexFunctor
|
||||
GeometryArray
|
||||
GeometryCleaner
|
||||
GeometryIndexSplitter
|
||||
GeometryInspector
|
||||
GeometrySplitterVisitor
|
||||
GeometryMapper
|
||||
RemapGeometryVisitor
|
||||
GeometryUniqueVisitor
|
||||
glesUtil
|
||||
IndexMeshVisitor
|
||||
|
||||
138
src/osgPlugins/gles/GeometryCleaner
Normal file
138
src/osgPlugins/gles/GeometryCleaner
Normal file
@@ -0,0 +1,138 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab
|
||||
*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commercial and non commercial
|
||||
* applications, as long as this copyright notice is maintained.
|
||||
*
|
||||
* This application 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_CLEANER
|
||||
#define GEOMETRY_CLEANER
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
#include <osgAnimation/MorphGeometry>
|
||||
|
||||
#include "GeometryMapper"
|
||||
#include "SubGeometry"
|
||||
|
||||
|
||||
class GeometryCleaner : public GeometryMapper
|
||||
{
|
||||
public:
|
||||
|
||||
const GeometryList& process(osg::Geometry& geometry) {
|
||||
_clean.clear();
|
||||
|
||||
if(dynamic_cast<osgAnimation::MorphGeometry*>(&geometry)) {
|
||||
// a morph geometry may have a degenerated primitive in one target but not all targets
|
||||
// let's leave them unmodified
|
||||
_clean.push_back(&geometry);
|
||||
}
|
||||
else if(dynamic_cast<osgAnimation::RigGeometry*>(&geometry)) {
|
||||
// skipping rigged geometry for now
|
||||
_clean.push_back(&geometry);
|
||||
}
|
||||
else {
|
||||
osg::Vec3Array* positions = dynamic_cast<osg::Vec3Array*>(geometry.getVertexArray());
|
||||
SubGeometry cleaned(geometry,
|
||||
clean(*positions, getTriangles(geometry), 3),
|
||||
clean(*positions, getLines(geometry), 2),
|
||||
clean(*positions, getWireframe(geometry), 2),
|
||||
clean(*positions, getPoints(geometry), 1));
|
||||
_clean.push_back(cleaned.geometry());
|
||||
}
|
||||
|
||||
return _clean;
|
||||
}
|
||||
|
||||
osg::DrawElements* getTriangles(osg::Geometry& geometry) {
|
||||
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
||||
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
||||
if(primitive && primitive->getMode() == osg::PrimitiveSet::TRIANGLES) {
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
osg::DrawElements* getLines(osg::Geometry& geometry) {
|
||||
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
||||
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
||||
if(primitive && primitive->getMode() == osg::PrimitiveSet::LINES) {
|
||||
bool wireframe(false);
|
||||
if(!primitive->getUserValue("wireframe", wireframe) || !wireframe)
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
osg::DrawElements* getWireframe(osg::Geometry& geometry) {
|
||||
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
||||
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
||||
if(primitive && primitive->getMode() == osg::PrimitiveSet::LINES) {
|
||||
bool wireframe(false);
|
||||
if(primitive->getUserValue("wireframe", wireframe) && wireframe)
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
osg::DrawElements* getPoints(osg::Geometry& geometry) {
|
||||
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
||||
osg::DrawElements* primitive = geometry.getPrimitiveSet(i)->getDrawElements();
|
||||
if(primitive && primitive->getMode() == osg::PrimitiveSet::POINTS) {
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> clean(const osg::Vec3Array& positions, osg::DrawElements* elements, const unsigned int size) {
|
||||
std::vector<unsigned int> indices;
|
||||
|
||||
if(!elements) return indices;
|
||||
|
||||
for(unsigned int i = 0 ; i < elements->getNumIndices() ; i += size) {
|
||||
if(size == 3) {
|
||||
unsigned int v1 = elements->index(i),
|
||||
v2 = elements->index(i + 1),
|
||||
v3 = elements->index(i + 2);
|
||||
osg::Vec3 p1 = positions[v1],
|
||||
p2 = positions[v2],
|
||||
p3 = positions[v3];
|
||||
|
||||
osg::Vec3f cross = (p2 - p1) ^ (p3 - p1);
|
||||
if(cross.length()) {
|
||||
indices.push_back(v1);
|
||||
indices.push_back(v2);
|
||||
indices.push_back(v3);
|
||||
}
|
||||
}
|
||||
else if (size == 2) {
|
||||
unsigned int v1 = elements->index(i),
|
||||
v2 = elements->index(i + 1);
|
||||
if(!(positions[v1] == positions[v2])) {
|
||||
indices.push_back(v1);
|
||||
indices.push_back(v2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
indices.push_back(elements->index(i));
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
|
||||
GeometryList _clean;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -25,15 +25,81 @@
|
||||
#include <osgAnimation/RigGeometry>
|
||||
|
||||
#include "glesUtil"
|
||||
#include "GeometryMapper"
|
||||
#include "GeometryArray"
|
||||
#include "TriangleMeshGraph"
|
||||
#include "SubGeometry"
|
||||
#include "Line"
|
||||
|
||||
|
||||
class GeometryIndexSplitter
|
||||
class GeometryIndexSplitter : public GeometryMapper
|
||||
{
|
||||
protected:
|
||||
class Cluster {
|
||||
public:
|
||||
Cluster(unsigned int maxAllowedIndex):
|
||||
maxIndex(maxAllowedIndex)
|
||||
{
|
||||
}
|
||||
|
||||
bool full() const {
|
||||
return subvertices.size() >= maxIndex;
|
||||
}
|
||||
|
||||
bool fullOfTriangles() const {
|
||||
// consider worse case i.e. no triangle vertex is already in the cluster
|
||||
// so need room for 3 indices
|
||||
return subvertices.size() + 3 >= maxIndex;
|
||||
}
|
||||
|
||||
bool fullOfLines() const {
|
||||
return subvertices.size() + 2 >= maxIndex;
|
||||
}
|
||||
|
||||
bool contains(unsigned int v1, unsigned int v2) const {
|
||||
return contains(v1) && contains(v2);
|
||||
}
|
||||
|
||||
bool contains(unsigned int v1) const {
|
||||
return subvertices.count(v1);
|
||||
}
|
||||
|
||||
void addTriangle(unsigned int v1, unsigned int v2, unsigned v3) {
|
||||
subtriangles.push_back(v1);
|
||||
subtriangles.push_back(v2);
|
||||
subtriangles.push_back(v3);
|
||||
|
||||
subvertices.insert(v1);
|
||||
subvertices.insert(v2);
|
||||
subvertices.insert(v3);
|
||||
}
|
||||
|
||||
void addLine(unsigned int v1, unsigned int v2) {
|
||||
sublines.push_back(v1);
|
||||
sublines.push_back(v2);
|
||||
|
||||
subvertices.insert(v1);
|
||||
subvertices.insert(v2);
|
||||
}
|
||||
|
||||
void addPoint(unsigned int v1) {
|
||||
subpoints.push_back(v1);
|
||||
|
||||
subvertices.insert(v1);
|
||||
}
|
||||
|
||||
void addWire(unsigned int v1, unsigned int v2) {
|
||||
subwireframe.push_back(v1);
|
||||
subwireframe.push_back(v2);
|
||||
}
|
||||
|
||||
public:
|
||||
const unsigned int maxIndex;
|
||||
IndexVector subtriangles, subwireframe, sublines, subpoints;
|
||||
IndexSet subvertices;
|
||||
};
|
||||
|
||||
|
||||
class IndexCache : public IndexDeque {
|
||||
public:
|
||||
IndexCache(unsigned int size=64) : _size(size)
|
||||
@@ -48,18 +114,29 @@ protected:
|
||||
};
|
||||
|
||||
public:
|
||||
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
|
||||
|
||||
GeometryIndexSplitter(unsigned int maxAllowedIndex):
|
||||
_maxAllowedIndex(maxAllowedIndex)
|
||||
{}
|
||||
|
||||
const GeometryList& process(osg::Geometry& geometry) {
|
||||
_geometryList.clear();
|
||||
split(geometry);
|
||||
return _geometryList;
|
||||
}
|
||||
|
||||
bool split(osg::Geometry&);
|
||||
|
||||
unsigned int findCandidate(const IndexVector&);
|
||||
unsigned int findCandidate(const IndexVector&, const IndexVector&);
|
||||
void setTriangleCluster(const TriangleMeshGraph&, unsigned int, unsigned int, IndexVector&, IndexSet&, unsigned int&);
|
||||
void extract_primitives(const IndexSet&, const osg::DrawElements*, IndexVector&, unsigned int);
|
||||
template<typename C>
|
||||
typename C::value_type getNext(C& primitives, typename C::value_type default_value) {
|
||||
if(primitives.empty()) {
|
||||
return default_value;
|
||||
}
|
||||
typename C::value_type next = *primitives.begin();
|
||||
primitives.erase(primitives.begin());
|
||||
return next;
|
||||
}
|
||||
|
||||
unsigned int findCandidate(IndexSet&, const IndexCache&, const TriangleMeshGraph&);
|
||||
|
||||
protected:
|
||||
bool needToSplit(const osg::Geometry&) const;
|
||||
@@ -68,7 +145,6 @@ protected:
|
||||
|
||||
template<typename T>
|
||||
void setBufferBoundingBox(T*) const;
|
||||
void setValidIndices(std::set<unsigned int>&, const osg::DrawElements*) const;
|
||||
|
||||
public:
|
||||
const unsigned int _maxAllowedIndex;
|
||||
|
||||
@@ -11,8 +11,8 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
|
||||
attachBufferBoundingBox(geometry);
|
||||
|
||||
osg::DrawElements *wire_primitive = 0,
|
||||
*line_primitive = 0,
|
||||
*point_primitive = 0;
|
||||
*line_primitive = 0,
|
||||
*point_primitive = 0;
|
||||
for(unsigned int i = 0 ; i < geometry.getNumPrimitiveSets() ; ++ i) {
|
||||
osg::DrawElements* primitive = (geometry.getPrimitiveSet(i) ? geometry.getPrimitiveSet(i)->getDrawElements() : 0);
|
||||
if(primitive) {
|
||||
@@ -31,29 +31,34 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMeshGraph graph(geometry, false);
|
||||
|
||||
// only wireframe can be processed directly as they simply "duplicate" triangle or edge data;
|
||||
// lines/points may reference points not used for triangles so we keep a set of primitives
|
||||
// that remain to process
|
||||
LineSet source_lines;
|
||||
IndexSet source_points;
|
||||
IndexSet triangles;
|
||||
LineSet lines, wires;
|
||||
IndexSet points;
|
||||
|
||||
for(unsigned int i = 0 ; i < graph.getNumTriangles() ; ++ i) {
|
||||
triangles.insert(i);
|
||||
}
|
||||
if(line_primitive) {
|
||||
for(unsigned int i = 0 ; i < line_primitive->getNumIndices() ; i += 2) {
|
||||
source_lines.insert(Line(line_primitive->index(i), line_primitive->index(i + 1)));
|
||||
lines.insert(Line(line_primitive->index(i), line_primitive->index(i + 1)));
|
||||
}
|
||||
}
|
||||
if(wire_primitive) {
|
||||
for(unsigned int i = 0 ; i < wire_primitive->getNumIndices() ; i += 2) {
|
||||
wires.insert(Line(wire_primitive->index(i), wire_primitive->index(i + 1)));
|
||||
}
|
||||
}
|
||||
if(point_primitive) {
|
||||
for(unsigned int i = 0 ; i < point_primitive->getNumIndices() ; ++ i) {
|
||||
source_points.insert(point_primitive->index(i));
|
||||
points.insert(point_primitive->index(i));
|
||||
}
|
||||
}
|
||||
|
||||
TriangleMeshGraph graph(geometry, false);
|
||||
unsigned int remaining_triangles = graph.getNumTriangles(),
|
||||
cluster = 0;
|
||||
IndexVector clusters(remaining_triangles, 0);
|
||||
IndexCache cache;
|
||||
|
||||
// assign a cluster id for each triangle
|
||||
// 1. bootstrap cluster by selecting first remaining triangle
|
||||
// 2. while cluster size is < max cluster size
|
||||
@@ -64,95 +69,75 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
|
||||
// 3. insert wireframe edges corresponding to selected triangles
|
||||
// 4. extract subgeometry
|
||||
|
||||
while(remaining_triangles || !source_lines.empty() || !source_points.empty()) {
|
||||
IndexVector subtriangles, subwireframe, sublines, subpoints;
|
||||
IndexSet cluster_vertices;
|
||||
while(triangles.size() || lines.size() || points.size()) {
|
||||
Cluster cluster(_maxAllowedIndex);
|
||||
IndexCache cache;
|
||||
unsigned int candidate = std::numeric_limits<unsigned int>::max();
|
||||
|
||||
++ cluster;
|
||||
// let's consider that every insert needs the place for a full new primitive for simplicity
|
||||
while(!cluster.fullOfTriangles() &&
|
||||
(candidate = findCandidate(triangles, cache, graph)) != std::numeric_limits<unsigned int>::max()) {
|
||||
cache.push_back(candidate);
|
||||
Triangle t = graph.triangle(candidate);
|
||||
cluster.addTriangle(t.v1(), t.v2(), t.v3());
|
||||
}
|
||||
|
||||
if(remaining_triangles) {
|
||||
// find first unmarked triangle (as remaining_triangles > 0 there *must* be at least one)
|
||||
cache.push_back(findCandidate(clusters));
|
||||
setTriangleCluster(graph, cache.back(), cluster, clusters, cluster_vertices, remaining_triangles);
|
||||
while(!cluster.fullOfLines() && lines.size()) {
|
||||
Line line = getNext(lines, Line(std::numeric_limits<unsigned int>::max(), std::numeric_limits<unsigned int>::max()));
|
||||
cluster.addLine(line._a, line._b);
|
||||
}
|
||||
|
||||
while(remaining_triangles && cluster_vertices.size() < _maxAllowedIndex) {
|
||||
unsigned int candidate = std::numeric_limits<unsigned int>::max();
|
||||
while(!cluster.full() && points.size()) {
|
||||
unsigned int point = getNext(points, std::numeric_limits<unsigned int>::max());
|
||||
cluster.addPoint(point);
|
||||
}
|
||||
|
||||
for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) {
|
||||
candidate = findCandidate(graph.triangleNeighbors(*cached), clusters);
|
||||
if(candidate != std::numeric_limits<unsigned int>::max()) break;
|
||||
// update lines/points: if all vertices referenced by a point/line primitive are
|
||||
// already extracted, let's insert it in the subgeometry and update the set of
|
||||
// primitives still remaining Lines may e.g. reference one vertex in cluster A and
|
||||
// the other in cluster B hence need specific care
|
||||
if(line_primitive) {
|
||||
for(LineSet::iterator line = lines.begin() ; line != lines.end() ; ) {
|
||||
if(cluster.contains(line->_a, line->_b)) {
|
||||
cluster.addLine(line->_a, line->_b);
|
||||
lines.erase(line ++);
|
||||
}
|
||||
|
||||
if(candidate == std::numeric_limits<unsigned int>::max()) {
|
||||
// do we have room for a triangle having all vertices not in the cluster?
|
||||
if(!(cluster_vertices.size() + 2 < _maxAllowedIndex)) {
|
||||
break;
|
||||
}
|
||||
|
||||
candidate = findCandidate(clusters);
|
||||
}
|
||||
|
||||
cache.push_back(candidate);
|
||||
setTriangleCluster(graph, candidate, cluster, clusters, cluster_vertices, remaining_triangles);
|
||||
}
|
||||
|
||||
// build list of cluster triangles
|
||||
for(unsigned int triangle = 0 ; triangle < clusters.size() ; ++ triangle) {
|
||||
if(clusters[triangle] == cluster) {
|
||||
const Triangle& t = graph.triangle(triangle);
|
||||
subtriangles.push_back(t.v1());
|
||||
subtriangles.push_back(t.v2());
|
||||
subtriangles.push_back(t.v3());
|
||||
}
|
||||
}
|
||||
|
||||
// update lines/points: if all vertices referenced by a point/line primitive are
|
||||
// already extracted, let's insert it in the subgeometry and update the set of
|
||||
// primitives still remaining Lines may e.g. reference one vertex in cluster A and
|
||||
// the other in cluster B hence need specific care
|
||||
if(line_primitive) {
|
||||
extract_primitives(cluster_vertices, line_primitive, sublines, 2);
|
||||
for(unsigned int i = 0 ; i < sublines.size() / 2 ; i += 2) {
|
||||
source_lines.erase(Line(sublines[i], sublines[i + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
if(point_primitive) {
|
||||
extract_primitives(cluster_vertices, point_primitive, subpoints, 1);
|
||||
for(unsigned int i = 0 ; i < subpoints.size() ; ++ i) {
|
||||
source_points.erase(subpoints[i]);
|
||||
else {
|
||||
++ line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let's consider that every new lines adds 2 vertices for simplicity
|
||||
while(!source_lines.empty() && cluster_vertices.size() - 1 < _maxAllowedIndex) {
|
||||
Line line = *source_lines.begin();
|
||||
source_lines.erase(source_lines.begin());
|
||||
cluster_vertices.insert(line._a);
|
||||
cluster_vertices.insert(line._b);
|
||||
sublines.push_back(line._a);
|
||||
sublines.push_back(line._b);
|
||||
}
|
||||
|
||||
while(!source_points.empty() && cluster_vertices.size() < _maxAllowedIndex) {
|
||||
unsigned int point = *source_points.begin();
|
||||
source_points.erase(source_points.begin());
|
||||
cluster_vertices.insert(point);
|
||||
subpoints.push_back(point);
|
||||
if(point_primitive) {
|
||||
// find all cluster vertices that should also have a point primitive
|
||||
for(IndexSet::iterator subvertex = cluster.subvertices.begin() ; subvertex != cluster.subvertices.end() ; ++ subvertex) {
|
||||
unsigned int index = *subvertex;
|
||||
if(points.find(index) != points.end()) {
|
||||
cluster.addPoint(index);
|
||||
points.erase(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally extract wireframe (may originate from triangles or lines but necessarily have
|
||||
// to reference vertices that are *all* in the geometry)
|
||||
if(wire_primitive) {
|
||||
extract_primitives(cluster_vertices, wire_primitive, subwireframe, 2);
|
||||
for(LineSet::iterator wire = wires.begin() ; wire != wires.end() ; ) {
|
||||
if(cluster.contains(wire->_a, wire->_b)) {
|
||||
cluster.addWire(wire->_a, wire->_b);
|
||||
wires.erase(wire ++);
|
||||
}
|
||||
else {
|
||||
++ wire;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_geometryList.push_back(SubGeometry(geometry,
|
||||
subtriangles,
|
||||
sublines,
|
||||
subwireframe,
|
||||
subpoints).geometry());
|
||||
cluster.subtriangles,
|
||||
cluster.sublines,
|
||||
cluster.subwireframe,
|
||||
cluster.subpoints).geometry());
|
||||
}
|
||||
|
||||
osg::notify(osg::NOTICE) << "geometry " << &geometry << " " << geometry.getName()
|
||||
@@ -164,60 +149,20 @@ bool GeometryIndexSplitter::split(osg::Geometry& geometry) {
|
||||
}
|
||||
|
||||
|
||||
unsigned int GeometryIndexSplitter::findCandidate(const IndexVector& clusters) {
|
||||
for(unsigned int i = 0 ; i < clusters.size() ; ++ i) {
|
||||
if(!clusters[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::numeric_limits<unsigned int>::max();
|
||||
}
|
||||
|
||||
|
||||
unsigned int GeometryIndexSplitter::findCandidate(const IndexVector& candidates, const IndexVector& clusters) {
|
||||
for(IndexVector::const_iterator candidate = candidates.begin() ; candidate != candidates.end() ; ++ candidate) {
|
||||
if(!clusters[*candidate]) {
|
||||
return *candidate;
|
||||
}
|
||||
}
|
||||
return std::numeric_limits<unsigned int>::max();
|
||||
}
|
||||
|
||||
|
||||
void GeometryIndexSplitter::setTriangleCluster(const TriangleMeshGraph& graph,
|
||||
unsigned int triangle,
|
||||
unsigned int cluster,
|
||||
IndexVector& clusters,
|
||||
IndexSet& cluster_vertices,
|
||||
unsigned int& remaining) {
|
||||
clusters[triangle] = cluster;
|
||||
const Triangle& t = graph.triangle(triangle);
|
||||
cluster_vertices.insert(t.v1());
|
||||
cluster_vertices.insert(t.v2());
|
||||
cluster_vertices.insert(t.v3());
|
||||
remaining --;
|
||||
}
|
||||
|
||||
|
||||
void GeometryIndexSplitter::extract_primitives(const IndexSet& vertices,
|
||||
const osg::DrawElements* elements,
|
||||
IndexVector& indices,
|
||||
unsigned int primitive_size) {
|
||||
for(unsigned int i = 0 ; i < elements->getNumIndices() ; i += primitive_size) {
|
||||
bool is_included = true;
|
||||
for(unsigned int j = 0 ; j < primitive_size ; ++ j) {
|
||||
if(!vertices.count(elements->index(i + j))) {
|
||||
is_included = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_included) {
|
||||
for(unsigned int j = 0 ; j < primitive_size ; ++ j) {
|
||||
indices.push_back(elements->index(i + j));
|
||||
unsigned int GeometryIndexSplitter::findCandidate(IndexSet& triangles, const IndexCache& cache, const TriangleMeshGraph& graph) {
|
||||
// look for unclustered neighboring triangles
|
||||
for(IndexCache::const_reverse_iterator cached = cache.rbegin() ; cached != cache.rend() ; ++ cached) {
|
||||
IndexVector candidates = graph.triangleNeighbors(*cached);
|
||||
for(IndexVector::const_iterator candidate = candidates.begin() ; candidate != candidates.end() ; ++ candidate) {
|
||||
if(triangles.count(*candidate)) {
|
||||
triangles.erase(*candidate);
|
||||
return *candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fallback on any unclustered triangle
|
||||
return getNext(triangles, std::numeric_limits<unsigned int>::max());
|
||||
}
|
||||
|
||||
|
||||
@@ -276,10 +221,3 @@ void GeometryIndexSplitter::setBufferBoundingBox(T* buffer) const {
|
||||
buffer->setUserValue("ufr", ufr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GeometryIndexSplitter::setValidIndices(std::set<unsigned int>& indices, const osg::DrawElements* primitive) const {
|
||||
for(unsigned int j = 0 ; j < primitive->getNumIndices() ; ++ j) {
|
||||
indices.insert(primitive->index(j));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "GeometryUniqueVisitor"
|
||||
#include "glesUtil"
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osgDB/ReaderWriter>
|
||||
@@ -34,8 +35,7 @@ public:
|
||||
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
|
||||
unsigned int count = 0;
|
||||
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target, ++ count) {
|
||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry(*target->getGeometry());
|
||||
geometry->setPrimitiveSetList(morphGeometry.getPrimitiveSetList());
|
||||
glesUtil::TargetGeometry geometry(*target, morphGeometry);
|
||||
std::ostringstream oss;
|
||||
if(geometry->getName().empty()) {
|
||||
oss << "/tmp/noname_" << _processed.size();
|
||||
|
||||
31
src/osgPlugins/gles/GeometryMapper
Normal file
31
src/osgPlugins/gles/GeometryMapper
Normal file
@@ -0,0 +1,31 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab
|
||||
*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commercial and non commercial
|
||||
* applications, as long as this copyright notice is maintained.
|
||||
*
|
||||
* This application 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_MAPPER
|
||||
#define GEOMETRY_MAPPER
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geometry>
|
||||
|
||||
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
|
||||
|
||||
class GeometryMapper {
|
||||
public:
|
||||
|
||||
// map one geometry to a list of geometries
|
||||
// to be used with RemapGeometryVisitor
|
||||
virtual const GeometryList& process(osg::Geometry&) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -16,26 +16,32 @@
|
||||
#include <osg/Node>
|
||||
#include <algorithm> //std::max
|
||||
|
||||
#include "AnimationCleanerVisitor"
|
||||
#include "RigAnimationVisitor"
|
||||
//animation:
|
||||
#include "AABBonBoneVisitor"
|
||||
#include "AnimationCleanerVisitor"
|
||||
#include "DisableAnimationVisitor"
|
||||
#include "LimitMorphTargetCount"
|
||||
#include "MostInfluencedGeometryByBone"
|
||||
#include "RigAnimationVisitor"
|
||||
#include "RigAttributesVisitor"
|
||||
|
||||
// geometry:
|
||||
#include "BindPerVertexVisitor"
|
||||
#include "DetachPrimitiveVisitor"
|
||||
#include "DrawArrayVisitor"
|
||||
#include "GeometrySplitterVisitor"
|
||||
#include "IndexMeshVisitor"
|
||||
#include "PreTransformVisitor"
|
||||
#include "RemapGeometryVisitor"
|
||||
#include "SmoothNormalVisitor"
|
||||
#include "TangentSpaceVisitor"
|
||||
#include "TriangleStripVisitor"
|
||||
#include "UnIndexMeshVisitor"
|
||||
#include "WireframeVisitor"
|
||||
#include "AABBonBoneVisitor"
|
||||
#include "AnimationCleanerVisitor"
|
||||
#include "MostInfluencedGeometryByBone"
|
||||
#include "LimitMorphTargetCount"
|
||||
#include "RigAttributesVisitor"
|
||||
|
||||
#include "GeometryIndexSplitter"
|
||||
#include "GeometryCleaner"
|
||||
|
||||
// debug
|
||||
#include "GeometryInspector"
|
||||
|
||||
|
||||
@@ -165,6 +171,12 @@ protected:
|
||||
node->accept(indexer);
|
||||
}
|
||||
|
||||
void makeCleanGeometry(osg::Node* node) {
|
||||
GeometryCleaner cleaner;
|
||||
RemapGeometryVisitor remapper(cleaner, _exportNonGeometryDrawables);
|
||||
node->accept(remapper);
|
||||
}
|
||||
|
||||
void makeSmoothNormal(osg::Node* node) {
|
||||
SmoothNormalVisitor smoother(osg::PI / 4.f, true);
|
||||
node->accept(smoother);
|
||||
@@ -176,8 +188,9 @@ protected:
|
||||
}
|
||||
|
||||
void makeSplit(osg::Node* node) {
|
||||
GeometrySplitterVisitor splitter(_maxIndexValue, _exportNonGeometryDrawables );
|
||||
node->accept(splitter);
|
||||
GeometryIndexSplitter splitter(_maxIndexValue);
|
||||
RemapGeometryVisitor remapper(splitter, _exportNonGeometryDrawables);
|
||||
node->accept(remapper);
|
||||
}
|
||||
|
||||
void makeTriStrip(osg::Node* node) {
|
||||
|
||||
@@ -26,6 +26,12 @@ osg::Node* OpenGLESGeometryOptimizer::optimize(osg::Node& node) {
|
||||
// index (merge exact duplicates + uses simple triangles & lines i.e. no strip/fan/loop)
|
||||
makeIndexMesh(model.get());
|
||||
|
||||
// clean (remove degenerated data)
|
||||
std::string authoringTool;
|
||||
if(model->getUserValue("authoring_tool", authoringTool) && authoringTool == "Tilt Brush") {
|
||||
makeCleanGeometry(model.get());
|
||||
}
|
||||
|
||||
// smooth vertex normals (if geometry has no normal compute smooth normals)
|
||||
makeSmoothNormal(model.get());
|
||||
|
||||
|
||||
51
src/osgPlugins/gles/RemapGeometryVisitor
Normal file
51
src/osgPlugins/gles/RemapGeometryVisitor
Normal file
@@ -0,0 +1,51 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab
|
||||
*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commercial and non commercial
|
||||
* applications, as long as this copyright notice is maintained.
|
||||
*
|
||||
* This application 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef REMAP_GEOMETRY_VISITOR
|
||||
#define REMAP_GEOMETRY_VISITOR
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geometry>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
|
||||
#include "GeometryUniqueVisitor"
|
||||
#include "GeometryMapper"
|
||||
|
||||
|
||||
class RemapGeometryVisitor : public GeometryUniqueVisitor {
|
||||
public:
|
||||
typedef std::vector< osg::ref_ptr<osg::Geometry> > GeometryList;
|
||||
typedef std::vector< osg::ref_ptr<osg::Drawable> > DrawableList;
|
||||
typedef std::map<osg::Geometry*, GeometryList> GeometryMap;
|
||||
|
||||
RemapGeometryVisitor(GeometryMapper& mapper, bool exportNonGeometryDrawables=false):
|
||||
GeometryUniqueVisitor("RemapGeometryVisitor"),
|
||||
_mapper(mapper),
|
||||
_exportNonGeometryDrawables(exportNonGeometryDrawables)
|
||||
{}
|
||||
|
||||
void apply(osg::Geode&);
|
||||
void process(osg::Geometry&);
|
||||
|
||||
protected:
|
||||
bool isProcessed(osg::Geometry*);
|
||||
void setProcessed(osg::Geometry*, const GeometryList&);
|
||||
|
||||
protected:
|
||||
GeometryMapper& _mapper;
|
||||
std::map<osg::Geometry*, GeometryList> _remap;
|
||||
bool _exportNonGeometryDrawables;
|
||||
};
|
||||
|
||||
#endif
|
||||
72
src/osgPlugins/gles/RemapGeometryVisitor.cpp
Normal file
72
src/osgPlugins/gles/RemapGeometryVisitor.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "RemapGeometryVisitor"
|
||||
#include "glesUtil"
|
||||
|
||||
|
||||
void RemapGeometryVisitor::apply(osg::Geode& geode) {
|
||||
GeometryUniqueVisitor::apply(geode);
|
||||
GeometryList remappedGeometries;
|
||||
DrawableList nonGeometryDrawables;
|
||||
|
||||
for(unsigned int i = 0 ; i < geode.getNumDrawables() ; ++ i) {
|
||||
osg::Geometry* geometry = geode.getDrawable(i)->asGeometry();
|
||||
if(geometry) {
|
||||
if(osgAnimation::RigGeometry* rigGeometry = dynamic_cast<osgAnimation::RigGeometry*>(geometry)) {
|
||||
GeometryMap::iterator lookup = _remap.find(rigGeometry->getSourceGeometry());
|
||||
if(lookup != _remap.end() && !lookup->second.empty()) {
|
||||
|
||||
// convert now static rigGeometry into simple Geometry
|
||||
for(GeometryList::iterator mapped = lookup->second.begin() ; mapped != lookup->second.end() ; ++ mapped) {
|
||||
if(glesUtil::hasPositiveWeights(mapped->get())) {
|
||||
osgAnimation::RigGeometry* mappedRig = new osgAnimation::RigGeometry(*rigGeometry);
|
||||
mappedRig->setSourceGeometry(mapped->get());
|
||||
remappedGeometries.push_back(mappedRig);
|
||||
}
|
||||
else {
|
||||
remappedGeometries.push_back(mapped->get());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
GeometryMap::iterator lookup = _remap.find(geometry);
|
||||
if(lookup != _remap.end() && !lookup->second.empty()) {
|
||||
remappedGeometries.insert(remappedGeometries.end(), lookup->second.begin(), lookup->second.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nonGeometryDrawables.push_back(geode.getDrawable(i));
|
||||
}
|
||||
}
|
||||
|
||||
// remove all drawables
|
||||
geode.removeDrawables(0, geode.getNumDrawables());
|
||||
// insert splitted geometries
|
||||
for(unsigned int i = 0 ; i < remappedGeometries.size() ; ++ i) {
|
||||
geode.addDrawable(remappedGeometries[i].get());
|
||||
}
|
||||
|
||||
if(_exportNonGeometryDrawables) {
|
||||
// insert other drawables (e.g. osgText)
|
||||
for(unsigned int i = 0 ; i < nonGeometryDrawables.size() ; ++ i) {
|
||||
geode.addDrawable(nonGeometryDrawables[i].get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RemapGeometryVisitor::process(osg::Geometry& geometry) {
|
||||
const GeometryList& mapped = _mapper.process(geometry);
|
||||
setProcessed(&geometry, mapped);
|
||||
}
|
||||
|
||||
|
||||
bool RemapGeometryVisitor::isProcessed(osg::Geometry* node) {
|
||||
return _remap.find(node) != _remap.end();
|
||||
}
|
||||
|
||||
|
||||
void RemapGeometryVisitor::setProcessed(osg::Geometry* node, const GeometryList& list) {
|
||||
_remap.insert(std::pair<osg::Geometry*, GeometryList>(node, GeometryList(list)));
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "GeometryUniqueVisitor"
|
||||
#include "TriangleMeshSmoother"
|
||||
#include "glesUtil"
|
||||
|
||||
|
||||
class SmoothNormalVisitor : public GeometryUniqueVisitor {
|
||||
@@ -25,20 +26,41 @@ public:
|
||||
}
|
||||
|
||||
void process(osgAnimation::MorphGeometry& morphGeometry) {
|
||||
TriangleMeshSmoother(morphGeometry, 0, true, TriangleMeshSmoother::smooth_all);
|
||||
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
|
||||
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
|
||||
// check normal orientation using the same primitives as parent geometry
|
||||
osg::Geometry::PrimitiveSetList& primitives = target->getGeometry()->getPrimitiveSetList();
|
||||
target->getGeometry()->setPrimitiveSetList(morphGeometry.getPrimitiveSetList());
|
||||
bool needSmoothing = needMorphGeometrySmoothing(morphGeometry);
|
||||
|
||||
TriangleMeshSmoother(*target->getGeometry(), 0, true, TriangleMeshSmoother::smooth_all);
|
||||
if(needSmoothing) {
|
||||
TriangleMeshSmoother(morphGeometry, 0, true, TriangleMeshSmoother::smooth_all);
|
||||
|
||||
target->getGeometry()->setPrimitiveSetList(primitives);
|
||||
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
|
||||
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
|
||||
// check normal orientation using the same primitives as parent geometry
|
||||
glesUtil::TargetGeometry geometry(*target, morphGeometry);
|
||||
if(geometry && !geometry->getNormalArray()) {
|
||||
TriangleMeshSmoother(*geometry, 0, true, TriangleMeshSmoother::smooth_all);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool needMorphGeometrySmoothing(osgAnimation::MorphGeometry& morphGeometry) {
|
||||
if(!morphGeometry.getNormalArray()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
osgAnimation::MorphGeometry::MorphTargetList targets = morphGeometry.getMorphTargetList();
|
||||
|
||||
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
|
||||
osg::Geometry* geometry = target->getGeometry();
|
||||
if(geometry && !geometry->getNormalArray()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float _creaseAngle;
|
||||
bool _comparePosition;
|
||||
};
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
#include "TangentSpaceVisitor"
|
||||
|
||||
#include "glesUtil"
|
||||
|
||||
void TangentSpaceVisitor::process(osgAnimation::MorphGeometry& morphGeometry) {
|
||||
process(static_cast<osg::Geometry&>(morphGeometry));
|
||||
|
||||
osgAnimation::MorphGeometry::MorphTargetList& targets = morphGeometry.getMorphTargetList();
|
||||
for(osgAnimation::MorphGeometry::MorphTargetList::iterator target = targets.begin() ; target != targets.end() ; ++ target) {
|
||||
osg::Geometry* geometry = target->getGeometry();
|
||||
bool useParentMorphTexCoord = geometry->getTexCoordArrayList().empty();
|
||||
|
||||
if(useParentMorphTexCoord) {
|
||||
// tangent space require tex coords; in case a target has no tex coords, we try to
|
||||
// bind the parent geometry tex coords
|
||||
geometry->setTexCoordArrayList(morphGeometry.getTexCoordArrayList());
|
||||
}
|
||||
|
||||
glesUtil::TargetGeometry geometry(*target, morphGeometry);
|
||||
process(*geometry);
|
||||
|
||||
if(useParentMorphTexCoord) {
|
||||
// drop parent tex coords after tangent space computation
|
||||
geometry->setTexCoordArrayList(osg::Geometry::ArrayList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +23,9 @@ void TangentSpaceVisitor::process(osg::Geometry& geometry) {
|
||||
geometry.getVertexAttribArray(tangentIndex)->setUserValue("tangent", true);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
OSG_WARN << "Anomaly: [TangentSpaceVisitor] Missing tangent array at specificied index." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!geometry.getTexCoordArray(_textureUnit)){
|
||||
@@ -56,21 +46,6 @@ void TangentSpaceVisitor::process(osg::Geometry& geometry) {
|
||||
osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator = new osgUtil::TangentSpaceGenerator;
|
||||
generator->generate(&geometry, _textureUnit);
|
||||
|
||||
// keep original normal array
|
||||
if (!geometry.getNormalArray()) {
|
||||
if (generator->getNormalArray()) {
|
||||
osg::Vec3Array* vec3Normals = new osg::Vec3Array();
|
||||
osg::Vec4Array* vec4Normals = generator->getNormalArray();
|
||||
for (unsigned int i = 0; i < vec4Normals->size(); i++) {
|
||||
osg::Vec3 n = osg::Vec3((*vec4Normals)[i][0],
|
||||
(*vec4Normals)[i][1],
|
||||
(*vec4Normals)[i][2]);
|
||||
vec3Normals->push_back(n);
|
||||
}
|
||||
geometry.setNormalArray(vec3Normals, osg::Array::BIND_PER_VERTEX);
|
||||
}
|
||||
}
|
||||
|
||||
if (generator->getTangentArray()) {
|
||||
osg::Vec4Array* normal = generator->getNormalArray();
|
||||
osg::Vec4Array* tangent = generator->getTangentArray();
|
||||
|
||||
@@ -244,14 +244,16 @@ void TriangleMeshSmoother::updateGeometryPrimitives() {
|
||||
}
|
||||
}
|
||||
|
||||
osg::DrawElementsUInt* triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
|
||||
for(unsigned int i = 0 ; i < _graph->getNumTriangles() ; ++ i) {
|
||||
const Triangle& triangle = _graph->triangle(i);
|
||||
triangles->push_back(triangle.v1());
|
||||
triangles->push_back(triangle.v2());
|
||||
triangles->push_back(triangle.v3());
|
||||
if(_graph->getNumTriangles()) {
|
||||
osg::DrawElementsUInt* triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
|
||||
for(unsigned int i = 0 ; i < _graph->getNumTriangles() ; ++ i) {
|
||||
const Triangle& triangle = _graph->triangle(i);
|
||||
triangles->push_back(triangle.v1());
|
||||
triangles->push_back(triangle.v2());
|
||||
triangles->push_back(triangle.v3());
|
||||
}
|
||||
primitives.push_back(triangles);
|
||||
}
|
||||
primitives.push_back(triangles);
|
||||
|
||||
_geometry.setPrimitiveSetList(primitives);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace glesUtil {
|
||||
using namespace std;
|
||||
using namespace osg;
|
||||
typedef std::vector<unsigned int> IndexList;
|
||||
|
||||
typedef osgAnimation::MorphGeometry::MorphTargetList MorphTargetList;
|
||||
|
||||
inline bool hasPositiveWeights(const osg::Geometry* geometry) {
|
||||
const osg::Vec4Array* weights = 0;
|
||||
@@ -53,6 +53,52 @@ namespace glesUtil {
|
||||
}
|
||||
|
||||
|
||||
class TargetGeometry {
|
||||
public:
|
||||
TargetGeometry(osgAnimation::MorphGeometry::MorphTarget& target,
|
||||
osgAnimation::MorphGeometry& morph):
|
||||
_geometry(0)
|
||||
{
|
||||
_geometry = target.getGeometry();
|
||||
_geometry->setPrimitiveSetList(morph.getPrimitiveSetList());
|
||||
|
||||
_hasTexCoord = _geometry->getTexCoordArrayList().size();
|
||||
if(!_hasTexCoord) {
|
||||
_geometry->setTexCoordArrayList(morph.getTexCoordArrayList());
|
||||
}
|
||||
}
|
||||
|
||||
osg::Geometry* operator->() {
|
||||
return _geometry;
|
||||
}
|
||||
|
||||
operator osg::Geometry*() {
|
||||
return _geometry;
|
||||
}
|
||||
|
||||
operator osg::Geometry&() {
|
||||
return *_geometry;
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return _geometry != 0;
|
||||
}
|
||||
|
||||
~TargetGeometry() {
|
||||
if(!_hasTexCoord) {
|
||||
// drop parent tex coords after tangent space computation
|
||||
_geometry->setTexCoordArrayList(osg::Geometry::ArrayList());
|
||||
}
|
||||
_geometry->setPrimitiveSetList(osg::Geometry::PrimitiveSetList());
|
||||
}
|
||||
|
||||
protected:
|
||||
osg::Geometry* _geometry;
|
||||
bool _hasTexCoord;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// A helper class that gathers up all the attribute arrays of an
|
||||
// osg::Geometry object that are BIND_PER_VERTEX and runs an
|
||||
// ArrayVisitor on them.
|
||||
@@ -61,6 +107,20 @@ namespace glesUtil {
|
||||
typedef std::vector<osg::Array*> ArrayList;
|
||||
|
||||
GeometryArrayGatherer(osg::Geometry& geometry) {
|
||||
addGeometryVertexAttributes(geometry);
|
||||
_targetAttributesIndex = _arrayList.size();
|
||||
|
||||
if(osgAnimation::MorphGeometry* morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(&geometry)) {
|
||||
MorphTargetList targets = morphGeometry->getMorphTargetList();
|
||||
for (MorphTargetList::iterator iterator = targets.begin(); iterator != targets.end(); ++ iterator) {
|
||||
if(iterator->getGeometry()) {
|
||||
addTargetVertexAttributes(*iterator->getGeometry());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addGeometryVertexAttributes(osg::Geometry& geometry) {
|
||||
add(geometry.getVertexArray());
|
||||
add(geometry.getNormalArray());
|
||||
add(geometry.getColorArray());
|
||||
@@ -74,6 +134,10 @@ namespace glesUtil {
|
||||
}
|
||||
}
|
||||
|
||||
void addTargetVertexAttributes(osg::Geometry& target) {
|
||||
add(target.getVertexArray());
|
||||
}
|
||||
|
||||
void add(osg::Array* array) {
|
||||
if (array) {
|
||||
_arrayList.push_back(array);
|
||||
@@ -81,12 +145,16 @@ namespace glesUtil {
|
||||
}
|
||||
|
||||
void accept(osg::ArrayVisitor& av) {
|
||||
for(ArrayList::iterator itr = _arrayList.begin() ; itr != _arrayList.end(); ++ itr) {
|
||||
unsigned int geometryAttributesIndex = 0;
|
||||
for(ArrayList::iterator itr = _arrayList.begin() ;
|
||||
geometryAttributesIndex < _targetAttributesIndex && itr != _arrayList.end();
|
||||
++ geometryAttributesIndex, ++ itr) {
|
||||
(*itr)->accept(av);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList _arrayList;
|
||||
unsigned int _targetAttributesIndex;
|
||||
};
|
||||
|
||||
|
||||
@@ -349,8 +417,8 @@ namespace glesUtil {
|
||||
void remapTargetVertices(Remapper remapper, Geometry& geom)
|
||||
{
|
||||
if(osgAnimation::MorphGeometry *morphGeometry = dynamic_cast<osgAnimation::MorphGeometry*>(&geom)) {
|
||||
osgAnimation::MorphGeometry::MorphTargetList targetList = morphGeometry->getMorphTargetList();
|
||||
for (osgAnimation::MorphGeometry::MorphTargetList::iterator ti = targetList.begin(); ti != targetList.end(); ++ti) {
|
||||
MorphTargetList targetList = morphGeometry->getMorphTargetList();
|
||||
for (MorphTargetList::iterator ti = targetList.begin(); ti != targetList.end(); ++ti) {
|
||||
osgAnimation::MorphGeometry::MorphTarget *morphTarget = &(*ti);
|
||||
osg::Geometry *target = morphTarget->getGeometry();
|
||||
GeometryArrayGatherer gatherer(*target);
|
||||
|
||||
Reference in New Issue
Block a user