| 1 | #include <osgFX/BumpMapping> |
|---|
| 2 | #include <osgFX/Registry> |
|---|
| 3 | |
|---|
| 4 | #include <osg/VertexProgram> |
|---|
| 5 | #include <osg/FragmentProgram> |
|---|
| 6 | #include <osg/Texture2D> |
|---|
| 7 | #include <osg/Depth> |
|---|
| 8 | #include <osg/TexEnv> |
|---|
| 9 | #include <osg/TexEnvCombine> |
|---|
| 10 | #include <osg/BlendFunc> |
|---|
| 11 | #include <osg/Geometry> |
|---|
| 12 | #include <osg/Notify> |
|---|
| 13 | |
|---|
| 14 | #include <osgUtil/TangentSpaceGenerator> |
|---|
| 15 | |
|---|
| 16 | #include <osgDB/ReadFile> |
|---|
| 17 | |
|---|
| 18 | #include <sstream> |
|---|
| 19 | |
|---|
| 20 | using namespace osgFX; |
|---|
| 21 | |
|---|
| 22 | namespace |
|---|
| 23 | { |
|---|
| 24 | |
|---|
| 25 | using osg::NodeVisitor; |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | class TsgVisitor: public NodeVisitor { |
|---|
| 31 | public: |
|---|
| 32 | TsgVisitor(BumpMapping* bm): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), _bm(bm) {} |
|---|
| 33 | |
|---|
| 34 | META_NodeVisitor("osgFX","TsgVisitor") |
|---|
| 35 | |
|---|
| 36 | void apply(osg::Geode& geode) |
|---|
| 37 | { |
|---|
| 38 | for (unsigned i=0; i<geode.getNumDrawables(); ++i) { |
|---|
| 39 | osg::Geometry* geo = dynamic_cast<osg::Geometry* >(geode.getDrawable(i)); |
|---|
| 40 | if (geo) { |
|---|
| 41 | _bm->prepareGeometry(geo); |
|---|
| 42 | } |
|---|
| 43 | } |
|---|
| 44 | NodeVisitor::apply(geode); |
|---|
| 45 | } |
|---|
| 46 | private: |
|---|
| 47 | BumpMapping* _bm; |
|---|
| 48 | }; |
|---|
| 49 | |
|---|
| 50 | |
|---|
| 51 | |
|---|
| 52 | |
|---|
| 53 | class TexCoordGenerator: public osg::NodeVisitor { |
|---|
| 54 | public: |
|---|
| 55 | TexCoordGenerator(int du, int nu): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), du_(du), nu_(nu) {} |
|---|
| 56 | |
|---|
| 57 | META_NodeVisitor("osgFX","TexCoordGenerator") |
|---|
| 58 | |
|---|
| 59 | void apply(osg::Geode& geode) |
|---|
| 60 | { |
|---|
| 61 | const osg::BoundingSphere &bsphere = geode.getBound(); |
|---|
| 62 | float scale = 10; |
|---|
| 63 | if (bsphere.radius() != 0) { |
|---|
| 64 | scale = 5 / bsphere.radius(); |
|---|
| 65 | } |
|---|
| 66 | for (unsigned i=0; i<geode.getNumDrawables(); ++i) { |
|---|
| 67 | osg::Geometry* geo = dynamic_cast<osg::Geometry* >(geode.getDrawable(i)); |
|---|
| 68 | if (geo) { |
|---|
| 69 | osg::ref_ptr<osg::Vec2Array> tc = generate_coords(geo->getVertexArray(), geo->getNormalArray(), scale); |
|---|
| 70 | geo->setTexCoordArray(du_, tc.get()); |
|---|
| 71 | geo->setTexCoordArray(nu_, tc.get()); |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | NodeVisitor::apply(geode); |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | protected: |
|---|
| 78 | osg::Vec2Array* generate_coords(osg::Array* vx, osg::Array* nx, float scale) |
|---|
| 79 | { |
|---|
| 80 | osg::Vec2Array* v2a = dynamic_cast<osg::Vec2Array*>(vx); |
|---|
| 81 | osg::Vec3Array* v3a = dynamic_cast<osg::Vec3Array*>(vx); |
|---|
| 82 | osg::Vec4Array* v4a = dynamic_cast<osg::Vec4Array*>(vx); |
|---|
| 83 | osg::Vec2Array* n2a = dynamic_cast<osg::Vec2Array*>(nx); |
|---|
| 84 | osg::Vec3Array* n3a = dynamic_cast<osg::Vec3Array*>(nx); |
|---|
| 85 | osg::Vec4Array* n4a = dynamic_cast<osg::Vec4Array*>(nx); |
|---|
| 86 | |
|---|
| 87 | osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array; |
|---|
| 88 | for (unsigned i=0; i<vx->getNumElements(); ++i) { |
|---|
| 89 | |
|---|
| 90 | osg::Vec3 P; |
|---|
| 91 | if (v2a) P.set((*v2a)[i].x(), (*v2a)[i].y(), 0); |
|---|
| 92 | if (v3a) P.set((*v3a)[i].x(), (*v3a)[i].y(), (*v3a)[i].z()); |
|---|
| 93 | if (v4a) P.set((*v4a)[i].x(), (*v4a)[i].y(), (*v4a)[i].z()); |
|---|
| 94 | |
|---|
| 95 | osg::Vec3 N(0, 0, 1); |
|---|
| 96 | if (n2a) N.set((*n2a)[i].x(), (*n2a)[i].y(), 0); |
|---|
| 97 | if (n3a) N.set((*n3a)[i].x(), (*n3a)[i].y(), (*n3a)[i].z()); |
|---|
| 98 | if (n4a) N.set((*n4a)[i].x(), (*n4a)[i].y(), (*n4a)[i].z()); |
|---|
| 99 | |
|---|
| 100 | int axis = 0; |
|---|
| 101 | if (N.y() > N.x() && N.y() > N.z()) axis = 1; |
|---|
| 102 | if (-N.y() > N.x() && -N.y() > N.z()) axis = 1; |
|---|
| 103 | if (N.z() > N.x() && N.z() > N.y()) axis = 2; |
|---|
| 104 | if (-N.z() > N.x() && -N.z() > N.y()) axis = 2; |
|---|
| 105 | |
|---|
| 106 | osg::Vec2 uv; |
|---|
| 107 | |
|---|
| 108 | switch (axis) { |
|---|
| 109 | case 0: uv.set(P.y(), P.z()); break; |
|---|
| 110 | case 1: uv.set(P.x(), P.z()); break; |
|---|
| 111 | case 2: uv.set(P.x(), P.y()); break; |
|---|
| 112 | default: ; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | tc->push_back(uv * scale); |
|---|
| 116 | } |
|---|
| 117 | return tc.release(); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | private: |
|---|
| 121 | int du_; |
|---|
| 122 | int nu_; |
|---|
| 123 | }; |
|---|
| 124 | |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | namespace |
|---|
| 128 | { |
|---|
| 129 | |
|---|
| 130 | const unsigned int NO_VALID_CONTEXT = 0xffffffff; |
|---|
| 131 | |
|---|
| 132 | |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | |
|---|
| 138 | class ViewMatrixExtractor: public osg::StateAttribute { |
|---|
| 139 | public: |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | ViewMatrixExtractor() |
|---|
| 143 | : osg::StateAttribute(), |
|---|
| 144 | _vp(0), |
|---|
| 145 | _param(0), |
|---|
| 146 | _first_context(NO_VALID_CONTEXT) |
|---|
| 147 | { |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | ViewMatrixExtractor(const ViewMatrixExtractor& copy, const osg::CopyOp& copyop) |
|---|
| 151 | : osg::StateAttribute(copy, copyop), |
|---|
| 152 | _vp(static_cast<osg::VertexProgram* >(copyop(copy._vp.get()))), |
|---|
| 153 | _param(copy._param), |
|---|
| 154 | _first_context(NO_VALID_CONTEXT) |
|---|
| 155 | { |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | ViewMatrixExtractor(osg::VertexProgram* vp, int param) |
|---|
| 159 | : osg::StateAttribute(), |
|---|
| 160 | _vp(vp), |
|---|
| 161 | _param(param), |
|---|
| 162 | _first_context(NO_VALID_CONTEXT) |
|---|
| 163 | { |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | META_StateAttribute(osgFX, ViewMatrixExtractor, VIEWMATRIXEXTRACTOR); |
|---|
| 167 | |
|---|
| 168 | int compare(const osg::StateAttribute& sa) const |
|---|
| 169 | { |
|---|
| 170 | COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa); |
|---|
| 171 | if (_vp.get() != rhs._vp.get()) return -1; |
|---|
| 172 | if (_param < rhs._param) return -1; |
|---|
| 173 | if (_param > rhs._param) return 1; |
|---|
| 174 | return 0; |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | void apply(osg::State& state) const |
|---|
| 178 | { |
|---|
| 179 | if (_first_context == NO_VALID_CONTEXT) { |
|---|
| 180 | _first_context = state.getContextID(); |
|---|
| 181 | } |
|---|
| 182 | if (state.getContextID() == _first_context) { |
|---|
| 183 | if (_vp.valid()) { |
|---|
| 184 | osg::Matrix M = state.getInitialInverseViewMatrix(); |
|---|
| 185 | for (int i=0; i<4; ++i) { |
|---|
| 186 | _vp->setProgramLocalParameter(_param+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i))); |
|---|
| 187 | } |
|---|
| 188 | } |
|---|
| 189 | } |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | private: |
|---|
| 193 | mutable osg::ref_ptr<osg::VertexProgram> _vp; |
|---|
| 194 | int _param; |
|---|
| 195 | mutable unsigned int _first_context; |
|---|
| 196 | }; |
|---|
| 197 | |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | |
|---|
| 201 | namespace |
|---|
| 202 | { |
|---|
| 203 | |
|---|
| 204 | Registry::Proxy proxy(new BumpMapping); |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | |
|---|
| 208 | namespace |
|---|
| 209 | { |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | |
|---|
| 213 | |
|---|
| 214 | class FullArbTechnique: public Technique { |
|---|
| 215 | public: |
|---|
| 216 | |
|---|
| 217 | FullArbTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex) |
|---|
| 218 | : Technique(), |
|---|
| 219 | _lightnum(lightnum), |
|---|
| 220 | _diffuse_unit(diffuseunit), |
|---|
| 221 | _normal_unit(normalunit), |
|---|
| 222 | _diffuse_tex(diffuse_tex), |
|---|
| 223 | _normal_tex(normal_tex) |
|---|
| 224 | { |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | META_Technique( |
|---|
| 228 | "FullArbTechnique", |
|---|
| 229 | "Single-pass technique, requires ARB_vertex_program and ARB_fragment_program." |
|---|
| 230 | ); |
|---|
| 231 | |
|---|
| 232 | void getRequiredExtensions(std::vector<std::string>& extensions) const |
|---|
| 233 | { |
|---|
| 234 | extensions.push_back("GL_ARB_vertex_program"); |
|---|
| 235 | extensions.push_back("GL_ARB_fragment_program"); |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | protected: |
|---|
| 239 | |
|---|
| 240 | void define_passes() |
|---|
| 241 | { |
|---|
| 242 | int freeunit; |
|---|
| 243 | for (freeunit=0; freeunit==_diffuse_unit||freeunit==_normal_unit; ++freeunit) {} |
|---|
| 244 | |
|---|
| 245 | |
|---|
| 246 | std::ostringstream vp_oss; |
|---|
| 247 | vp_oss << |
|---|
| 248 | "!!ARBvp1.0\n" |
|---|
| 249 | "OPTION ARB_position_invariant;" |
|---|
| 250 | "PARAM c4 = { 0, 0, 0, 1 };" |
|---|
| 251 | "PARAM c5 = { 0.5, 4, 0, 0 };" |
|---|
| 252 | "TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8;" |
|---|
| 253 | "ATTRIB v5 = vertex.attrib[15];" |
|---|
| 254 | "ATTRIB v4 = vertex.attrib[7];" |
|---|
| 255 | "ATTRIB v3 = vertex.attrib[6];" |
|---|
| 256 | "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];" |
|---|
| 257 | "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];" |
|---|
| 258 | "ATTRIB v18 = vertex.normal;" |
|---|
| 259 | "ATTRIB v16 = vertex.position;" |
|---|
| 260 | "PARAM s259[4] = { state.matrix.mvp };" |
|---|
| 261 | "PARAM s18 = state.light[0].position;" |
|---|
| 262 | "PARAM s77 = state.lightprod[0].specular;" |
|---|
| 263 | "PARAM s4 = state.material.shininess;" |
|---|
| 264 | "PARAM s75 = state.lightprod[0].ambient;" |
|---|
| 265 | "PARAM s223[4] = { state.matrix.modelview };" |
|---|
| 266 | "PARAM c0[4] = { program.local[0..3] };" |
|---|
| 267 | " MOV result.texcoord[" << freeunit << "].xyz, s75.xyzx;" |
|---|
| 268 | " MOV result.texcoord[" << freeunit << "].w, s4.x;" |
|---|
| 269 | " MOV result.texcoord[" << _normal_unit << "].zw, s77.zwzw;" |
|---|
| 270 | " MOV result.texcoord[" << _normal_unit << "].xy, v24;" |
|---|
| 271 | " MOV result.texcoord[" << _diffuse_unit << "].zw, s77.xyxy;" |
|---|
| 272 | " MOV result.texcoord[" << _diffuse_unit << "].xy, v25;" |
|---|
| 273 | " MOV R5, c0[0];" |
|---|
| 274 | " MUL R0, R5.y, s223[1];" |
|---|
| 275 | " MAD R0, R5.x, s223[0], R0;" |
|---|
| 276 | " MAD R0, R5.z, s223[2], R0;" |
|---|
| 277 | " MAD R0, R5.w, s223[3], R0;" |
|---|
| 278 | " DP4 R1.x, R0, v16;" |
|---|
| 279 | " MOV R4, c0[1];" |
|---|
| 280 | " MUL R2, R4.y, s223[1];" |
|---|
| 281 | " MAD R2, R4.x, s223[0], R2;" |
|---|
| 282 | " MAD R2, R4.z, s223[2], R2;" |
|---|
| 283 | " MAD R7, R4.w, s223[3], R2;" |
|---|
| 284 | " DP4 R1.y, R7, v16;" |
|---|
| 285 | " MOV R3, c0[2];" |
|---|
| 286 | " MUL R2, R3.y, s223[1];" |
|---|
| 287 | " MAD R2, R3.x, s223[0], R2;" |
|---|
| 288 | " MAD R2, R3.z, s223[2], R2;" |
|---|
| 289 | " MAD R6, R3.w, s223[3], R2;" |
|---|
| 290 | " DP4 R1.z, R6, v16;" |
|---|
| 291 | " MOV R2, c0[3];" |
|---|
| 292 | " MUL R8, R2.y, s223[1];" |
|---|
| 293 | " MAD R8, R2.x, s223[0], R8;" |
|---|
| 294 | " MAD R8, R2.z, s223[2], R8;" |
|---|
| 295 | " MAD R8, R2.w, s223[3], R8;" |
|---|
| 296 | " MOV R8.x, R5.w;" |
|---|
| 297 | " MOV R8.y, R4.w;" |
|---|
| 298 | " MOV R8.z, R3.w;" |
|---|
| 299 | " ADD R1.yzw, R8.xxyz, -R1.xxyz;" |
|---|
| 300 | " DP3 R1.x, R1.yzwy, R1.yzwy;" |
|---|
| 301 | " RSQ R1.x, R1.x;" |
|---|
| 302 | " DP4 R5.x, R5, s18;" |
|---|
| 303 | " DP4 R5.y, R4, s18;" |
|---|
| 304 | " DP4 R5.z, R3, s18;" |
|---|
| 305 | " DP3 R2.x, R5.xyzx, R5.xyzx;" |
|---|
| 306 | " RSQ R2.x, R2.x;" |
|---|
| 307 | " MUL R5.xyz, R2.x, R5.xyzx;" |
|---|
| 308 | " MAD R1.yzw, R1.x, R1.yyzw, R5.xxyz;" |
|---|
| 309 | " DP3 R1.x, R1.yzwy, R1.yzwy;" |
|---|
| 310 | " RSQ R1.x, R1.x;" |
|---|
| 311 | " MUL R4.xyz, R1.x, R1.yzwy;" |
|---|
| 312 | " DP3 R3.x, R0.xyzx, v3.xyzx;" |
|---|
| 313 | " DP3 R3.y, R7.xyzx, v3.xyzx;" |
|---|
| 314 | " DP3 R3.z, R6.xyzx, v3.xyzx;" |
|---|
| 315 | " DP3 R8.x, R3.xyzx, R4.xyzx;" |
|---|
| 316 | " DP3 R2.x, R0.xyzx, v4.xyzx;" |
|---|
| 317 | " DP3 R2.y, R7.xyzx, v4.xyzx;" |
|---|
| 318 | " DP3 R2.z, R6.xyzx, v4.xyzx;" |
|---|
| 319 | " DP3 R8.y, R2.xyzx, R4.xyzx;" |
|---|
| 320 | " DP3 R1.x, R0.xyzx, v5.xyzx;" |
|---|
| 321 | " DP3 R1.y, R7.xyzx, v5.xyzx;" |
|---|
| 322 | " DP3 R1.z, R6.xyzx, v5.xyzx;" |
|---|
| 323 | " DP3 R8.z, R1.xyzx, R4.xyzx;" |
|---|
| 324 | " MAD result.color.front.secondary.xyz, c5.x, R8.xyzx, c5.x;" |
|---|
| 325 | " DP3 R0.y, R0.xyzx, v18.xyzx;" |
|---|
| 326 | " DP3 R0.z, R7.xyzx, v18.xyzx;" |
|---|
| 327 | " DP3 R0.w, R6.xyzx, v18.xyzx;" |
|---|
| 328 | " DP3 R0.x, R0.yzwy, R0.yzwy;" |
|---|
| 329 | " RSQ R0.x, R0.x;" |
|---|
| 330 | " MUL R6.xyz, R0.x, R0.yzwy;" |
|---|
| 331 | " DP3 R0.x, R6.xyzx, R4.xyzx;" |
|---|
| 332 | " MUL result.color.front.secondary.w, c5.y, R0.x;" |
|---|
| 333 | " DP3 R0.x, R3.xyzx, R5.xyzx;" |
|---|
| 334 | " DP3 R0.y, R2.xyzx, R5.xyzx;" |
|---|
| 335 | " DP3 R0.z, R1.xyzx, R5.xyzx;" |
|---|
| 336 | " MAD result.color.front.primary.xyz, c5.x, R0.xyzx, c5.x;" |
|---|
| 337 | " DP3 R0.x, R6.xyzx, R5.xyzx;" |
|---|
| 338 | " MUL result.color.front.primary.w, c5.y, R0.x;" |
|---|
| 339 | "END\n"; |
|---|
| 340 | |
|---|
| 341 | |
|---|
| 342 | std::ostringstream fp_oss; |
|---|
| 343 | fp_oss << |
|---|
| 344 | "!!ARBfp1.0\n" |
|---|
| 345 | "PARAM c0 = {1, 2, 0.5, 0};" |
|---|
| 346 | "PARAM c1 = {0, 0, 0, 1};" |
|---|
| 347 | "TEMP R0;" |
|---|
| 348 | "TEMP R1;" |
|---|
| 349 | "TEMP R2;" |
|---|
| 350 | "TEX R0, fragment.texcoord[" << _normal_unit << "], texture[" << _normal_unit << "], 2D;" |
|---|
| 351 | "TEX R1, fragment.texcoord[" << _diffuse_unit << "], texture[" << _diffuse_unit << "], 2D;" |
|---|
| 352 | "ADD R0, R0, -c0.z;" |
|---|
| 353 | "MUL R0.xyz, c0.y, R0;" |
|---|
| 354 | "ADD R2.xyz, fragment.color.primary, -c0.z;" |
|---|
| 355 | "MUL R2.xyz, c0.y, R2;" |
|---|
| 356 | "DP3_SAT R0.w, R0, R2;" |
|---|
| 357 | "ADD R2, fragment.color.secondary, -c0.z;" |
|---|
| 358 | "MUL R2.xyz, c0.y, R2;" |
|---|
| 359 | "DP3_SAT R0.x, R0, R2;" |
|---|
| 360 | "POW R0.x, R0.x, fragment.texcoord[" << freeunit << "].w;" |
|---|
| 361 | "MOV R2.xyz, fragment.texcoord[" << freeunit << "].xyyx;" |
|---|
| 362 | "MOV R2.w, c1.w;" |
|---|
| 363 | "MOV_SAT R0.y, fragment.color.primary.w;" |
|---|
| 364 | "MUL R0.w, R0.y, R0.w;" |
|---|
| 365 | "ADD R2, R2, R0.w;" |
|---|
| 366 | "MUL R1.xyz, R1, R2;" |
|---|
| 367 | "MOV_SAT R0.y, fragment.color.secondary.w;" |
|---|
| 368 | "MUL R0.xyz, R0.y, R0.x;" |
|---|
| 369 | "MOV R2.xy, fragment.texcoord[" << _diffuse_unit << "].zwzz;" |
|---|
| 370 | "MOV R2.z, fragment.texcoord[" << _normal_unit << "].z;" |
|---|
| 371 | "MUL R2.xyz, R0, R2;" |
|---|
| 372 | "ADD R2.xyz, R1, R2;" |
|---|
| 373 | "MOV result.color.xyz, R2;" |
|---|
| 374 | "MOV result.color.w, c0.x;" |
|---|
| 375 | "END\n"; |
|---|
| 376 | |
|---|
| 377 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 378 | |
|---|
| 379 | osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram; |
|---|
| 380 | vp->setVertexProgram(vp_oss.str()); |
|---|
| 381 | ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 382 | |
|---|
| 383 | osg::ref_ptr<osg::FragmentProgram> fp = new osg::FragmentProgram; |
|---|
| 384 | fp->setFragmentProgram(fp_oss.str()); |
|---|
| 385 | ss->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 386 | |
|---|
| 387 | ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 388 | |
|---|
| 389 | if (_diffuse_tex.valid()) { |
|---|
| 390 | ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 391 | } |
|---|
| 392 | |
|---|
| 393 | if (_normal_tex.valid()) { |
|---|
| 394 | ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 395 | } |
|---|
| 396 | |
|---|
| 397 | addPass(ss.get()); |
|---|
| 398 | } |
|---|
| 399 | |
|---|
| 400 | private: |
|---|
| 401 | int _lightnum; |
|---|
| 402 | int _diffuse_unit; |
|---|
| 403 | int _normal_unit; |
|---|
| 404 | osg::ref_ptr<osg::Texture2D> _diffuse_tex; |
|---|
| 405 | osg::ref_ptr<osg::Texture2D> _normal_tex; |
|---|
| 406 | }; |
|---|
| 407 | |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | namespace |
|---|
| 411 | { |
|---|
| 412 | |
|---|
| 413 | |
|---|
| 414 | |
|---|
| 415 | |
|---|
| 416 | class ArbVpTechnique: public Technique { |
|---|
| 417 | public: |
|---|
| 418 | ArbVpTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex) |
|---|
| 419 | : Technique(), |
|---|
| 420 | _lightnum(lightnum), |
|---|
| 421 | _diffuse_unit(diffuseunit), |
|---|
| 422 | _normal_unit(normalunit), |
|---|
| 423 | _diffuse_tex(diffuse_tex), |
|---|
| 424 | _normal_tex(normal_tex) |
|---|
| 425 | { |
|---|
| 426 | } |
|---|
| 427 | |
|---|
| 428 | META_Technique( |
|---|
| 429 | "ArbVpTechnique", |
|---|
| 430 | "Two-passes technique, requires ARB_vertex_program and ARB__textureenv_dot3." |
|---|
| 431 | "Only diffuse lighting, no ambient, no specularity." |
|---|
| 432 | ); |
|---|
| 433 | |
|---|
| 434 | void getRequiredExtensions(std::vector<std::string>& extensions) const |
|---|
| 435 | { |
|---|
| 436 | extensions.push_back("GL_ARB_vertex_program"); |
|---|
| 437 | extensions.push_back("GL_ARB_texture_env_dot3"); |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | void define_passes() |
|---|
| 441 | { |
|---|
| 442 | if (_diffuse_unit != (_normal_unit + 1)) { |
|---|
| 443 | OSG_WARN << "Warning: osgFX::BumpMapping: this technique (ArbVpTechnique) requires that _diffuse_unit == (_normal_unit + 1). Effect may not show up properly.\n"; |
|---|
| 444 | } |
|---|
| 445 | |
|---|
| 446 | |
|---|
| 447 | { |
|---|
| 448 | std::ostringstream vp_oss; |
|---|
| 449 | vp_oss << |
|---|
| 450 | "!!ARBvp1.0\n" |
|---|
| 451 | "OPTION ARB_position_invariant;" |
|---|
| 452 | "PARAM c0 = { 0.5, 1, 0, 0 };" |
|---|
| 453 | "TEMP R0, R1, R2;" |
|---|
| 454 | "ATTRIB v5 = vertex.attrib[15];" |
|---|
| 455 | "ATTRIB v4 = vertex.attrib[7];" |
|---|
| 456 | "ATTRIB v3 = vertex.attrib[6];" |
|---|
| 457 | "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];" |
|---|
| 458 | "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];" |
|---|
| 459 | "ATTRIB v18 = vertex.normal;" |
|---|
| 460 | "ATTRIB v16 = vertex.position;" |
|---|
| 461 | "PARAM s259[4] = { state.matrix.mvp };" |
|---|
| 462 | "PARAM s18 = state.light[" << _lightnum << "].position;" |
|---|
| 463 | "PARAM s223[4] = { state.matrix.modelview };" |
|---|
| 464 | " MOV result.texcoord[" << _diffuse_unit << "].xy, v25;" |
|---|
| 465 | " MOV result.texcoord[" << _normal_unit << "].xy, v24;" |
|---|
| 466 | " DP3 R0.y, s223[0].xyzx, v3.xyzx;" |
|---|
| 467 | " DP3 R0.z, s223[1].xyzx, v3.xyzx;" |
|---|
| 468 | " DP3 R0.w, s223[2].xyzx, v3.xyzx;" |
|---|
| 469 | " DP3 R0.x, s18.xyzx, s18.xyzx;" |
|---|
| 470 | " RSQ R0.x, R0.x;" |
|---|
| 471 | " MUL R2.xyz, R0.x, s18.xyzx;" |
|---|
| 472 | " DP3 R1.x, R0.yzwy, R2.xyzx;" |
|---|
| 473 | " DP3 R0.x, s223[0].xyzx, v4.xyzx;" |
|---|
| 474 | " DP3 R0.y, s223[1].xyzx, v4.xyzx;" |
|---|
| 475 | " DP3 R0.z, s223[2].xyzx, v4.xyzx;" |
|---|
| 476 | " DP3 R1.y, R0.xyzx, R2.xyzx;" |
|---|
| 477 | " DP3 R0.x, s223[0].xyzx, v5.xyzx;" |
|---|
| 478 | " DP3 R0.y, s223[1].xyzx, v5.xyzx;" |
|---|
| 479 | " DP3 R0.z, s223[2].xyzx, v5.xyzx;" |
|---|
| 480 | " DP3 R1.z, R0.xyzx, R2.xyzx;" |
|---|
| 481 | " MAD result.color.front.primary.xyz, c0.x, R1.xyzx, c0.x;" |
|---|
| 482 | " MOV result.color.front.primary.w, c0.y;" |
|---|
| 483 | "END\n"; |
|---|
| 484 | |
|---|
| 485 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 486 | |
|---|
| 487 | osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram; |
|---|
| 488 | vp->setVertexProgram(vp_oss.str()); |
|---|
| 489 | ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 490 | |
|---|
| 491 | if (_diffuse_tex.valid()) { |
|---|
| 492 | ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 493 | } |
|---|
| 494 | |
|---|
| 495 | if (_normal_tex.valid()) { |
|---|
| 496 | ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 497 | } |
|---|
| 498 | |
|---|
| 499 | osg::ref_ptr<osg::TexEnvCombine> tec = new osg::TexEnvCombine; |
|---|
| 500 | tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB); |
|---|
| 501 | tec->setSource0_RGB(osg::TexEnvCombine::PRIMARY_COLOR); |
|---|
| 502 | tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE); |
|---|
| 503 | ss->setTextureAttributeAndModes(_normal_unit, tec.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 504 | |
|---|
| 505 | osg::ref_ptr<osg::TexEnv> te = new osg::TexEnv; |
|---|
| 506 | te->setMode(osg::TexEnv::MODULATE); |
|---|
| 507 | ss->setTextureAttributeAndModes(_diffuse_unit, te.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 508 | |
|---|
| 509 | addPass(ss.get()); |
|---|
| 510 | } |
|---|
| 511 | |
|---|
| 512 | |
|---|
| 513 | bool selfShadowing = false; |
|---|
| 514 | if (selfShadowing) |
|---|
| 515 | { |
|---|
| 516 | std::ostringstream vp_oss; |
|---|
| 517 | vp_oss << |
|---|
| 518 | "!!ARBvp1.0\n" |
|---|
| 519 | "OPTION ARB_position_invariant;" |
|---|
| 520 | "PARAM c0 = { 8, 0, 1, 0 };" |
|---|
| 521 | "TEMP R0;" |
|---|
| 522 | "ATTRIB v18 = vertex.normal;" |
|---|
| 523 | "ATTRIB v16 = vertex.position;" |
|---|
| 524 | "PARAM s259[4] = { state.matrix.mvp };" |
|---|
| 525 | "PARAM s18 = state.light[" << _lightnum << "].position;" |
|---|
| 526 | "PARAM s631[4] = { state.matrix.modelview.invtrans };" |
|---|
| 527 | " DP4 R0.x, s631[0], v18;" |
|---|
| 528 | " DP4 R0.y, s631[1], v18;" |
|---|
| 529 | " DP4 R0.z, s631[2], v18;" |
|---|
| 530 | " DP3 R0.x, R0.xyzx, s18.xyzx;" |
|---|
| 531 | " MAX R0.x, R0.x, c0.y;" |
|---|
| 532 | " MUL R0.x, c0.x, R0.x;" |
|---|
| 533 | " MIN result.color.front.primary.xyz, R0.x, c0.z;" |
|---|
| 534 | " MOV result.color.front.primary.w, c0.z;" |
|---|
| 535 | "END\n"; |
|---|
| 536 | |
|---|
| 537 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 538 | |
|---|
| 539 | osg::ref_ptr<osg::Depth> depth = new osg::Depth; |
|---|
| 540 | depth->setFunction(osg::Depth::EQUAL); |
|---|
| 541 | ss->setAttributeAndModes(depth.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 542 | |
|---|
| 543 | osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram; |
|---|
| 544 | vp->setVertexProgram(vp_oss.str()); |
|---|
| 545 | ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 546 | |
|---|
| 547 | osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc; |
|---|
| 548 | bf->setFunction(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO); |
|---|
| 549 | ss->setAttributeAndModes(bf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 550 | |
|---|
| 551 | ss->setTextureMode(_diffuse_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 552 | ss->setTextureMode(_normal_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 553 | |
|---|
| 554 | addPass(ss.get()); |
|---|
| 555 | } |
|---|
| 556 | |
|---|
| 557 | } |
|---|
| 558 | |
|---|
| 559 | protected: |
|---|
| 560 | int _lightnum; |
|---|
| 561 | int _diffuse_unit; |
|---|
| 562 | int _normal_unit; |
|---|
| 563 | osg::ref_ptr<osg::Texture2D> _diffuse_tex; |
|---|
| 564 | osg::ref_ptr<osg::Texture2D> _normal_tex; |
|---|
| 565 | }; |
|---|
| 566 | |
|---|
| 567 | } |
|---|
| 568 | |
|---|
| 569 | |
|---|
| 570 | BumpMapping::BumpMapping() |
|---|
| 571 | : Effect(), |
|---|
| 572 | _lightnum(0), |
|---|
| 573 | _diffuse_unit(1), |
|---|
| 574 | _normal_unit(0) |
|---|
| 575 | { |
|---|
| 576 | } |
|---|
| 577 | |
|---|
| 578 | BumpMapping::BumpMapping(const BumpMapping& copy, const osg::CopyOp& copyop) |
|---|
| 579 | : Effect(copy, copyop), |
|---|
| 580 | _lightnum(copy._lightnum), |
|---|
| 581 | _diffuse_unit(copy._diffuse_unit), |
|---|
| 582 | _normal_unit(copy._normal_unit), |
|---|
| 583 | _diffuse_tex(static_cast<osg::Texture2D* >(copyop(copy._diffuse_tex.get()))), |
|---|
| 584 | _normal_tex(static_cast<osg::Texture2D* >(copyop(copy._normal_tex.get()))) |
|---|
| 585 | { |
|---|
| 586 | } |
|---|
| 587 | |
|---|
| 588 | bool BumpMapping::define_techniques() |
|---|
| 589 | { |
|---|
| 590 | addTechnique(new FullArbTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get())); |
|---|
| 591 | addTechnique(new ArbVpTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get())); |
|---|
| 592 | return true; |
|---|
| 593 | } |
|---|
| 594 | |
|---|
| 595 | void BumpMapping::prepareGeometry(osg::Geometry* geo) |
|---|
| 596 | { |
|---|
| 597 | osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator; |
|---|
| 598 | tsg->generate(geo, _normal_unit); |
|---|
| 599 | if (!geo->getVertexAttribArray(6)) |
|---|
| 600 | geo->setVertexAttribData(6, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); |
|---|
| 601 | if (!geo->getVertexAttribArray(7)) |
|---|
| 602 | geo->setVertexAttribData(7, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX, GL_FALSE)); |
|---|
| 603 | if (!geo->getVertexAttribArray(15)) |
|---|
| 604 | geo->setVertexAttribData(15, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX, GL_FALSE)); |
|---|
| 605 | } |
|---|
| 606 | |
|---|
| 607 | void BumpMapping::prepareNode(osg::Node* node) |
|---|
| 608 | { |
|---|
| 609 | osg::ref_ptr<TsgVisitor> tv = new TsgVisitor(this); |
|---|
| 610 | node->accept(*tv.get()); |
|---|
| 611 | } |
|---|
| 612 | |
|---|
| 613 | void BumpMapping::prepareChildren() |
|---|
| 614 | { |
|---|
| 615 | for (unsigned i=0; i<getNumChildren(); ++i) |
|---|
| 616 | prepareNode(getChild(i)); |
|---|
| 617 | } |
|---|
| 618 | |
|---|
| 619 | void BumpMapping::setUpDemo() |
|---|
| 620 | { |
|---|
| 621 | |
|---|
| 622 | TexCoordGenerator tcg(_diffuse_unit, _normal_unit); |
|---|
| 623 | for (unsigned i=0; i<getNumChildren(); ++i) |
|---|
| 624 | getChild(i)->accept(tcg); |
|---|
| 625 | |
|---|
| 626 | |
|---|
| 627 | if (!_diffuse_tex.valid()) { |
|---|
| 628 | _diffuse_tex = new osg::Texture2D; |
|---|
| 629 | _diffuse_tex->setImage(osgDB::readImageFile("Images/whitemetal_diffuse.jpg")); |
|---|
| 630 | _diffuse_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); |
|---|
| 631 | _diffuse_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); |
|---|
| 632 | _diffuse_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); |
|---|
| 633 | _diffuse_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); |
|---|
| 634 | _diffuse_tex->setMaxAnisotropy(8); |
|---|
| 635 | } |
|---|
| 636 | |
|---|
| 637 | |
|---|
| 638 | if (!_normal_tex.valid()) { |
|---|
| 639 | _normal_tex = new osg::Texture2D; |
|---|
| 640 | _normal_tex->setImage(osgDB::readImageFile("Images/whitemetal_normal.jpg")); |
|---|
| 641 | _normal_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); |
|---|
| 642 | _normal_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); |
|---|
| 643 | _normal_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); |
|---|
| 644 | _normal_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); |
|---|
| 645 | _normal_tex->setMaxAnisotropy(8); |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | |
|---|
| 649 | prepareChildren(); |
|---|
| 650 | |
|---|
| 651 | |
|---|
| 652 | dirtyTechniques(); |
|---|
| 653 | } |
|---|