BsBansheeLitTexRenderableController.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. #include "BsBansheeLitTexRenderableController.h"
  2. #include "BsRenderableProxy.h"
  3. #include "BsShader.h"
  4. #include "BsShaderProxy.h"
  5. #include "BsGpuParams.h"
  6. #include "BsBansheeRenderer.h"
  7. #include "BsHardwareBufferManager.h"
  8. #include "BsGpuParamBlockBuffer.h"
  9. #include "BsTechnique.h"
  10. #include "BsPass.h"
  11. #include "BsRenderSystem.h"
  12. namespace BansheeEngine
  13. {
  14. LitTexRenderableController::LitTexRenderableController()
  15. {
  16. defaultShader = createDefaultShader();
  17. TechniquePtr defaultTechnique = defaultShader->getBestTechnique();
  18. PassPtr defaultPass = defaultTechnique->getPass(0);
  19. bool matrixTranspose = defaultPass->getVertexProgram()->requiresMatrixTranspose(); // Only need this from first vertex program as this is a static setting across all GPU programs
  20. GpuParamDescPtr vertParamDesc = defaultPass->getVertexProgram()->getParamDesc();
  21. GpuParamDescPtr fragParamDesc = defaultPass->getFragmentProgram()->getParamDesc();
  22. GpuParamDescPtr staticParamsDesc = bs_shared_ptr<GpuParamDesc>();
  23. GpuParamDescPtr perFrameParamsDesc = bs_shared_ptr<GpuParamDesc>();
  24. GpuParamDescPtr perObjectParamsDesc = bs_shared_ptr<GpuParamDesc>();
  25. bool foundLightDir = false;
  26. bool foundTime = false;
  27. bool foundWVP = false;
  28. bool foundStatic = false;
  29. bool foundPerFrame = false;
  30. bool foundPerObject = false;
  31. const Map<String, SHADER_DATA_PARAM_DESC>& dataParams = defaultShader->_getDataParams();
  32. for (auto& param : dataParams)
  33. {
  34. if (!foundLightDir && param.second.rendererSemantic == RPS_LightDir)
  35. {
  36. auto iterFind = fragParamDesc->params.find(param.second.gpuVariableName);
  37. if (iterFind == fragParamDesc->params.end())
  38. continue;
  39. lightDirParamDesc = iterFind->second;
  40. staticParamsDesc->params[iterFind->first] = iterFind->second;
  41. foundLightDir = true;
  42. }
  43. else if (!foundTime && param.second.rendererSemantic == RPS_Time)
  44. {
  45. auto iterFind = vertParamDesc->params.find(param.second.gpuVariableName);
  46. if (iterFind == vertParamDesc->params.end())
  47. continue;
  48. timeParamDesc = iterFind->second;
  49. perFrameParamsDesc->params[iterFind->first] = iterFind->second;
  50. foundTime = true;
  51. }
  52. else if (!foundWVP && param.second.rendererSemantic == RPS_WorldViewProjTfrm)
  53. {
  54. auto iterFind = vertParamDesc->params.find(param.second.gpuVariableName);
  55. if (iterFind == vertParamDesc->params.end())
  56. continue;
  57. wvpParamDesc = iterFind->second;
  58. perObjectParamsDesc->params[iterFind->first] = iterFind->second;
  59. foundWVP = true;
  60. }
  61. }
  62. const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlocks = defaultShader->_getParamBlocks();
  63. for (auto& block : paramBlocks)
  64. {
  65. if (!foundStatic && block.second.rendererSemantic == RBS_Static)
  66. {
  67. auto iterFind = fragParamDesc->paramBlocks.find(block.second.name);
  68. if (iterFind == fragParamDesc->paramBlocks.end())
  69. continue;
  70. staticParamBlockDesc = iterFind->second;
  71. staticParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  72. foundStatic = true;
  73. }
  74. else if (!foundPerFrame && block.second.rendererSemantic == RBS_PerFrame)
  75. {
  76. auto iterFind = vertParamDesc->paramBlocks.find(block.second.name);
  77. if (iterFind == vertParamDesc->paramBlocks.end())
  78. continue;
  79. perFrameParamBlockDesc = iterFind->second;
  80. perFrameParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  81. foundPerFrame = true;
  82. }
  83. else if (!foundPerObject && block.second.rendererSemantic == RBS_PerObject)
  84. {
  85. auto iterFind = vertParamDesc->paramBlocks.find(block.second.name);
  86. if (iterFind == vertParamDesc->paramBlocks.end())
  87. continue;
  88. perObjectParamBlockDesc = iterFind->second;
  89. perObjectParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
  90. foundPerObject = true;
  91. }
  92. }
  93. if (!foundLightDir || !foundTime || !foundWVP || !foundStatic || !foundPerFrame || !foundPerObject)
  94. BS_EXCEPT(InternalErrorException, "Invalid default shader.");
  95. // Create global GPU param buffers and get parameter handles
  96. staticParams = bs_shared_ptr<GpuParams>(staticParamsDesc, matrixTranspose);
  97. perFrameParams = bs_shared_ptr<GpuParams>(perFrameParamsDesc, matrixTranspose);
  98. staticParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(staticParamBlockDesc.blockSize * sizeof(UINT32));
  99. perFrameParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(perFrameParamBlockDesc.blockSize * sizeof(UINT32));
  100. staticParams->setParamBlockBuffer(staticParamBlockDesc.slot, staticParamBuffer);
  101. perFrameParams->setParamBlockBuffer(perFrameParamBlockDesc.slot, perFrameParamBuffer);
  102. staticParams->getParam(lightDirParamDesc.name, lightDirParam);
  103. perFrameParams->getParam(timeParamDesc.name, timeParam);
  104. lightDirParam.set(Vector4(0.707f, 0.707f, 0.707f, 0.0f));
  105. }
  106. void LitTexRenderableController::initializeRenderElem(RenderableElement* element)
  107. {
  108. static auto paramsMatch = [](const GpuParamDataDesc& a, const GpuParamDataDesc& b)
  109. {
  110. return a.gpuMemOffset == b.gpuMemOffset && a.elementSize == b.elementSize &&
  111. a.arraySize == b.arraySize && a.arrayElementStride == b.arrayElementStride;
  112. };
  113. element->rendererData = PerObjectData();
  114. PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  115. ShaderProxyPtr shader = element->material->shader;
  116. const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlockDescs = shader->paramBlocks;
  117. const Map<String, SHADER_DATA_PARAM_DESC>& dataParamDescs = shader->dataParams;
  118. String staticBlockName;
  119. String perFrameBlockName;
  120. String perObjectBlockName;
  121. String wvpParamName;
  122. for (auto& paramBlockDesc : paramBlockDescs)
  123. {
  124. switch (paramBlockDesc.second.rendererSemantic)
  125. {
  126. case RBS_Static:
  127. staticBlockName = paramBlockDesc.second.name;
  128. break;
  129. case RBS_PerFrame:
  130. perFrameBlockName = paramBlockDesc.second.name;
  131. break;
  132. case RBS_PerObject:
  133. perObjectBlockName = paramBlockDesc.second.name;
  134. break;
  135. }
  136. }
  137. for (auto& paramDesc : dataParamDescs)
  138. {
  139. if (paramDesc.second.rendererSemantic == RPS_WorldViewProjTfrm)
  140. wvpParamName = paramDesc.second.gpuVariableName;
  141. }
  142. UINT32 idx = 0;
  143. for (auto& gpuParams : element->material->params)
  144. {
  145. const GpuParamDesc& paramsDesc = gpuParams->getParamDesc();
  146. if (staticBlockName != "")
  147. {
  148. auto findIter = paramsDesc.paramBlocks.find(staticBlockName);
  149. if (findIter != paramsDesc.paramBlocks.end())
  150. {
  151. // TODO - We only compare block sizes but not actual contents. Should I check them too?
  152. // Probably shouldn't concern myself with that here, instead check that on a higher level.
  153. if (findIter->second.blockSize == staticParamBlockDesc.blockSize)
  154. {
  155. UINT32 slotIdx = findIter->second.slot;
  156. element->material->rendererBuffers.push_back(MaterialProxy::BufferBindInfo(idx, slotIdx, staticParamBuffer));
  157. }
  158. }
  159. }
  160. if (perFrameBlockName != "")
  161. {
  162. auto findIter = paramsDesc.paramBlocks.find(perFrameBlockName);
  163. if (findIter != paramsDesc.paramBlocks.end())
  164. {
  165. if (findIter->second.blockSize == perFrameParamBlockDesc.blockSize)
  166. {
  167. UINT32 slotIdx = findIter->second.slot;
  168. element->material->rendererBuffers.push_back(MaterialProxy::BufferBindInfo(idx, slotIdx, perFrameParamBuffer));
  169. }
  170. }
  171. }
  172. if (perObjectBlockName != "")
  173. {
  174. auto findIter = paramsDesc.paramBlocks.find(perObjectBlockName);
  175. if (findIter != paramsDesc.paramBlocks.end())
  176. {
  177. if (findIter->second.blockSize == perObjectParamBlockDesc.blockSize)
  178. {
  179. if (rendererData->perObjectParamBuffer == nullptr)
  180. rendererData->perObjectParamBuffer = HardwareBufferManager::instance().createGpuParamBlockBuffer(perObjectParamBlockDesc.blockSize * sizeof(UINT32));
  181. rendererData->perObjectBuffers.push_back(MaterialProxy::BufferBindInfo(idx, findIter->second.slot, rendererData->perObjectParamBuffer));
  182. if (!rendererData->hasWVPParam && wvpParamName != "")
  183. {
  184. auto findIter2 = paramsDesc.params.find(wvpParamName);
  185. if (findIter2 != paramsDesc.params.end())
  186. {
  187. if (paramsMatch(findIter2->second, wvpParamDesc))
  188. {
  189. gpuParams->getParam(wvpParamName, rendererData->wvpParam);
  190. rendererData->hasWVPParam = true;
  191. }
  192. }
  193. }
  194. }
  195. }
  196. }
  197. idx++;
  198. }
  199. bindGlobalBuffers(element);
  200. }
  201. void LitTexRenderableController::bindPerObjectBuffers(const RenderableElement* element)
  202. {
  203. const PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  204. for (auto& perObjectBuffer : rendererData->perObjectBuffers)
  205. {
  206. GpuParamsPtr params = element->material->params[perObjectBuffer.paramsIdx];
  207. params->setParamBlockBuffer(perObjectBuffer.slotIdx, rendererData->perObjectParamBuffer);
  208. }
  209. }
  210. void LitTexRenderableController::updateGlobalBuffers(float time)
  211. {
  212. timeParam.set(time);
  213. staticParams->updateHardwareBuffers();
  214. perFrameParams->updateHardwareBuffers();
  215. }
  216. void LitTexRenderableController::updatePerObjectBuffers(RenderableElement* element, const Matrix4& wvpMatrix)
  217. {
  218. PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element->rendererData);
  219. if (rendererData->hasWVPParam)
  220. rendererData->wvpParam.set(wvpMatrix);
  221. if (rendererData->perObjectParamBuffer != nullptr)
  222. {
  223. GpuParamBlockPtr paramBlock = rendererData->perObjectParamBuffer->getParamBlock();
  224. if (paramBlock->isDirty())
  225. paramBlock->uploadToBuffer(rendererData->perObjectParamBuffer);
  226. }
  227. }
  228. ShaderPtr LitTexRenderableController::createDefaultShader()
  229. {
  230. String rsName = RenderSystem::instance().getName();
  231. HGpuProgram vsProgram;
  232. HGpuProgram psProgram;
  233. if (rsName == RenderSystemDX11)
  234. {
  235. String vsCode = R"(
  236. cbuffer PerFrame
  237. {
  238. float time;
  239. }
  240. cbuffer PerObject
  241. {
  242. float4x4 matWorldViewProj;
  243. }
  244. void vs_main(in float3 inPos : POSITION,
  245. out float4 oPosition : SV_Position)
  246. {
  247. oPosition = mul(matWorldViewProj, float4(inPos.xyz + float3(sin(time), 0, 0), 1));
  248. })";
  249. String psCode = R"(
  250. cbuffer Static
  251. {
  252. float4 lightDir;
  253. }
  254. float4 ps_main() : SV_Target
  255. {
  256. return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
  257. })";
  258. vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
  259. psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_FS_4_0);
  260. }
  261. else if (rsName == RenderSystemDX9)
  262. {
  263. String vsCode = R"(
  264. BS_PARAM_BLOCK PerFrame { time }
  265. BS_PARAM_BLOCK PerObject { matWorldViewProj }
  266. float time;
  267. float4x4 matWorldViewProj;
  268. void vs_main(in float3 inPos : POSITION,
  269. out float4 oPosition : POSITION)
  270. {
  271. oPosition = mul(matWorldViewProj, float4(inPos.xyz + float3(sin(time), 0, 0), 1));
  272. })";
  273. String psCode = R"(
  274. BS_PARAM_BLOCK Static { lightDir }
  275. float4 lightDir;
  276. float4 ps_main() : COLOR0
  277. {
  278. return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
  279. })";
  280. vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
  281. psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_FS_2_0);
  282. }
  283. else if (rsName == RenderSystemOpenGL)
  284. {
  285. String vsCode = R"(#version 400
  286. uniform PerFrame
  287. {
  288. float time;
  289. };
  290. uniform PerObject
  291. {
  292. mat4 matWorldViewProj;
  293. };
  294. in vec3 bs_position;
  295. void main()
  296. {
  297. gl_Position = matWorldViewProj * vec4(bs_position.xyz + vec3(sin(time), 0, 0), 1);
  298. })";
  299. String psCode = R"(#version 400
  300. uniform Static
  301. {
  302. vec4 lightDir;
  303. };
  304. out vec4 fragColor;
  305. void main()
  306. {
  307. fragColor = lightDir * vec4(0.5f, 0.5f, 0.5f, 0.5f);
  308. })";
  309. vsProgram = GpuProgram::create(vsCode, "main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
  310. psProgram = GpuProgram::create(psCode, "main", "glsl", GPT_FRAGMENT_PROGRAM, GPP_FS_4_0);
  311. }
  312. vsProgram.synchronize();
  313. psProgram.synchronize();
  314. ShaderPtr defaultShader = Shader::create("LitTexDefault");
  315. defaultShader->setParamBlockAttribs("Static", true, GPBU_DYNAMIC, RBS_Static);
  316. defaultShader->setParamBlockAttribs("PerFrame", true, GPBU_DYNAMIC, RBS_PerFrame);
  317. defaultShader->setParamBlockAttribs("PerObject", true, GPBU_DYNAMIC, RBS_PerObject);
  318. defaultShader->addParameter("lightDir", "lightDir", GPDT_FLOAT4, RPS_LightDir);
  319. defaultShader->addParameter("time", "time", GPDT_FLOAT1, RPS_Time);
  320. defaultShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4, RPS_WorldViewProjTfrm);
  321. TechniquePtr newTechnique = defaultShader->addTechnique(rsName, RendererDefault);
  322. PassPtr newPass = newTechnique->addPass();
  323. newPass->setVertexProgram(vsProgram);
  324. newPass->setFragmentProgram(psProgram);
  325. return defaultShader;
  326. }
  327. }