| 1 | #include <osgFX/AnisotropicLighting> |
|---|
| 2 | #include <osgFX/Registry> |
|---|
| 3 | |
|---|
| 4 | #include <osg/VertexProgram> |
|---|
| 5 | #include <osg/Texture2D> |
|---|
| 6 | #include <osg/TexEnv> |
|---|
| 7 | |
|---|
| 8 | #include <osgDB/ReadFile> |
|---|
| 9 | |
|---|
| 10 | #include <sstream> |
|---|
| 11 | |
|---|
| 12 | using namespace osgFX; |
|---|
| 13 | |
|---|
| 14 | namespace |
|---|
| 15 | { |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | class ViewMatrixExtractor: public osg::StateAttribute { |
|---|
| 24 | public: |
|---|
| 25 | ViewMatrixExtractor() |
|---|
| 26 | : osg::StateAttribute(), |
|---|
| 27 | _vp(0), |
|---|
| 28 | _param(0), |
|---|
| 29 | _first_context(-1) |
|---|
| 30 | { |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | ViewMatrixExtractor(const ViewMatrixExtractor& copy, const osg::CopyOp& copyop) |
|---|
| 34 | : osg::StateAttribute(copy, copyop), |
|---|
| 35 | _vp(static_cast<osg::VertexProgram *>(copyop(copy._vp.get()))), |
|---|
| 36 | _param(copy._param), |
|---|
| 37 | _first_context(-1) |
|---|
| 38 | { |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | ViewMatrixExtractor(osg::VertexProgram *vp, int param) |
|---|
| 42 | : osg::StateAttribute(), |
|---|
| 43 | _vp(vp), |
|---|
| 44 | _param(param), |
|---|
| 45 | _first_context(-1) |
|---|
| 46 | { |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | META_StateAttribute(osgFX, ViewMatrixExtractor, VIEWMATRIXEXTRACTOR); |
|---|
| 50 | |
|---|
| 51 | int compare(const osg::StateAttribute &sa) const |
|---|
| 52 | { |
|---|
| 53 | COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa); |
|---|
| 54 | if (_vp.get() != rhs._vp.get()) return -1; |
|---|
| 55 | if (_param < rhs._param) return -1; |
|---|
| 56 | if (_param > rhs._param) return 1; |
|---|
| 57 | return 0; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | void apply(osg::State& state) const |
|---|
| 61 | { |
|---|
| 62 | if (_first_context == -1) { |
|---|
| 63 | _first_context = state.getContextID(); |
|---|
| 64 | } |
|---|
| 65 | if (state.getContextID() == (unsigned int)_first_context) { |
|---|
| 66 | if (_vp.valid()) { |
|---|
| 67 | osg::Matrix M = state.getInitialInverseViewMatrix(); |
|---|
| 68 | for (int i=0; i<4; ++i) { |
|---|
| 69 | _vp->setProgramLocalParameter(_param+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i))); |
|---|
| 70 | } |
|---|
| 71 | } |
|---|
| 72 | } |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | private: |
|---|
| 76 | mutable osg::ref_ptr<osg::VertexProgram> _vp; |
|---|
| 77 | int _param; |
|---|
| 78 | mutable int _first_context; |
|---|
| 79 | }; |
|---|
| 80 | |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | namespace |
|---|
| 84 | { |
|---|
| 85 | |
|---|
| 86 | osg::Image* create_default_image() |
|---|
| 87 | { |
|---|
| 88 | const int _texturesize = 16; |
|---|
| 89 | osg::ref_ptr<osg::Image> image = new osg::Image; |
|---|
| 90 | image->setImage(_texturesize, _texturesize, 1, 3, GL_RGB, GL_UNSIGNED_BYTE, new unsigned char[3*_texturesize*_texturesize], osg::Image::USE_NEW_DELETE); |
|---|
| 91 | for (int i=0; i<_texturesize; ++i) { |
|---|
| 92 | for (int j=0; j<_texturesize; ++j) { |
|---|
| 93 | float s = static_cast<float>(j) / (_texturesize-1); |
|---|
| 94 | float t = static_cast<float>(i) / (_texturesize-1); |
|---|
| 95 | float lum = t * 0.75f; |
|---|
| 96 | float red = lum + 0.2f * powf(cosf(s*10), 3.0f); |
|---|
| 97 | float green = lum; |
|---|
| 98 | float blue = lum + 0.2f * powf(sinf(s*10), 3.0f); |
|---|
| 99 | if (red > 1) red = 1; |
|---|
| 100 | if (red < 0) red = 0; |
|---|
| 101 | if (blue > 1) blue = 1; |
|---|
| 102 | if (blue < 0) blue = 0; |
|---|
| 103 | *(image->data(j, i)+0) = static_cast<unsigned char>(red * 255); |
|---|
| 104 | *(image->data(j, i)+1) = static_cast<unsigned char>(green * 255); |
|---|
| 105 | *(image->data(j, i)+2) = static_cast<unsigned char>(blue * 255); |
|---|
| 106 | } |
|---|
| 107 | } |
|---|
| 108 | return image.release(); |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | namespace |
|---|
| 114 | { |
|---|
| 115 | |
|---|
| 116 | Registry::Proxy proxy(new AnisotropicLighting); |
|---|
| 117 | |
|---|
| 118 | class DefaultTechnique: public Technique { |
|---|
| 119 | public: |
|---|
| 120 | |
|---|
| 121 | DefaultTechnique(int lightnum, osg::Texture2D *texture) |
|---|
| 122 | : Technique(), |
|---|
| 123 | _lightnum(lightnum), |
|---|
| 124 | _texture(texture) |
|---|
| 125 | { |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | void getRequiredExtensions(std::vector<std::string>& extensions) const |
|---|
| 129 | { |
|---|
| 130 | extensions.push_back("GL_ARB_vertex_program"); |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | protected: |
|---|
| 134 | |
|---|
| 135 | void define_passes() |
|---|
| 136 | { |
|---|
| 137 | std::ostringstream vp_oss; |
|---|
| 138 | vp_oss << |
|---|
| 139 | "!!ARBvp1.0\n" |
|---|
| 140 | "PARAM c5 = { 0, 0, 0, 1 };" |
|---|
| 141 | "PARAM c4 = { 0, 0, 0, 0 };" |
|---|
| 142 | "TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8, R9;" |
|---|
| 143 | "ATTRIB v18 = vertex.normal;" |
|---|
| 144 | "ATTRIB v16 = vertex.position;" |
|---|
| 145 | "PARAM s259[4] = { state.matrix.mvp };" |
|---|
| 146 | "PARAM s18 = state.light[" << _lightnum << "].position;" |
|---|
| 147 | "PARAM s223[4] = { state.matrix.modelview };" |
|---|
| 148 | "PARAM c0[4] = { program.local[0..3] };" |
|---|
| 149 | " DP4 result.position.x, s259[0], v16;" |
|---|
| 150 | " DP4 result.position.y, s259[1], v16;" |
|---|
| 151 | " DP4 result.position.z, s259[2], v16;" |
|---|
| 152 | " DP4 result.position.w, s259[3], v16;" |
|---|
| 153 | " MOV R9, c0[0];" |
|---|
| 154 | " MUL R0, R9.y, s223[1];" |
|---|
| 155 | " MAD R0, R9.x, s223[0], R0;" |
|---|
| 156 | " MAD R0, R9.z, s223[2], R0;" |
|---|
| 157 | " MAD R8, R9.w, s223[3], R0;" |
|---|
| 158 | " DP4 R0.x, R8, v16;" |
|---|
| 159 | " MOV R7, c0[1];" |
|---|
| 160 | " MUL R1, R7.y, s223[1];" |
|---|
| 161 | " MAD R1, R7.x, s223[0], R1;" |
|---|
| 162 | " MAD R1, R7.z, s223[2], R1;" |
|---|
| 163 | " MAD R6, R7.w, s223[3], R1;" |
|---|
| 164 | " DP4 R0.y, R6, v16;" |
|---|
| 165 | " MOV R5, c0[2];" |
|---|
| 166 | " MUL R1, R5.y, s223[1];" |
|---|
| 167 | " MAD R1, R5.x, s223[0], R1;" |
|---|
| 168 | " MAD R1, R5.z, s223[2], R1;" |
|---|
| 169 | " MAD R4, R5.w, s223[3], R1;" |
|---|
| 170 | " DP4 R0.z, R4, v16;" |
|---|
| 171 | " MOV R3, c0[3];" |
|---|
| 172 | " MUL R1, R3.y, s223[1];" |
|---|
| 173 | " MAD R1, R3.x, s223[0], R1;" |
|---|
| 174 | " MAD R1, R3.z, s223[2], R1;" |
|---|
| 175 | " MAD R1, R3.w, s223[3], R1;" |
|---|
| 176 | " DP4 R0.w, R1, v16;" |
|---|
| 177 | " MOV R1.x, R9.w;" |
|---|
| 178 | " MOV R1.y, R7.w;" |
|---|
| 179 | " MOV R1.z, R5.w;" |
|---|
| 180 | " MOV R1.w, R3.w;" |
|---|
| 181 | " ADD R2, R1, -R0;" |
|---|
| 182 | " DP4 R0.x, R2, R2;" |
|---|
| 183 | " RSQ R1.x, R0.x;" |
|---|
| 184 | " DP4 R0.x, R9, s18;" |
|---|
| 185 | " DP4 R0.y, R7, s18;" |
|---|
| 186 | " DP4 R0.z, R5, s18;" |
|---|
| 187 | " DP4 R0.w, R3, s18;" |
|---|
| 188 | " DP4 R1.y, R0, R0;" |
|---|
| 189 | " RSQ R1.y, R1.y;" |
|---|
| 190 | " MUL R3, R1.y, R0;" |
|---|
| 191 | " MAD R2, R1.x, R2, R3;" |
|---|
| 192 | " DP4 R1.x, R2, R2;" |
|---|
| 193 | " RSQ R1.x, R1.x;" |
|---|
| 194 | " MUL R1, R1.x, R2;" |
|---|
| 195 | " DP3 R2.x, R8.xyzx, v18.xyzx;" |
|---|
| 196 | " DP3 R2.y, R6.xyzx, v18.xyzx;" |
|---|
| 197 | " DP3 R2.z, R4.xyzx, v18.xyzx;" |
|---|
| 198 | " MOV R2.w, c4.x;" |
|---|
| 199 | " DP4 R1.x, R1, R2;" |
|---|
| 200 | " MAX result.texcoord[0].x, R1.x, c4.x;" |
|---|
| 201 | " DP4 R0.x, R0, R2;" |
|---|
| 202 | " MAX result.texcoord[0].y, R0.x, c4.x;" |
|---|
| 203 | "END\n"; |
|---|
| 204 | |
|---|
| 205 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 206 | |
|---|
| 207 | osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram; |
|---|
| 208 | vp->setVertexProgram(vp_oss.str()); |
|---|
| 209 | ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 210 | |
|---|
| 211 | ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 212 | |
|---|
| 213 | ss->setTextureAttributeAndModes(0, _texture.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 214 | |
|---|
| 215 | osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv; |
|---|
| 216 | texenv->setMode(osg::TexEnv::DECAL); |
|---|
| 217 | ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 218 | |
|---|
| 219 | #if !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GL3_AVAILABLE) |
|---|
| 220 | ss->setMode( GL_ALPHA_TEST, osg::StateAttribute::OFF ); |
|---|
| 221 | #else |
|---|
| 222 | OSG_NOTICE<<"Warning: osgFX::AnisotropicLighting unable to disable GL_ALPHA_TEST."<<std::endl; |
|---|
| 223 | #endif |
|---|
| 224 | |
|---|
| 225 | addPass(ss.get()); |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | private: |
|---|
| 229 | int _lightnum; |
|---|
| 230 | osg::ref_ptr<osg::Texture2D> _texture; |
|---|
| 231 | }; |
|---|
| 232 | |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | |
|---|
| 236 | AnisotropicLighting::AnisotropicLighting() |
|---|
| 237 | : Effect(), |
|---|
| 238 | _lightnum(0), |
|---|
| 239 | _texture(new osg::Texture2D) |
|---|
| 240 | { |
|---|
| 241 | _texture->setImage(create_default_image()); |
|---|
| 242 | _texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP); |
|---|
| 243 | _texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP); |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | AnisotropicLighting::AnisotropicLighting(const AnisotropicLighting& copy, const osg::CopyOp& copyop) |
|---|
| 247 | : Effect(copy, copyop), |
|---|
| 248 | _lightnum(copy._lightnum), |
|---|
| 249 | _texture(static_cast<osg::Texture2D *>(copyop(copy._texture.get()))) |
|---|
| 250 | { |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | bool AnisotropicLighting::define_techniques() |
|---|
| 254 | { |
|---|
| 255 | addTechnique(new DefaultTechnique(_lightnum, _texture.get())); |
|---|
| 256 | return true; |
|---|
| 257 | } |
|---|