COpenGLParallaxMapRenderer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #include "IrrCompileConfig.h"
  5. #ifdef _IRR_COMPILE_WITH_OPENGL_
  6. #include "COpenGLParallaxMapRenderer.h"
  7. #include "COpenGLDriver.h"
  8. #include "IGPUProgrammingServices.h"
  9. #include "IShaderConstantSetCallBack.h"
  10. #include "IVideoDriver.h"
  11. #include "os.h"
  12. namespace irr
  13. {
  14. namespace video
  15. {
  16. // Irrlicht Engine OpenGL render path parallax map vertex shader
  17. // I guess it could be optimized a lot, because I wrote it in D3D ASM and
  18. // transferred it 1:1 to OpenGL
  19. const char OPENGL_PARALLAX_MAP_VSH[] =
  20. "!!ARBvp1.0\n"\
  21. "#input\n"\
  22. "# 0-3: transposed world matrix;\n"\
  23. "#;12: Light01 position \n"\
  24. "#;13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\
  25. "#;14: Light02 position \n"\
  26. "#;15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\
  27. "#;16: Eye position \n"\
  28. "\n"\
  29. "ATTRIB InPos = vertex.position;\n"\
  30. "ATTRIB InColor = vertex.color;\n"\
  31. "ATTRIB InNormal = vertex.normal;\n"\
  32. "ATTRIB InTexCoord = vertex.texcoord[0];\n"\
  33. "ATTRIB InTangent = vertex.texcoord[1];\n"\
  34. "ATTRIB InBinormal = vertex.texcoord[2];\n"\
  35. "\n"\
  36. "#output\n"\
  37. "OUTPUT OutPos = result.position;\n"\
  38. "OUTPUT OutLightColor1 = result.color.primary;\n"\
  39. "OUTPUT OutLightColor2 = result.color.secondary;\n"\
  40. "OUTPUT OutTexCoord = result.texcoord[0];\n"\
  41. "OUTPUT OutLightVector1 = result.texcoord[1];\n"\
  42. "OUTPUT OutLightVector2 = result.texcoord[2];\n"\
  43. "OUTPUT OutEyeVector = result.texcoord[3];\n"\
  44. "\n"\
  45. "PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\n"\
  46. "TEMP Temp;\n"\
  47. "TEMP TempColor;\n"\
  48. "TEMP TempLightVector1;\n"\
  49. "TEMP TempLightVector2;\n"\
  50. "TEMP TempEyeVector;\n"\
  51. "TEMP TempTransLightV1;\n"\
  52. "TEMP TempTransLightV2;\n"\
  53. "\n"\
  54. "# transform position to clip space \n"\
  55. "DP4 OutPos.x, MVP[0], InPos;\n"\
  56. "DP4 OutPos.y, MVP[1], InPos;\n"\
  57. "DP4 Temp.z, MVP[2], InPos;\n"\
  58. "DP4 OutPos.w, MVP[3], InPos;\n"\
  59. "MOV OutPos.z, Temp.z;\n"\
  60. "MOV result.fogcoord.x, Temp.z;\n"\
  61. "\n"\
  62. "# vertex - lightpositions \n"\
  63. "SUB TempLightVector1, program.local[12], InPos; \n"\
  64. "SUB TempLightVector2, program.local[14], InPos; \n"\
  65. "\n"\
  66. "# eye vector \n"\
  67. "SUB Temp, program.local[16], InPos; \n"\
  68. "\n"\
  69. "# transform the light vector 1 with U, V, W \n"\
  70. "DP3 TempTransLightV1.x, InTangent, TempLightVector1; \n"\
  71. "DP3 TempTransLightV1.y, InBinormal, TempLightVector1; \n"\
  72. "DP3 TempTransLightV1.z, InNormal, TempLightVector1; \n"\
  73. "\n"\
  74. "# transform the light vector 2 with U, V, W \n"\
  75. "DP3 TempTransLightV2.x, InTangent, TempLightVector2; \n"\
  76. "DP3 TempTransLightV2.y, InBinormal, TempLightVector2; \n"\
  77. "DP3 TempTransLightV2.z, InNormal, TempLightVector2; \n"\
  78. "\n"\
  79. "# transform the eye vector with U, V, W \n"\
  80. "DP3 TempEyeVector.x, InTangent, Temp; \n"\
  81. "DP3 TempEyeVector.y, InBinormal, Temp; \n"\
  82. "DP3 TempEyeVector.z, InNormal, Temp; \n"\
  83. "\n"\
  84. "# normalize light vector 1 \n"\
  85. "DP3 TempTransLightV1.w, TempTransLightV1, TempTransLightV1; \n"\
  86. "RSQ TempTransLightV1.w, TempTransLightV1.w; \n"\
  87. "MUL TempTransLightV1, TempTransLightV1, TempTransLightV1.w;\n"\
  88. "\n"\
  89. "# normalize light vector 2 \n"\
  90. "DP3 TempTransLightV2.w, TempTransLightV2, TempTransLightV2; \n"\
  91. "RSQ TempTransLightV2.w, TempTransLightV2.w; \n"\
  92. "MUL TempTransLightV2, TempTransLightV2, TempTransLightV2.w;\n"\
  93. "\n"\
  94. "# normalize eye vector \n"\
  95. "DP3 TempEyeVector.w, TempEyeVector, TempEyeVector; \n"\
  96. "RSQ TempEyeVector.w, TempEyeVector.w; \n"\
  97. "MUL TempEyeVector, TempEyeVector, TempEyeVector.w;\n"\
  98. "MUL TempEyeVector, TempEyeVector, {1,-1,-1,1}; # flip x \n"\
  99. "\n"\
  100. "\n"\
  101. "# move light and eye vectors out\n"\
  102. "MAD OutLightVector1, TempTransLightV1, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\
  103. "MAD OutLightVector2, TempTransLightV2, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\
  104. "MAD OutEyeVector, TempEyeVector, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\
  105. "\n"\
  106. "# calculate attenuation of light 1\n"\
  107. "MOV TempLightVector1.w, {0,0,0,0}; \n"\
  108. "DP3 TempLightVector1.x, TempLightVector1, TempLightVector1; \n"\
  109. "MUL TempLightVector1.x, TempLightVector1.x, program.local[13].w; \n"\
  110. "RSQ TempLightVector1, TempLightVector1.x; \n"\
  111. "MUL OutLightColor1, TempLightVector1, program.local[13]; # resulting light color = lightcolor * attenuation \n"\
  112. "\n"\
  113. "# calculate attenuation of light 2\n"\
  114. "MOV TempLightVector2.w, {0,0,0,0}; \n"\
  115. "DP3 TempLightVector2.x, TempLightVector2, TempLightVector2; \n"\
  116. "MUL TempLightVector2.x, TempLightVector2.x, program.local[15].w; \n"\
  117. "RSQ TempLightVector2, TempLightVector2.x; \n"\
  118. "MUL OutLightColor2, TempLightVector2, program.local[15]; # resulting light color = lightcolor * attenuation \n"\
  119. "\n"\
  120. "# move out texture coordinates and original alpha value\n"\
  121. "MOV OutTexCoord, InTexCoord; \n"\
  122. "MOV OutLightColor1.w, InColor.w; \n"\
  123. "\n"\
  124. "END\n";
  125. // Irrlicht Engine OpenGL render path parallax map pixel shader
  126. // I guess it could be optimized a bit, because I wrote it in D3D ASM and
  127. // transfered it 1:1 to OpenGL
  128. const char OPENGL_PARALLAX_MAP_PSH[] =
  129. "!!ARBfp1.0\n"\
  130. "#_IRR_FOG_MODE_\n"\
  131. "\n"\
  132. "#Input\n"\
  133. "ATTRIB inTexCoord = fragment.texcoord[0]; \n"\
  134. "ATTRIB light1Vector = fragment.texcoord[1]; \n"\
  135. "ATTRIB light2Vector = fragment.texcoord[2]; \n"\
  136. "ATTRIB eyeVector = fragment.texcoord[3]; \n"\
  137. "ATTRIB light1Color = fragment.color.primary; \n"\
  138. "ATTRIB light2Color = fragment.color.secondary; \n"\
  139. "\n"\
  140. "#Output\n"\
  141. "OUTPUT outColor = result.color;\n"\
  142. "TEMP temp;\n"\
  143. "TEMP temp2;\n"\
  144. "TEMP colorMapColor;\n"\
  145. "TEMP normalMapColor;\n"\
  146. "\n"\
  147. "PARAM height_scale = program.local[0]; \n"\
  148. "# fetch color and normal map; \n"\
  149. "TXP normalMapColor, inTexCoord, texture[1], 2D; \n"\
  150. "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\
  151. "\n"\
  152. "\n"\
  153. "# extract eye vector (so substract 0.5f and multiply by 2)\n"\
  154. "MAD temp, eyeVector, {2,2,2,2}, {-1,-1,-1,-1};\n"\
  155. "\n"\
  156. "# height = height * scale \n"\
  157. "MUL normalMapColor, normalMapColor, height_scale;\n"\
  158. "\n"\
  159. "# calculate new texture coord: height * eye + oldTexCoord\n"\
  160. "MAD temp, temp, normalMapColor.wwww, inTexCoord;\n"\
  161. "\n"\
  162. "# fetch new textures \n"\
  163. "TXP colorMapColor, temp, texture[0], 2D; \n"\
  164. "TXP normalMapColor, temp, texture[1], 2D; \n"\
  165. "\n"\
  166. "# calculate color of light1; \n"\
  167. "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\
  168. "MAD temp, light1Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\
  169. "DP3_SAT temp, normalMapColor, temp; \n"\
  170. "MUL temp, light1Color, temp; \n"\
  171. "\n"\
  172. "# calculate color of light2; \n"\
  173. "MAD temp2, light2Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\
  174. "DP3_SAT temp2, normalMapColor, temp2; \n"\
  175. "MAD temp, light2Color, temp2, temp; \n"\
  176. "\n"\
  177. "# luminance * base color; \n"\
  178. "MUL outColor, temp, colorMapColor; \n"\
  179. "MOV outColor.a, light1Color.a; #write interpolated vertex alpha value\n"\
  180. "\n"\
  181. "END\n";
  182. //! Constructor
  183. COpenGLParallaxMapRenderer::COpenGLParallaxMapRenderer(video::COpenGLDriver* driver,
  184. s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
  185. : COpenGLShaderMaterialRenderer(driver, 0, baseMaterial), CompiledShaders(true)
  186. {
  187. #ifdef _DEBUG
  188. setDebugName("COpenGLParallaxMapRenderer");
  189. #endif
  190. // set this as callback. We could have done this in
  191. // the initialization list, but some compilers don't like it.
  192. CallBack = this;
  193. // basically, this simply compiles the hard coded shaders if the
  194. // hardware is able to do them, otherwise it maps to the base material
  195. if (!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) ||
  196. !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
  197. {
  198. // this hardware is not able to do shaders. Fall back to
  199. // base material.
  200. outMaterialTypeNr = driver->addMaterialRenderer(this);
  201. return;
  202. }
  203. // check if already compiled normal map shaders are there.
  204. video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID);
  205. if (renderer)
  206. {
  207. // use the already compiled shaders
  208. video::COpenGLParallaxMapRenderer* nmr = reinterpret_cast<video::COpenGLParallaxMapRenderer*>(renderer);
  209. CompiledShaders = false;
  210. VertexShader = nmr->VertexShader;
  211. PixelShader = nmr->PixelShader;
  212. outMaterialTypeNr = driver->addMaterialRenderer(this);
  213. }
  214. else
  215. {
  216. // compile shaders on our own
  217. init(outMaterialTypeNr, OPENGL_PARALLAX_MAP_VSH, OPENGL_PARALLAX_MAP_PSH, EVT_TANGENTS);
  218. }
  219. // fallback if compilation has failed
  220. if (-1==outMaterialTypeNr)
  221. outMaterialTypeNr = driver->addMaterialRenderer(this);
  222. }
  223. //! Destructor
  224. COpenGLParallaxMapRenderer::~COpenGLParallaxMapRenderer()
  225. {
  226. if (CallBack == this)
  227. CallBack = 0;
  228. if (!CompiledShaders)
  229. {
  230. // prevent this from deleting shaders we did not create
  231. VertexShader = 0;
  232. PixelShader.clear();
  233. }
  234. }
  235. void COpenGLParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material,
  236. const video::SMaterial& lastMaterial,
  237. bool resetAllRenderstates, video::IMaterialRendererServices* services)
  238. {
  239. COpenGLShaderMaterialRenderer::OnSetMaterial(material, lastMaterial,
  240. resetAllRenderstates, services);
  241. CurrentScale = material.MaterialTypeParam;
  242. }
  243. //! Returns the render capability of the material.
  244. s32 COpenGLParallaxMapRenderer::getRenderCapability() const
  245. {
  246. if (Driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) &&
  247. Driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
  248. return 0;
  249. return 1;
  250. }
  251. //! Called by the engine when the vertex and/or pixel shader constants for an
  252. //! material renderer should be set.
  253. void COpenGLParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
  254. {
  255. video::IVideoDriver* driver = services->getVideoDriver();
  256. // set transposed world matrix
  257. const core::matrix4& tWorld = driver->getTransform(video::ETS_WORLD).getTransposed();
  258. services->setVertexShaderConstant(tWorld.pointer(), 0, 4);
  259. // set transposed worldViewProj matrix
  260. core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
  261. worldViewProj *= driver->getTransform(video::ETS_VIEW);
  262. worldViewProj *= driver->getTransform(video::ETS_WORLD);
  263. core::matrix4 tr(worldViewProj.getTransposed());
  264. services->setVertexShaderConstant(tr.pointer(), 8, 4);
  265. // here we fetch the fixed function lights from the driver
  266. // and set them as constants
  267. u32 cnt = driver->getDynamicLightCount();
  268. // Load the inverse world matrix.
  269. core::matrix4 invWorldMat;
  270. driver->getTransform(video::ETS_WORLD).getInverse(invWorldMat);
  271. for (u32 i=0; i<2; ++i)
  272. {
  273. video::SLight light;
  274. if (i<cnt)
  275. light = driver->getDynamicLight(i);
  276. else
  277. {
  278. light.DiffuseColor.set(0,0,0); // make light dark
  279. light.Radius = 1.0f;
  280. }
  281. light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
  282. // Transform the light by the inverse world matrix to get it into object space.
  283. invWorldMat.transformVect(light.Position);
  284. services->setVertexShaderConstant(
  285. reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
  286. services->setVertexShaderConstant(
  287. reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
  288. }
  289. // Obtain the view position by transforming 0,0,0 by the inverse view matrix
  290. // and then multiply this by the inverse world matrix.
  291. core::vector3df viewPos(0.0f, 0.0f, 0.0f);
  292. core::matrix4 inverseView;
  293. driver->getTransform(video::ETS_VIEW).getInverse(inverseView);
  294. inverseView.transformVect(viewPos);
  295. invWorldMat.transformVect(viewPos);
  296. services->setVertexShaderConstant(reinterpret_cast<const f32*>(&viewPos.X), 16, 1);
  297. // set scale factor
  298. f32 factor = 0.02f; // default value
  299. if (CurrentScale != 0.0f)
  300. factor = CurrentScale;
  301. f32 c6[] = {factor, factor, factor, factor};
  302. services->setPixelShaderConstant(c6, 0, 1);
  303. }
  304. } // end namespace video
  305. } // end namespace irr
  306. #endif