Support for BumpMapping added by Marco Jez.
This commit is contained in:
parent
bc14e4ecdc
commit
7575f45800
@ -44,6 +44,9 @@ Package=<4>
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name Core osgUtil
|
||||
End Project Dependency
|
||||
Begin Project Dependency
|
||||
Project_Dep_Name Core osgDB
|
||||
End Project Dependency
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
@ -150,6 +150,10 @@ DEP_CPP_ANISO=\
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgFX\BumpMapping.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgFX\Cartoon.cpp
|
||||
DEP_CPP_CARTO=\
|
||||
"..\..\Include\Osg\Array"\
|
||||
@ -499,6 +503,10 @@ SOURCE=..\..\include\osgFX\AnisotropicLighting
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\osgFX\BumpMapping
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\osgFX\Cartoon
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -154,6 +154,10 @@ DEP_CPP_IO_AN=\
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\src\osgPlugins\osgFX\IO_BumpMapping.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\..\src\osgPlugins\osgFX\IO_Cartoon.cpp
|
||||
DEP_CPP_IO_CA=\
|
||||
"..\..\..\Include\osg\ArgumentParser"\
|
||||
|
198
include/osgFX/BumpMapping
Normal file
198
include/osgFX/BumpMapping
Normal file
@ -0,0 +1,198 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
//osgFX - Copyright (C) 2003 Marco Jez
|
||||
|
||||
#ifndef OSGFX_BUMPMAPPING_
|
||||
#define OSGFX_BUMPMAPPING_
|
||||
|
||||
#include <osgFX/Export>
|
||||
#include <osgFX/Effect>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
namespace osgFX
|
||||
{
|
||||
|
||||
/**
|
||||
This effect makes surfaces appear bumpy. The child node must use two textures,
|
||||
one for diffuse color and one for the normal map (which can be created
|
||||
from a height map with tools like nVIDIA's normal map generator). Furthermore,
|
||||
tangent-space basis vectors must be created and assigned to each Geometry; this
|
||||
can be done quickly by calling BumpMapping::prepareChild(). Note that both
|
||||
diffuse and normal map textures must have corresponding UV maps defined in
|
||||
Geometry objects.
|
||||
This effect defines a preferred technique which uses ARB vertex & fragment
|
||||
programs, and a fallback technique which doesn't use fragment programs. The
|
||||
latter is more limited though since it can't handle ambient and specular
|
||||
components.
|
||||
*/
|
||||
class OSGFX_EXPORT BumpMapping: public Effect {
|
||||
public:
|
||||
BumpMapping();
|
||||
BumpMapping(const BumpMapping ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
|
||||
|
||||
META_Effect(osgFX, BumpMapping,
|
||||
|
||||
"Bump Mapping",
|
||||
|
||||
"This effect makes surfaces appear bumpy. The child node must use two textures, "
|
||||
"one for diffuse color and one for the normal map (which can be created "
|
||||
"from a height map with tools like nVIDIA's normal map generator). Furthermore, "
|
||||
"tangent-space basis vectors must be created and assigned to each Geometry; this "
|
||||
"can be done quickly by calling BumpMapping::prepareChild(). Note that both "
|
||||
"diffuse and normal map textures must have corresponding UV maps defined in "
|
||||
"Geometry objects.\n"
|
||||
"This effect defines a preferred technique which uses ARB vertex & fragment "
|
||||
"programs, and a fallback technique which doesn't use fragment programs. The "
|
||||
"latter is more limited though since it can't handle ambient and specular "
|
||||
"components.",
|
||||
|
||||
"Marco Jez");
|
||||
|
||||
|
||||
/** get the OpenGL light number */
|
||||
inline int getLightNumber() const;
|
||||
|
||||
/** set the OpenGL light number that will be used in lighting computations */
|
||||
inline void setLightNumber(int n);
|
||||
|
||||
/** get the texture unit that contains diffuse color texture. Default is 1 */
|
||||
inline int getDiffuseTextureUnit() const;
|
||||
|
||||
/** set the texture unit that contains diffuse color texture. Default is 1 */
|
||||
inline void setDiffuseTextureUnit(int n);
|
||||
|
||||
/** get the texture unit that contains normal map texture. Default is 0 */
|
||||
inline int getNormalMapTextureUnit() const;
|
||||
|
||||
/** set the texture unit that contains normal map texture. Default is 0 */
|
||||
inline void setNormalMapTextureUnit(int n);
|
||||
|
||||
/** get the diffuse color texture that overrides the child's texture */
|
||||
inline osg::Texture2D *getOverrideDiffuseTexture();
|
||||
|
||||
/** get the const diffuse color texture that overrides the child's texture */
|
||||
inline const osg::Texture2D *getOverrideDiffuseTexture() const;
|
||||
|
||||
/** set the diffuse color texture that overrides the child's texture */
|
||||
inline void setOverrideDiffuseTexture(osg::Texture2D *texture);
|
||||
|
||||
/** get the normal map texture that overrides the child's texture */
|
||||
inline osg::Texture2D *getOverrideNormalMapTexture();
|
||||
|
||||
/** get the const normal map texture that overrides the child's texture */
|
||||
inline const osg::Texture2D *getOverrideNormalMapTexture() const;
|
||||
|
||||
/** set the normal map texture that overrides the child's texture */
|
||||
inline void setOverrideNormalMapTexture(osg::Texture2D *texture);
|
||||
|
||||
/**
|
||||
prepare a Geometry for bump lighting. Tangent-space basis vectors are
|
||||
generated and attached to the geometry as vertex attribute arrays.
|
||||
*/
|
||||
void prepareGeometry(osg::Geometry *geo);
|
||||
|
||||
/** prepare a Node for bump lighting, calling prepareGeometry() for each Geometry */
|
||||
void prepareNode(osg::Node *node);
|
||||
|
||||
/** prepare the current child for bump lighting. Actually calls prepareNode(getChild()) */
|
||||
void prepareChild();
|
||||
|
||||
/** set up a demo environment with predefined diffuse and normal maps, as well as texture coordinates */
|
||||
void setUpDemo();
|
||||
|
||||
protected:
|
||||
virtual ~BumpMapping() {}
|
||||
BumpMapping &operator=(const BumpMapping &) { return *this; }
|
||||
|
||||
bool define_techniques();
|
||||
|
||||
private:
|
||||
int lightnum_;
|
||||
int diffuseunit_;
|
||||
int normalunit_;
|
||||
osg::ref_ptr<osg::Texture2D> diffuse_tex_;
|
||||
osg::ref_ptr<osg::Texture2D> normal_tex_;
|
||||
};
|
||||
|
||||
// INLINE METHODS
|
||||
|
||||
inline int BumpMapping::getLightNumber() const
|
||||
{
|
||||
return lightnum_;
|
||||
}
|
||||
|
||||
inline void BumpMapping::setLightNumber(int n)
|
||||
{
|
||||
lightnum_ = n;
|
||||
dirtyTechniques();
|
||||
}
|
||||
|
||||
inline int BumpMapping::getDiffuseTextureUnit() const
|
||||
{
|
||||
return diffuseunit_;
|
||||
}
|
||||
|
||||
inline void BumpMapping::setDiffuseTextureUnit(int n)
|
||||
{
|
||||
diffuseunit_ = n;
|
||||
dirtyTechniques();
|
||||
}
|
||||
|
||||
inline int BumpMapping::getNormalMapTextureUnit() const
|
||||
{
|
||||
return normalunit_;
|
||||
}
|
||||
|
||||
inline void BumpMapping::setNormalMapTextureUnit(int n)
|
||||
{
|
||||
normalunit_ = n;
|
||||
dirtyTechniques();
|
||||
}
|
||||
|
||||
inline osg::Texture2D *BumpMapping::getOverrideDiffuseTexture()
|
||||
{
|
||||
return diffuse_tex_.get();
|
||||
}
|
||||
|
||||
inline const osg::Texture2D *BumpMapping::getOverrideDiffuseTexture() const
|
||||
{
|
||||
return diffuse_tex_.get();
|
||||
}
|
||||
|
||||
inline void BumpMapping::setOverrideDiffuseTexture(osg::Texture2D *texture)
|
||||
{
|
||||
diffuse_tex_ = texture;
|
||||
dirtyTechniques();
|
||||
}
|
||||
|
||||
inline osg::Texture2D *BumpMapping::getOverrideNormalMapTexture()
|
||||
{
|
||||
return normal_tex_.get();
|
||||
}
|
||||
|
||||
inline const osg::Texture2D *BumpMapping::getOverrideNormalMapTexture() const
|
||||
{
|
||||
return normal_tex_.get();
|
||||
}
|
||||
|
||||
inline void BumpMapping::setOverrideNormalMapTexture(osg::Texture2D *texture)
|
||||
{
|
||||
normal_tex_ = texture;
|
||||
dirtyTechniques();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
635
src/osgFX/BumpMapping.cpp
Normal file
635
src/osgFX/BumpMapping.cpp
Normal file
@ -0,0 +1,635 @@
|
||||
#include <osgFX/BumpMapping>
|
||||
#include <osgFX/Registry>
|
||||
|
||||
#include <osg/VertexProgram>
|
||||
#include <osg/FragmentProgram>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Depth>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexEnvCombine>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Notify>
|
||||
|
||||
#include <osgUtil/TangentSpaceGenerator>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// this is a visitor class that prepares all geometries in a subgraph
|
||||
// by calling prepareGeometry() which in turn generates tangent-space
|
||||
// basis vectors
|
||||
class TsgVisitor: public osg::NodeVisitor {
|
||||
public:
|
||||
TsgVisitor(BumpMapping *bm): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), bm_(bm) {}
|
||||
void apply(osg::Geode &geode)
|
||||
{
|
||||
for (unsigned i=0; i<geode.getNumDrawables(); ++i) {
|
||||
osg::Geometry *geo = dynamic_cast<osg::Geometry *>(geode.getDrawable(i));
|
||||
if (geo) {
|
||||
bm_->prepareGeometry(geo);
|
||||
}
|
||||
}
|
||||
osg::NodeVisitor::apply(geode);
|
||||
}
|
||||
private:
|
||||
osg::ref_ptr<BumpMapping> bm_;
|
||||
};
|
||||
|
||||
|
||||
// this visitor generates texture coordinates for all geometries in a
|
||||
// subgraph. It is used only for demo purposes.
|
||||
class TexCoordGenerator: public osg::NodeVisitor {
|
||||
public:
|
||||
TexCoordGenerator(int du, int nu): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), du_(du), nu_(nu) {}
|
||||
void apply(osg::Geode &geode)
|
||||
{
|
||||
const osg::BoundingSphere &bsphere = geode.getBound();
|
||||
float scale = 10;
|
||||
if (bsphere.radius() != 0) {
|
||||
scale = 5 / bsphere.radius();
|
||||
}
|
||||
for (unsigned i=0; i<geode.getNumDrawables(); ++i) {
|
||||
osg::Geometry *geo = dynamic_cast<osg::Geometry *>(geode.getDrawable(i));
|
||||
if (geo) {
|
||||
osg::ref_ptr<osg::Vec2Array> tc = generate_coords(geo->getVertexArray(), geo->getNormalArray(), scale);
|
||||
geo->setTexCoordArray(du_, tc.get());
|
||||
geo->setTexCoordArray(nu_, tc.get());
|
||||
}
|
||||
}
|
||||
osg::NodeVisitor::apply(geode);
|
||||
}
|
||||
|
||||
protected:
|
||||
osg::Vec2Array *generate_coords(osg::Array *vx, osg::Array *nx, float scale)
|
||||
{
|
||||
osg::Vec2Array *v2a = dynamic_cast<osg::Vec2Array *>(vx);
|
||||
osg::Vec3Array *v3a = dynamic_cast<osg::Vec3Array *>(vx);
|
||||
osg::Vec4Array *v4a = dynamic_cast<osg::Vec4Array *>(vx);
|
||||
osg::Vec2Array *n2a = dynamic_cast<osg::Vec2Array *>(nx);
|
||||
osg::Vec3Array *n3a = dynamic_cast<osg::Vec3Array *>(nx);
|
||||
osg::Vec4Array *n4a = dynamic_cast<osg::Vec4Array *>(nx);
|
||||
|
||||
osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;
|
||||
for (unsigned i=0; i<vx->getNumElements(); ++i) {
|
||||
|
||||
osg::Vec3 P;
|
||||
if (v2a) P.set(v2a->at(i).x(), v2a->at(i).y(), 0);
|
||||
if (v3a) P.set(v3a->at(i).x(), v3a->at(i).y(), v3a->at(i).z());
|
||||
if (v4a) P.set(v4a->at(i).x(), v4a->at(i).y(), v4a->at(i).z());
|
||||
|
||||
osg::Vec3 N(0, 0, 1);
|
||||
if (n2a) N.set(n2a->at(i).x(), n2a->at(i).y(), 0);
|
||||
if (n3a) N.set(n3a->at(i).x(), n3a->at(i).y(), n3a->at(i).z());
|
||||
if (n4a) N.set(n4a->at(i).x(), n4a->at(i).y(), n4a->at(i).z());
|
||||
|
||||
int axis = 0;
|
||||
if (N.y() > N.x() && N.y() > N.z()) axis = 1;
|
||||
if (-N.y() > N.x() && -N.y() > N.z()) axis = 1;
|
||||
if (N.z() > N.x() && N.z() > N.y()) axis = 2;
|
||||
if (-N.z() > N.x() && -N.z() > N.y()) axis = 2;
|
||||
|
||||
osg::Vec2 uv;
|
||||
|
||||
switch (axis) {
|
||||
case 0: uv.set(P.y(), P.z()); break;
|
||||
case 1: uv.set(P.x(), P.z()); break;
|
||||
case 2: uv.set(P.x(), P.y()); break;
|
||||
default: ;
|
||||
}
|
||||
|
||||
tc->push_back(uv * scale);
|
||||
}
|
||||
return tc.take();
|
||||
}
|
||||
|
||||
private:
|
||||
int du_;
|
||||
int nu_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// a state attribute class that grabs the initial inverse view matrix
|
||||
// and sends it to a VertexProgram.
|
||||
// NOTE: due to lack of support for per-context parameters in VertexProgram,
|
||||
// this class will send the matrix to the vp only while the first context
|
||||
// is being rendered. All subsequent contexts will use the first context's
|
||||
// matrix.
|
||||
class ViewMatrixExtractor: public osg::StateAttribute {
|
||||
public:
|
||||
ViewMatrixExtractor()
|
||||
: osg::StateAttribute(),
|
||||
vp_(0),
|
||||
param_(0),
|
||||
first_context_(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ViewMatrixExtractor(const ViewMatrixExtractor ©, const osg::CopyOp ©op)
|
||||
: osg::StateAttribute(copy, copyop),
|
||||
vp_(static_cast<osg::VertexProgram *>(copyop(copy.vp_.get()))),
|
||||
param_(copy.param_),
|
||||
first_context_(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ViewMatrixExtractor(osg::VertexProgram *vp, int param)
|
||||
: osg::StateAttribute(),
|
||||
vp_(vp),
|
||||
param_(param),
|
||||
first_context_(-1)
|
||||
{
|
||||
}
|
||||
|
||||
META_StateAttribute(osgFX, ViewMatrixExtractor, 0x564d4548);
|
||||
|
||||
int compare(const osg::StateAttribute &sa) const
|
||||
{
|
||||
COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa);
|
||||
if (vp_.get() != rhs.vp_.get()) return -1;
|
||||
if (param_ < rhs.param_) return -1;
|
||||
if (param_ > rhs.param_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply(osg::State &state) const
|
||||
{
|
||||
if (first_context_ == -1) {
|
||||
first_context_ = state.getContextID();
|
||||
}
|
||||
if (state.getContextID() == first_context_) {
|
||||
if (vp_.valid()) {
|
||||
osg::Matrix M = state.getInitialInverseViewMatrix();
|
||||
for (int i=0; i<4; ++i) {
|
||||
vp_->setProgramLocalParameter(param_+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable osg::ref_ptr<osg::VertexProgram> vp_;
|
||||
int param_;
|
||||
mutable int first_context_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// let's register this cool effect! :)
|
||||
Registry::Proxy proxy(new BumpMapping);
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// "Full ARB" technique uses ARB vertex program and fragment program.
|
||||
// Handles ambient, diffuse and specular lighting transparently. A texture
|
||||
// for the diffuse component is required as well as a normal map texture.
|
||||
class FullArbTechnique: public Technique {
|
||||
public:
|
||||
|
||||
FullArbTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D *diffuse_tex, osg::Texture2D *normal_tex)
|
||||
: Technique(),
|
||||
lightnum_(lightnum),
|
||||
diffuseunit_(diffuseunit),
|
||||
normalunit_(normalunit),
|
||||
diffuse_tex_(diffuse_tex),
|
||||
normal_tex_(normal_tex)
|
||||
{
|
||||
}
|
||||
|
||||
META_Technique(
|
||||
"FullArbTechnique",
|
||||
"Single-pass technique, requires ARB_vertex_program and ARB_fragment_program."
|
||||
);
|
||||
|
||||
void getRequiredExtensions(std::vector<std::string> &extensions) const
|
||||
{
|
||||
extensions.push_back("GL_ARB_vertex_program");
|
||||
extensions.push_back("GL_ARB_fragment_program");
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
// vertex program
|
||||
std::ostringstream vp_oss;
|
||||
vp_oss <<
|
||||
"!!ARBvp1.0\n"
|
||||
"OPTION ARB_position_invariant;"
|
||||
"PARAM c4 = { 0, 0, 0, 1 };"
|
||||
"PARAM c5 = { 0.5, 4, 0, 0 };"
|
||||
"TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8;"
|
||||
"ATTRIB v5 = vertex.attrib[15];"
|
||||
"ATTRIB v4 = vertex.attrib[7];"
|
||||
"ATTRIB v3 = vertex.attrib[6];"
|
||||
"ATTRIB v25 = vertex.texcoord[1];"
|
||||
"ATTRIB v24 = vertex.texcoord[0];"
|
||||
"ATTRIB v18 = vertex.normal;"
|
||||
"ATTRIB v16 = vertex.position;"
|
||||
"PARAM s259[4] = { state.matrix.mvp };"
|
||||
"PARAM s18 = state.light[0].position;"
|
||||
"PARAM s77 = state.lightprod[0].specular;"
|
||||
"PARAM s4 = state.material.shininess;"
|
||||
"PARAM s75 = state.lightprod[0].ambient;"
|
||||
"PARAM s223[4] = { state.matrix.modelview[0] };"
|
||||
"PARAM c0[4] = { program.local[0..3] };"
|
||||
" MOV result.texcoord[2].xyz, s75.xyzx;"
|
||||
" MOV result.texcoord[2].w, s4.x;"
|
||||
" MOV result.texcoord[0].zw, s77.xyxy;"
|
||||
" MOV result.texcoord[0].xy, v24;"
|
||||
" MOV result.texcoord[1].zw, s77.zwzw;"
|
||||
" MOV result.texcoord[1].xy, v25;"
|
||||
" MOV R5, c0[0];"
|
||||
" MUL R0, R5.y, s223[1];"
|
||||
" MAD R0, R5.x, s223[0], R0;"
|
||||
" MAD R0, R5.z, s223[2], R0;"
|
||||
" MAD R0, R5.w, s223[3], R0;"
|
||||
" DP4 R1.x, R0, v16;"
|
||||
" MOV R4, c0[1];"
|
||||
" MUL R2, R4.y, s223[1];"
|
||||
" MAD R2, R4.x, s223[0], R2;"
|
||||
" MAD R2, R4.z, s223[2], R2;"
|
||||
" MAD R7, R4.w, s223[3], R2;"
|
||||
" DP4 R1.y, R7, v16;"
|
||||
" MOV R3, c0[2];"
|
||||
" MUL R2, R3.y, s223[1];"
|
||||
" MAD R2, R3.x, s223[0], R2;"
|
||||
" MAD R2, R3.z, s223[2], R2;"
|
||||
" MAD R6, R3.w, s223[3], R2;"
|
||||
" DP4 R1.z, R6, v16;"
|
||||
" MOV R2, c0[3];"
|
||||
" MUL R8, R2.y, s223[1];"
|
||||
" MAD R8, R2.x, s223[0], R8;"
|
||||
" MAD R8, R2.z, s223[2], R8;"
|
||||
" MAD R8, R2.w, s223[3], R8;"
|
||||
" MOV R8.x, R5.w;"
|
||||
" MOV R8.y, R4.w;"
|
||||
" MOV R8.z, R3.w;"
|
||||
" ADD R1.yzw, R8.xxyz, -R1.xxyz;"
|
||||
" DP3 R1.x, R1.yzwy, R1.yzwy;"
|
||||
" RSQ R1.x, R1.x;"
|
||||
" DP4 R5.x, R5, s18;"
|
||||
" DP4 R5.y, R4, s18;"
|
||||
" DP4 R5.z, R3, s18;"
|
||||
" DP3 R2.x, R5.xyzx, R5.xyzx;"
|
||||
" RSQ R2.x, R2.x;"
|
||||
" MUL R5.xyz, R2.x, R5.xyzx;"
|
||||
" MAD R1.yzw, R1.x, R1.yyzw, R5.xxyz;"
|
||||
" DP3 R1.x, R1.yzwy, R1.yzwy;"
|
||||
" RSQ R1.x, R1.x;"
|
||||
" MUL R4.xyz, R1.x, R1.yzwy;"
|
||||
" DP3 R3.x, R0.xyzx, v3.xyzx;"
|
||||
" DP3 R3.y, R7.xyzx, v3.xyzx;"
|
||||
" DP3 R3.z, R6.xyzx, v3.xyzx;"
|
||||
" DP3 R8.x, R3.xyzx, R4.xyzx;"
|
||||
" DP3 R2.x, R0.xyzx, v4.xyzx;"
|
||||
" DP3 R2.y, R7.xyzx, v4.xyzx;"
|
||||
" DP3 R2.z, R6.xyzx, v4.xyzx;"
|
||||
" DP3 R8.y, R2.xyzx, R4.xyzx;"
|
||||
" DP3 R1.x, R0.xyzx, v5.xyzx;"
|
||||
" DP3 R1.y, R7.xyzx, v5.xyzx;"
|
||||
" DP3 R1.z, R6.xyzx, v5.xyzx;"
|
||||
" DP3 R8.z, R1.xyzx, R4.xyzx;"
|
||||
" MAD result.color.front.secondary.xyz, c5.x, R8.xyzx, c5.x;"
|
||||
" DP3 R0.y, R0.xyzx, v18.xyzx;"
|
||||
" DP3 R0.z, R7.xyzx, v18.xyzx;"
|
||||
" DP3 R0.w, R6.xyzx, v18.xyzx;"
|
||||
" DP3 R0.x, R0.yzwy, R0.yzwy;"
|
||||
" RSQ R0.x, R0.x;"
|
||||
" MUL R6.xyz, R0.x, R0.yzwy;"
|
||||
" DP3 R0.x, R6.xyzx, R4.xyzx;"
|
||||
" MUL result.color.front.secondary.w, c5.y, R0.x;"
|
||||
" DP3 R0.x, R3.xyzx, R5.xyzx;"
|
||||
" DP3 R0.y, R2.xyzx, R5.xyzx;"
|
||||
" DP3 R0.z, R1.xyzx, R5.xyzx;"
|
||||
" MAD result.color.front.primary.xyz, c5.x, R0.xyzx, c5.x;"
|
||||
" DP3 R0.x, R6.xyzx, R5.xyzx;"
|
||||
" MUL result.color.front.primary.w, c5.y, R0.x;"
|
||||
"END\n";
|
||||
|
||||
// fragment program
|
||||
std::ostringstream fp_oss;
|
||||
fp_oss <<
|
||||
"!!ARBfp1.0\n"
|
||||
"PARAM c0 = {1, 2, 0.5, 0};"
|
||||
"PARAM c1 = {0, 0, 0, 1};"
|
||||
"TEMP R0;"
|
||||
"TEMP R1;"
|
||||
"TEMP R2;"
|
||||
"TEX R0, fragment.texcoord[0], texture[0], 2D;"
|
||||
"TEX R1, fragment.texcoord[1], texture[1], 2D;"
|
||||
"ADD R0, R0, -c0.z;"
|
||||
"MUL R0.xyz, c0.y, R0;"
|
||||
"ADD R2.xyz, fragment.color.primary, -c0.z;"
|
||||
"MUL R2.xyz, c0.y, R2;"
|
||||
"DP3_SAT R0.w, R0, R2;"
|
||||
"ADD R2, fragment.color.secondary, -c0.z;"
|
||||
"MUL R2.xyz, c0.y, R2;"
|
||||
"DP3_SAT R0.x, R0, R2;"
|
||||
"POW R0.x, R0.x, fragment.texcoord[2].w;"
|
||||
"MOV R2.xyz, fragment.texcoord[2].xyyx;"
|
||||
"MOV R2.w, c1.w;"
|
||||
"MOV_SAT R0.y, fragment.color.primary.w;"
|
||||
"MUL R0.w, R0.y, R0.w;"
|
||||
"ADD R2, R2, R0.w;"
|
||||
"MUL R1.xyz, R1, R2;"
|
||||
"MOV_SAT R0.y, fragment.color.secondary.w;"
|
||||
"MUL R0.xyz, R0.y, R0.x;"
|
||||
"MOV R2.xy, fragment.texcoord[1].zwzz;"
|
||||
"MOV R2.z, fragment.texcoord[0].z;"
|
||||
"MUL R2.xyz, R0, R2;"
|
||||
"ADD R2.xyz, R1, R2;"
|
||||
"MOV result.color.xyz, R2;"
|
||||
"MOV result.color.w, c0.x;"
|
||||
"END\n";
|
||||
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
|
||||
vp->setVertexProgram(vp_oss.str());
|
||||
ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::FragmentProgram> fp = new osg::FragmentProgram;
|
||||
fp->setFragmentProgram(fp_oss.str());
|
||||
ss->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
if (diffuse_tex_.valid()) {
|
||||
ss->setTextureAttributeAndModes(diffuseunit_, diffuse_tex_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
if (normal_tex_.valid()) {
|
||||
ss->setTextureAttributeAndModes(normalunit_, normal_tex_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
private:
|
||||
int lightnum_;
|
||||
int diffuseunit_;
|
||||
int normalunit_;
|
||||
osg::ref_ptr<osg::Texture2D> diffuse_tex_;
|
||||
osg::ref_ptr<osg::Texture2D> normal_tex_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// "ARB Vp" technique uses ARB vertex program and DOT3 texture environment.
|
||||
// Ambient and specular components are not handled. A texture for the diffuse
|
||||
// component is required as well as a normal map texture.
|
||||
class ArbVpTechnique: public Technique {
|
||||
public:
|
||||
ArbVpTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D *diffuse_tex, osg::Texture2D *normal_tex)
|
||||
: Technique(),
|
||||
lightnum_(lightnum),
|
||||
diffuseunit_(diffuseunit),
|
||||
normalunit_(normalunit),
|
||||
diffuse_tex_(diffuse_tex),
|
||||
normal_tex_(normal_tex)
|
||||
{
|
||||
}
|
||||
|
||||
META_Technique(
|
||||
"ArbVpTechnique",
|
||||
"Two-passes technique, requires ARB_vertex_program and ARB_texture_env_dot3."
|
||||
"Only diffuse lighting, no ambient, no specularity."
|
||||
);
|
||||
|
||||
void getRequiredExtensions(std::vector<std::string> &extensions) const
|
||||
{
|
||||
extensions.push_back("GL_ARB_vertex_program");
|
||||
extensions.push_back("GL_ARB_texture_env_dot3");
|
||||
}
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
if (diffuseunit_ != (normalunit_ + 1)) {
|
||||
osg::notify(osg::WARN) << "Warning: osgFX::BumpMapping: this technique (ArbVpTechnique) requires that diffuse_unit == (normal_unit + 1). Effect may not show up properly.\n";
|
||||
}
|
||||
|
||||
// first pass, diffuse bump
|
||||
{
|
||||
std::ostringstream vp_oss;
|
||||
vp_oss <<
|
||||
"!!ARBvp1.0\n"
|
||||
"OPTION ARB_position_invariant;"
|
||||
"PARAM c0 = { 0.5, 1, 0, 0 };"
|
||||
"TEMP R0, R1, R2;"
|
||||
"ATTRIB v5 = vertex.attrib[15];"
|
||||
"ATTRIB v4 = vertex.attrib[7];"
|
||||
"ATTRIB v3 = vertex.attrib[6];"
|
||||
"ATTRIB v24 = vertex.texcoord[" << normalunit_ << "];"
|
||||
"ATTRIB v25 = vertex.texcoord[" << diffuseunit_ << "];"
|
||||
"ATTRIB v18 = vertex.normal;"
|
||||
"ATTRIB v16 = vertex.position;"
|
||||
"PARAM s259[4] = { state.matrix.mvp };"
|
||||
"PARAM s18 = state.light[" << lightnum_ << "].position;"
|
||||
"PARAM s223[4] = { state.matrix.modelview[0] };"
|
||||
" MOV result.texcoord[" << diffuseunit_ << "].xy, v25;"
|
||||
" MOV result.texcoord[" << normalunit_ << "].xy, v24;"
|
||||
" DP3 R0.y, s223[0].xyzx, v3.xyzx;"
|
||||
" DP3 R0.z, s223[1].xyzx, v3.xyzx;"
|
||||
" DP3 R0.w, s223[2].xyzx, v3.xyzx;"
|
||||
" DP3 R0.x, s18.xyzx, s18.xyzx;"
|
||||
" RSQ R0.x, R0.x;"
|
||||
" MUL R2.xyz, R0.x, s18.xyzx;"
|
||||
" DP3 R1.x, R0.yzwy, R2.xyzx;"
|
||||
" DP3 R0.x, s223[0].xyzx, v4.xyzx;"
|
||||
" DP3 R0.y, s223[1].xyzx, v4.xyzx;"
|
||||
" DP3 R0.z, s223[2].xyzx, v4.xyzx;"
|
||||
" DP3 R1.y, R0.xyzx, R2.xyzx;"
|
||||
" DP3 R0.x, s223[0].xyzx, v5.xyzx;"
|
||||
" DP3 R0.y, s223[1].xyzx, v5.xyzx;"
|
||||
" DP3 R0.z, s223[2].xyzx, v5.xyzx;"
|
||||
" DP3 R1.z, R0.xyzx, R2.xyzx;"
|
||||
" MAD result.color.front.primary.xyz, c0.x, R1.xyzx, c0.x;"
|
||||
" MOV result.color.front.primary.w, c0.y;"
|
||||
"END\n";
|
||||
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
|
||||
vp->setVertexProgram(vp_oss.str());
|
||||
ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
if (diffuse_tex_.valid()) {
|
||||
ss->setTextureAttributeAndModes(diffuseunit_, diffuse_tex_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
if (normal_tex_.valid()) {
|
||||
ss->setTextureAttributeAndModes(normalunit_, normal_tex_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::TexEnvCombine> tec = new osg::TexEnvCombine;
|
||||
tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
|
||||
tec->setSource0_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
|
||||
tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
|
||||
ss->setTextureAttributeAndModes(normalunit_, tec.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::TexEnv> te = new osg::TexEnv;
|
||||
te->setMode(osg::TexEnv::MODULATE);
|
||||
ss->setTextureAttributeAndModes(diffuseunit_, te.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
// second pass, self-shadowing
|
||||
{
|
||||
std::ostringstream vp_oss;
|
||||
vp_oss <<
|
||||
"!!ARBvp1.0\n"
|
||||
"OPTION ARB_position_invariant;"
|
||||
"PARAM c0 = { 8, 0, 1, 0 };"
|
||||
"TEMP R0;"
|
||||
"ATTRIB v18 = vertex.normal;"
|
||||
"ATTRIB v16 = vertex.position;"
|
||||
"PARAM s259[4] = { state.matrix.mvp };"
|
||||
"PARAM s18 = state.light[" << lightnum_ << "].position;"
|
||||
"PARAM s631[4] = { state.matrix.modelview[0].invtrans };"
|
||||
" DP4 R0.x, s631[0], v18;"
|
||||
" DP4 R0.y, s631[1], v18;"
|
||||
" DP4 R0.z, s631[2], v18;"
|
||||
" DP3 R0.x, R0.xyzx, s18.xyzx;"
|
||||
" MAX R0.x, R0.x, c0.y;"
|
||||
" MUL R0.x, c0.x, R0.x;"
|
||||
" MIN result.color.front.primary.xyz, R0.x, c0.z;"
|
||||
" MOV result.color.front.primary.w, c0.z;"
|
||||
"END\n";
|
||||
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
|
||||
depth->setFunction(osg::Depth::EQUAL);
|
||||
ss->setAttributeAndModes(depth.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
|
||||
vp->setVertexProgram(vp_oss.str());
|
||||
ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
|
||||
bf->setFunction(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
|
||||
ss->setAttributeAndModes(bf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setTextureMode(diffuseunit_, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
ss->setTextureMode(normalunit_, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int lightnum_;
|
||||
int diffuseunit_;
|
||||
int normalunit_;
|
||||
osg::ref_ptr<osg::Texture2D> diffuse_tex_;
|
||||
osg::ref_ptr<osg::Texture2D> normal_tex_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
BumpMapping::BumpMapping()
|
||||
: Effect(),
|
||||
lightnum_(0),
|
||||
diffuseunit_(1),
|
||||
normalunit_(0)
|
||||
{
|
||||
}
|
||||
|
||||
BumpMapping::BumpMapping(const BumpMapping ©, const osg::CopyOp ©op)
|
||||
: Effect(copy, copyop),
|
||||
lightnum_(copy.lightnum_),
|
||||
diffuseunit_(copy.diffuseunit_),
|
||||
normalunit_(copy.normalunit_),
|
||||
diffuse_tex_(static_cast<osg::Texture2D *>(copyop(copy.diffuse_tex_.get()))),
|
||||
normal_tex_(static_cast<osg::Texture2D *>(copyop(copy.normal_tex_.get())))
|
||||
{
|
||||
}
|
||||
|
||||
bool BumpMapping::define_techniques()
|
||||
{
|
||||
addTechnique(new FullArbTechnique(lightnum_, diffuseunit_, normalunit_, diffuse_tex_.get(), normal_tex_.get()));
|
||||
addTechnique(new ArbVpTechnique(lightnum_, diffuseunit_, normalunit_, diffuse_tex_.get(), normal_tex_.get()));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BumpMapping::prepareGeometry(osg::Geometry *geo)
|
||||
{
|
||||
osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
|
||||
tsg->generate(geo, normalunit_);
|
||||
if (!geo->getVertexAttribArray(6))
|
||||
geo->setVertexAttribArray(6, false, tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX);
|
||||
if (!geo->getVertexAttribArray(7))
|
||||
geo->setVertexAttribArray(7, false, tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX);
|
||||
if (!geo->getVertexAttribArray(15))
|
||||
geo->setVertexAttribArray(15, false, tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX);
|
||||
}
|
||||
|
||||
void BumpMapping::prepareNode(osg::Node *node)
|
||||
{
|
||||
TsgVisitor tv(this);
|
||||
node->accept(tv);
|
||||
}
|
||||
|
||||
void BumpMapping::prepareChild()
|
||||
{
|
||||
if (getChild())
|
||||
prepareNode(getChild());
|
||||
}
|
||||
|
||||
void BumpMapping::setUpDemo()
|
||||
{
|
||||
// generate texture coordinates
|
||||
TexCoordGenerator tcg(diffuseunit_, normalunit_);
|
||||
getChild()->accept(tcg);
|
||||
|
||||
// set up diffuse texture
|
||||
if (!diffuse_tex_.valid()) {
|
||||
diffuse_tex_ = new osg::Texture2D;
|
||||
diffuse_tex_->setImage(osgDB::readImageFile("whitemetal_diffuse.jpg"));
|
||||
diffuse_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
||||
diffuse_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
diffuse_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||
diffuse_tex_->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
||||
diffuse_tex_->setMaxAnisotropy(8);
|
||||
}
|
||||
|
||||
// set up normal map texture
|
||||
if (!normal_tex_.valid()) {
|
||||
normal_tex_ = new osg::Texture2D;
|
||||
normal_tex_->setImage(osgDB::readImageFile("whitemetal_normal.jpg"));
|
||||
normal_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
||||
normal_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||
normal_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||
normal_tex_->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
||||
normal_tex_->setMaxAnisotropy(8);
|
||||
}
|
||||
|
||||
// generate tangent-space basis vector
|
||||
prepareChild();
|
||||
|
||||
// recreate techniques on next step
|
||||
dirtyTechniques();
|
||||
}
|
@ -3,6 +3,7 @@ include $(TOPDIR)/Make/makedefs
|
||||
|
||||
CXXFILES =\
|
||||
AnisotropicLighting.cpp\
|
||||
BumpMapping.cpp\
|
||||
Cartoon.cpp\
|
||||
Effect.cpp\
|
||||
Registry.cpp\
|
||||
|
@ -3,6 +3,7 @@ include $(TOPDIR)/Make/makedefs
|
||||
|
||||
CXXFILES =\
|
||||
IO_AnisotropicLighting.cpp\
|
||||
IO_BumpMapping.cpp\
|
||||
IO_Cartoon.cpp\
|
||||
IO_Scribe.cpp\
|
||||
IO_SpecularHighlights.cpp\
|
||||
|
83
src/osgPlugins/osgFX/IO_BumpMapping.cpp
Normal file
83
src/osgPlugins/osgFX/IO_BumpMapping.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include <osgFX/BumpMapping>
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/Input>
|
||||
#include <osgDB/Output>
|
||||
|
||||
bool BumpMapping_readLocalData(osg::Object &obj, osgDB::Input &fr);
|
||||
bool BumpMapping_writeLocalData(const osg::Object &obj, osgDB::Output &fw);
|
||||
|
||||
osgDB::RegisterDotOsgWrapperProxy BumpMapping_Proxy
|
||||
(
|
||||
new osgFX::BumpMapping,
|
||||
"osgFX::BumpMapping",
|
||||
"Object Node osgFX::Effect osgFX::BumpMapping",
|
||||
BumpMapping_readLocalData,
|
||||
BumpMapping_writeLocalData
|
||||
);
|
||||
|
||||
bool BumpMapping_readLocalData(osg::Object &obj, osgDB::Input &fr)
|
||||
{
|
||||
osgFX::BumpMapping &myobj = static_cast<osgFX::BumpMapping &>(obj);
|
||||
bool itAdvanced = false;
|
||||
|
||||
if (fr[0].matchWord("lightNumber")) {
|
||||
int n;
|
||||
if (fr[1].getInt(n)) {
|
||||
myobj.setLightNumber(n);
|
||||
fr += 2;
|
||||
itAdvanced = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fr[0].matchWord("diffuseUnit")) {
|
||||
int n;
|
||||
if (fr[1].getInt(n)) {
|
||||
myobj.setDiffuseTextureUnit(n);
|
||||
fr += 2;
|
||||
itAdvanced = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fr[0].matchWord("normalMapUnit")) {
|
||||
int n;
|
||||
if (fr[1].getInt(n)) {
|
||||
myobj.setNormalMapTextureUnit(n);
|
||||
fr += 2;
|
||||
itAdvanced = true;
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> diffuse_tex = static_cast<osg::Texture2D *>(fr.readObjectOfType(osgDB::type_wrapper<osg::Texture2D>()));
|
||||
if (diffuse_tex.valid()) {
|
||||
myobj.setOverrideDiffuseTexture(diffuse_tex.get());
|
||||
itAdvanced = true;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> normal_tex = static_cast<osg::Texture2D *>(fr.readObjectOfType(osgDB::type_wrapper<osg::Texture2D>()));
|
||||
if (normal_tex.valid()) {
|
||||
myobj.setOverrideDiffuseTexture(normal_tex.get());
|
||||
itAdvanced = true;
|
||||
}
|
||||
|
||||
return itAdvanced;
|
||||
}
|
||||
|
||||
bool BumpMapping_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
|
||||
{
|
||||
const osgFX::BumpMapping &myobj = static_cast<const osgFX::BumpMapping &>(obj);
|
||||
|
||||
fw.indent() << "lightNumber " << myobj.getLightNumber() << "\n";
|
||||
fw.indent() << "diffuseUnit " << myobj.getDiffuseTextureUnit() << "\n";
|
||||
fw.indent() << "normalMapUnit " << myobj.getNormalMapTextureUnit() << "\n";
|
||||
|
||||
if (myobj.getOverrideDiffuseTexture()) {
|
||||
fw.writeObject(*myobj.getOverrideDiffuseTexture());
|
||||
}
|
||||
|
||||
if (myobj.getOverrideNormalMapTexture()) {
|
||||
fw.writeObject(*myobj.getOverrideNormalMapTexture());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -35,36 +35,67 @@ void TangentSpaceGenerator::generate(osg::Geometry *geo, int normal_map_tex_unit
|
||||
|
||||
unsigned i; // VC6 doesn't like for-scoped variables
|
||||
|
||||
for (i=0; i<geo->getNumPrimitiveSets(); ++i) {
|
||||
osg::PrimitiveSet *pset = geo->getPrimitiveSet(i);
|
||||
for (unsigned pri=0; pri<geo->getNumPrimitiveSets(); ++pri) {
|
||||
osg::PrimitiveSet *pset = geo->getPrimitiveSet(pri);
|
||||
|
||||
unsigned N = pset->getNumIndices();
|
||||
|
||||
switch (pset->getMode()) {
|
||||
|
||||
case osg::PrimitiveSet::TRIANGLES:
|
||||
for (i=0; i<pset->getNumIndices(); i+=3) {
|
||||
for (i=0; i<N; i+=3) {
|
||||
compute_basis_vectors(pset, vx, tx, i, i+1, i+2);
|
||||
}
|
||||
break;
|
||||
|
||||
case osg::PrimitiveSet::QUADS:
|
||||
for (i=0; i<N; i+=4) {
|
||||
compute_basis_vectors(pset, vx, tx, i, i+1, i+2);
|
||||
compute_basis_vectors(pset, vx, tx, i+2, i+3, i);
|
||||
}
|
||||
break;
|
||||
|
||||
case osg::PrimitiveSet::TRIANGLE_STRIP:
|
||||
for (i=0; i<pset->getNumIndices()-2; ++i) {
|
||||
if (pset->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
|
||||
osg::DrawArrayLengths *dal = static_cast<osg::DrawArrayLengths *>(pset);
|
||||
unsigned j = 0;
|
||||
for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) {
|
||||
unsigned iN = static_cast<unsigned>(*pi-2);
|
||||
for (i=0; i<iN; ++i, ++j) {
|
||||
if ((i%2) == 0) {
|
||||
compute_basis_vectors(pset, vx, tx, j, j+1, j+2);
|
||||
} else {
|
||||
compute_basis_vectors(pset, vx, tx, j+1, j, j+2);
|
||||
}
|
||||
}
|
||||
j += 2;
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<N-2; ++i) {
|
||||
if ((i%2) == 0) {
|
||||
compute_basis_vectors(pset, vx, tx, i, i+1, i+2);
|
||||
} else {
|
||||
compute_basis_vectors(pset, vx, tx, i, i+2, i+1);
|
||||
compute_basis_vectors(pset, vx, tx, i+1, i, i+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case osg::PrimitiveSet::TRIANGLE_FAN:
|
||||
for (i=2; i<pset->getNumIndices(); ++i) {
|
||||
compute_basis_vectors(pset, vx, tx, 0, i-1, i);
|
||||
if (pset->getType() == osg::PrimitiveSet::DrawArrayLengthsPrimitiveType) {
|
||||
osg::DrawArrayLengths *dal = static_cast<osg::DrawArrayLengths *>(pset);
|
||||
unsigned j = 0;
|
||||
for (osg::DrawArrayLengths::const_iterator pi=dal->begin(); pi!=dal->end(); ++pi) {
|
||||
unsigned iN = static_cast<unsigned>(*pi-2);
|
||||
for (i=0; i<iN; ++i) {
|
||||
compute_basis_vectors(pset, vx, tx, 0, j+1, j+2);
|
||||
}
|
||||
j += 2;
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<N-2; ++i) {
|
||||
compute_basis_vectors(pset, vx, tx, 2, i+1, i+2);
|
||||
}
|
||||
break;
|
||||
|
||||
case osg::PrimitiveSet::QUADS:
|
||||
for (i=0; i<pset->getNumIndices(); i+=4) {
|
||||
compute_basis_vectors(pset, vx, tx, i, i+1, i+2);
|
||||
compute_basis_vectors(pset, vx, tx, i+2, i+3, i);
|
||||
}
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user