00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/meshvp_per_pixel_light.h"
00029 #include "3d/mesh_base_instance.h"
00030 #include "3d/driver.h"
00031 #include "3d/scene.h"
00032 #include "3d/render_trav.h"
00033 #include "3d/render_trav.h"
00034 #include "3d/vertex_program_parse.h"
00035
00036
00037
00038 #include <string>
00039
00040
00041
00042 namespace NL3D
00043 {
00044 std::auto_ptr<CVertexProgram> CMeshVPPerPixelLight::_VertexProgram[NumVp];
00045
00046
00047
00048 static const uint VPLightConstantStart = 24;
00049
00050
00051
00052
00053
00054
00056
00058
00064
00065 static const char* PPLightingVPCodeBegin =
00066 "!!VP1.0 \n\
00067 #compute B = N ^ T \n\
00068 MOV R6, v[2]; \n\
00069 MUL R1, R6.yzxw, v[9].zxyw; \n\
00070 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
00071 #vector in tangent space = [ T B N ] * L \n\
00072 ADD R2, c[4], -v[0]; # compute L \n\
00073 DP3 R3, R2, R2; # get L normalized \n\
00074 RSQ R3, R3.x; \n\
00075 MUL R2, R3, R2; \n\
00076 DP3 o[TEX0].x, v[9], R2; # get x of light vector in tangent space \n\
00077 DP3 o[TEX0].y, R1, R2; # get y \n\
00078 DP3 o[TEX0].z, R6, R2; # get z \n\
00079 #specular part \n\
00080 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
00081 #compute inverse norm of V \n\
00082 DP3 R4, R3, R3; \n\
00083 RSQ R4, R4.x; \n\
00084 #we normalize V and add it to L \n\
00085 MAD R2, R4, R3, R2; #H in R1 \n\
00086 \n\
00087 #normalize H \n\
00088 DP3 R3, R2, R2; \n\
00089 RSQ R3, R3.x; \n\
00090 MUL R2, R3, R2; \n\
00091 #compute H in tangent space \n\
00092 DP3 o[TEX2].x, v[9], R2; \n\
00093 DP3 o[TEX2].y, R1, R2; \n\
00094 DP3 o[TEX2].z, R6, R2; \n\
00095 # Position in R5 for additionnal lighting \n\
00096 MOV R5, v[0]; \n\
00097 # Normal is in R6 for additionnal lighting \n\
00098 ";
00099
00101 static const char* PPLightingVPNormalizeCodeBegin =
00102 "!!VP1.0 \n\
00103 #normalize the normal \n\
00104 DP3 R1, v[2], v[2]; \n\
00105 RSQ R1, R1.x; \n\
00106 MUL R6, v[2], R1; \n\
00107 \n\
00108 #normalize the second vector \n\
00109 DP3 R1, R6, v[9]; \n\
00110 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
00111 DP3 R2, R1, R1; \n\
00112 RSQ R2, R2.x; \n\
00113 MUL R5, R1, R2; #second basis vector in R5 \n\
00114 #compute B = N ^ T \n\
00115 MUL R1, R6.yzxw, R5.zxyw; \n\
00116 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
00117 \n\
00118 #vector in tangent space = [ T B N ] * L \n\
00119 ADD R2, c[4], -v[0]; # compute L \n\
00120 DP3 R3, R2, R2; # get L normalized \n\
00121 RSQ R3, R3.x; \n\
00122 MUL R2, R3, R2; \n\
00123 DP3 o[TEX0].x, R5, R2; # get x of light vector in tangent space \n\
00124 DP3 o[TEX0].y, R1, R2; # get y \n\
00125 DP3 o[TEX0].z, R6, R2; # get z \n\
00126 \n\
00127 #specular part \n\
00128 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
00129 #compute inverse norm of V \n\
00130 DP3 R4, R3, R3; \n\
00131 RSQ R4, R4.x; \n\
00132 #we normalize V and add it to L \n\
00133 MAD R2, R4, R3, R2; #H in R1 \n\
00134 \n\
00135 #normalize H \n\
00136 DP3 R3, R2, R2; \n\
00137 RSQ R3, R3.x; \n\
00138 MUL R2, R3, R2; \n\
00139 #compute H in tangent space \n\
00140 DP3 o[TEX2].x, R5, R2; \n\
00141 DP3 o[TEX2].y, R1, R2; \n\
00142 DP3 o[TEX2].z, R6, R2; \n\
00143 # Position in R5 for additionnal lighting \n\
00144 MOV R5, v[0]; \n\
00145 # Normal is in R6 for additionnal lighting \n\
00146 ";
00147
00148
00149
00150 static const char* PPLightingNoSpecVPCodeBegin =
00151 "!!VP1.0 \n\
00152 #compute B = N ^ T \n\
00153 MOV R6, v[2]; \n\
00154 MUL R1, R6.yzxw, v[9].zxyw; \n\
00155 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
00156 \n\
00157 #vector in tangent space = [ T B N ] * L \n\
00158 ADD R2, c[4], -v[0]; # compute L \n\
00159 DP3 R3, R2, R2; # get L normalized \n\
00160 RSQ R3, R3.x; \n\
00161 MUL R2, R3, R2; \n\
00162 DP3 o[TEX0].x, v[9], R2; # get x of light vector in tangent space \n\
00163 DP3 o[TEX0].y, R1, R2; # get y \n\
00164 DP3 o[TEX0].z, R6, R2; # get z \n\
00165 \n\
00166 \n\
00167 # Normal is in R6 for additionnal lighting \n\
00168 # Position in R5 for additionnal lighting \n\
00169 MOV R5, v[0]; \n\
00170 ";
00171
00173 static const char* PPLightingVPNormalizeNoSpecCodeBegin =
00174 "!!VP1.0 \n\
00175 #normalize the normal \n\
00176 DP3 R1, v[2], v[2]; \n\
00177 RSQ R1, R1.x; \n\
00178 MUL R6, v[2], R1; \n\
00179 \n\
00180 #normalize the second vector \n\
00181 DP3 R1, R6, v[9]; \n\
00182 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
00183 DP3 R2, R1, R1; \n\
00184 RSQ R2, R2.x; \n\
00185 MUL R5, R1, R2; #second basis vector in R5 \n\
00186 #compute B = N ^ T \n\
00187 MUL R1, R6.yzxw, R5.zxyw; \n\
00188 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
00189 \n\
00190 #vector in tangent space = [ T B N ] * L \n\
00191 ADD R2, c[4], -v[0]; # compute L \n\
00192 DP3 R3, R2, R2; # get L normalized \n\
00193 RSQ R3, R3.x; \n\
00194 MUL R2, R3, R2; \n\
00195 DP3 o[TEX0].x, R5, R2; # get x of light vector in tangent space \n\
00196 DP3 o[TEX0].y, R1, R2; # get y \n\
00197 DP3 o[TEX0].z, R6, R2; # get z \n\
00198 \n\
00199 # Normal is in R6 for additionnal lighting \n\
00200 # Position in R5 for additionnal lighting \n\
00201 MOV R5, v[0]; \n\
00202 ";
00203
00204
00206
00208
00211
00212
00213 static const char* PPLightingDirectionnalVPCodeBegin =
00214 "!!VP1.0 \n\
00215 #compute B = N ^ T \n\
00216 MOV R6, v[2]; \n\
00217 MUL R1, R6.yzxw, v[9].zxyw; \n\
00218 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
00219 \n\
00220 #vector in tangent space = [ T B N ] * L \n\
00221 DP3 o[TEX0].x, v[9], -c[4]; # get x of light vector in tangent space \n\
00222 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
00223 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
00224 \n\
00225 #specular part \n\
00226 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
00227 #compute inverse norm of V \n\
00228 DP3 R4, R3, R3; \n\
00229 RSQ R4, R4.x; \n\
00230 #we normalize V and add it to L. It gives H unnormalized \n\
00231 MAD R2, R4, R3, -c[4]; #H in R1 \n\
00232 \n\
00233 #normalize H \n\
00234 DP3 R3, R2, R2; \n\
00235 RSQ R3, R3.x; \n\
00236 MUL R2, R3, R2; \n\
00237 #compute H in tangent space \n\
00238 DP3 o[TEX2].x, v[9], R2; \n\
00239 DP3 o[TEX2].y, R1, R2; \n\
00240 DP3 o[TEX2].z, R6, R2; \n\
00241 \n\
00242 # Normal is in R6 for additionnal lighting \n\
00243 # Position in R5 for additionnal lighting \n\
00244 MOV R5, v[0]; \n\
00245 ";
00246
00247
00248 static const char* PPLightingDirectionnalVPNormalizeCodeBegin =
00249 "!!VP1.0 \n\
00250 #normalize the normal \n\
00251 DP3 R1, v[2], v[2]; \n\
00252 RSQ R1, R1.x; \n\
00253 MUL R6, v[2], R1; \n\
00254 \n\
00255 #normalize the second vector \n\
00256 DP3 R1, R6, v[9]; \n\
00257 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
00258 DP3 R2, R1, R1; \n\
00259 RSQ R2, R2.x; \n\
00260 MUL R5, R1, R2; #second basis vector in R5 \n\
00261 #compute B = N ^ T \n\
00262 MUL R1, R6.yzxw, R5.zxyw; \n\
00263 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
00264 \n\
00265 #vector in tangent space = [ T B N ] * L \n\
00266 DP3 o[TEX0].x, R5, -c[4]; # get x of light vector in tangent space \n\
00267 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
00268 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
00269 \n\
00270 #specular part \n\
00271 ADD R3, c[5], - v[0]; # compute V (return to eye) \n\
00272 #compute inverse norm of V \n\
00273 DP3 R4, R3, R3; \n\
00274 RSQ R4, R4.x; \n\
00275 #we normalize V and add it to L \n\
00276 MAD R2, R4, R3, -c[4]; #H in R1 \n\
00277 \n\
00278 #normalize H \n\
00279 DP3 R3, R2, R2; \n\
00280 RSQ R3, R3.x; \n\
00281 MUL R2, R3, R2; \n\
00282 #compute H in tangent space \n\
00283 DP3 o[TEX2].x, R5, R2; \n\
00284 DP3 o[TEX2].y, R1, R2; \n\
00285 DP3 o[TEX2].z, R6, R2; \n\
00286 # Normal is in R6 for additionnal lighting \n\
00287 # Position in R5 for additionnal lighting \n\
00288 MOV R5, v[0]; \n\
00289 ";
00290
00291
00292
00293 static const char* PPLightingDirectionnalNoSpecVPCodeBegin =
00294 "!!VP1.0 \n\
00295 #compute B = N ^ T \n\
00296 MOV R6, v[2]; \n\
00297 MUL R1, R6.yzxw, v[9].zxyw; \n\
00298 MAD R1, v[9].yzxw, -R6.zxyw, R1; \n\
00299 \n\
00300 #vector in tangent space = [ T B N ] * L \n\
00301 DP3 o[TEX0].x, v[9], -c[4]; # get x of light vector in tangent space \n\
00302 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
00303 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
00304 # Normal is in R6 for additionnal lighting \n\
00305 # Position in R5 for additionnal lighting \n\
00306 MOV R5, v[0]; \n\
00307 ";
00308
00309
00310 static const char* PPLightingDirectionnalNoSpecVPNormalizeCodeBegin =
00311 "!!VP1.0 \n\
00312 #normalize the normal \n\
00313 DP3 R1, v[2], v[2]; \n\
00314 RSQ R1, R1.x; \n\
00315 MUL R6, v[2], R1; \n\
00316 \n\
00317 #normalize the second vector \n\
00318 DP3 R1, R6, v[9]; \n\
00319 MAD R1, R6, -R1, v[9]; #subtract the normal component \n\
00320 DP3 R2, R1, R1; \n\
00321 RSQ R2, R2.x; \n\
00322 MUL R5, R1, R2; #second basis vector in R5 \n\
00323 #compute B = N ^ T \n\
00324 MUL R1, R6.yzxw, R5.zxyw; \n\
00325 MAD R1, R5.yzxw, -R6.zxyw, R1; #third basis vector in R1 \n\
00326 \n\
00327 #vector in tangent space = [ T B N ] * L \n\
00328 DP3 o[TEX0].x, R5, -c[4]; # get x of light vector in tangent space \n\
00329 DP3 o[TEX0].y, R1, -c[4]; # get y \n\
00330 DP3 o[TEX0].z, R6, -c[4]; # get z \n\
00331 \n\
00332 # Normal is in R6 for additionnal lighting \n\
00333 # Position in R5 for additionnal lighting \n\
00334 MOV R5, v[0]; \n\
00335 ";
00336
00337
00338
00339
00340 static const char* PPLightingVPCodeEnd=
00341 " # compute in Projection space \n\
00342 DP4 o[HPOS].x, c[0], v[0]; \n\
00343 DP4 o[HPOS].y, c[1], v[0]; \n\
00344 DP4 o[HPOS].z, c[2], v[0]; \n\
00345 DP4 o[HPOS].w, c[3], v[0]; \n\
00346 MOV o[TEX1].xy, v[8]; \n\
00347 END \n\
00348 ";
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 void CMeshVPPerPixelLight::initInstance(CMeshBaseInstance *mbi)
00372 {
00373
00374 static bool vpCreated= false;
00375 if(!vpCreated)
00376 {
00377 vpCreated= true;
00378
00379
00380
00381
00382
00383 static const char *vpName[] =
00384 {
00385
00386 PPLightingDirectionnalNoSpecVPCodeBegin,
00387 PPLightingNoSpecVPCodeBegin,
00388
00389 PPLightingDirectionnalVPCodeBegin,
00390 PPLightingVPCodeBegin,
00392
00393 PPLightingDirectionnalNoSpecVPNormalizeCodeBegin,
00394 PPLightingVPNormalizeNoSpecCodeBegin,
00395
00396 PPLightingDirectionnalVPNormalizeCodeBegin,
00397 PPLightingVPNormalizeCodeBegin,
00398 };
00399
00400 uint numvp = sizeof(vpName) / sizeof(const char *);
00401 nlassert(NumVp == numvp);
00402 for (uint vp = 0; vp < NumVp; ++vp)
00403 {
00404
00405
00406 std::string vpCode = std::string(vpName[vp])
00407 + std::string("# ***************")
00408 + CRenderTrav::getLightVPFragment(CRenderTrav::MaxVPLight-1, VPLightConstantStart, (vp & 2) != 0, false)
00409 + std::string("# ***************")
00410 + std::string(PPLightingVPCodeEnd);
00411 #ifdef NL_DEBUG
00412
00417 CVPParser vpParser;
00418 CVPParser::TProgram result;
00419 std::string parseOutput;
00420 if (!vpParser.parse(vpCode.c_str(), result, parseOutput))
00421 {
00422 nlwarning(parseOutput.c_str());
00423 nlassert(0);
00424 }
00425 #endif
00426 _VertexProgram[vp]= std::auto_ptr<CVertexProgram>(new CVertexProgram(vpCode.c_str()));
00427 }
00428
00429 }
00430 }
00431
00432
00433 bool CMeshVPPerPixelLight::begin(IDriver *drv,
00434 CScene *scene, CMeshBaseInstance *mbi,
00435 const NLMISC::CMatrix &invertedModelMat,
00436 const NLMISC::CVector &viewerPos)
00437 {
00438
00439 if (!
00440 (drv->isVertexProgramSupported()
00441 && !drv->isVertexProgramEmulated()
00442 && drv->supportPerPixelLighting(SpecularLighting)
00443 )
00444 )
00445 {
00446 return false;
00447 }
00448
00449 CRenderTrav *renderTrav= scene->getRenderTrav();
00451 renderTrav->beginVPLightSetup(VPLightConstantStart,
00452 SpecularLighting,
00453 invertedModelMat);
00454
00455 sint strongestLightIndex = renderTrav->getStrongestLightIndex();
00456 if (strongestLightIndex == -1) return false;
00457
00459
00460
00461 switch (strongestLight.getMode())
00462 {
00463 case CLight::DirectionalLight:
00464 {
00465
00466 NLMISC::CVector lPos = invertedModelMat.mulVector(strongestLight.getDirection());
00467 drv->setConstant(4, lPos);
00468 _IsPointLight = false;
00469 }
00470 break;
00471 case CLight::PointLight:
00472 {
00473
00474 NLMISC::CVector lPos = invertedModelMat * strongestLight.getPosition();
00475 drv->setConstant(4, lPos);
00476 _IsPointLight = true;
00477 }
00478 break;
00479 default:
00480 return false;
00481 break;
00482 }
00483
00484
00485 if (SpecularLighting)
00486 {
00487
00488 NLMISC::CVector vPos = invertedModelMat * viewerPos;
00489 drv->setConstant(5, vPos);
00490 }
00491
00492
00493 drv->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
00494
00495 enable(true, drv);
00496
00497 return true;
00498 }
00499
00500
00501
00502 void CMeshVPPerPixelLight::end(IDriver *drv)
00503 {
00504 enable(false, drv);
00505 }
00506
00507
00508
00509 void CMeshVPPerPixelLight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00510 {
00511 (void)f.serialVersion(0);
00512 f.serial(SpecularLighting);
00513 }
00514
00515
00516
00517 void CMeshVPPerPixelLight::enable(bool enabled, IDriver *drv)
00518 {
00519 if (enabled != _Enabled)
00520 {
00521 nlassert(drv);
00522 if (enabled)
00523 {
00524
00525
00526
00527
00528
00529 uint idVP = (drv->isForceNormalize() ? 4 : 0)
00530 | (SpecularLighting ? 2 : 0)
00531 | (_IsPointLight ? 1 : 0);
00532
00533 drv->activeVertexProgram(_VertexProgram[idVP].get());
00534 }
00535 else
00536 {
00537 drv->activeVertexProgram(NULL);
00538 }
00539 _Enabled = enabled;
00540 }
00541 }
00542
00543
00544 bool CMeshVPPerPixelLight::setupForMaterial(const CMaterial &mat,
00545 IDriver *drv,
00546 CScene *scene
00547 )
00548 {
00549 bool enabled = (mat.getShader() == CMaterial::PerPixelLighting || mat.getShader() == CMaterial::PerPixelLightingNoSpec);
00550 if (enabled)
00551 {
00552 CRenderTrav *renderTrav= scene->getRenderTrav();
00553 renderTrav->changeVPLightSetupMaterial(mat, true );
00554
00555 NLMISC::CRGBA pplDiffuse, pplSpecular;
00556 renderTrav->getStrongestLightColors(pplDiffuse, pplSpecular);
00557 drv->setPerPixelLightingLight(pplDiffuse, pplSpecular, mat.getShininess());
00558 }
00559 bool change = (enabled != _Enabled);
00560 enable(enabled, drv);
00561 return change;
00562 }
00563
00564 void CMeshVPPerPixelLight::setupForMaterial(const CMaterial &mat,
00565 IDriver *drv,
00566 CScene *scene,
00567 CVertexBuffer *vb)
00568 {
00569
00570 if (setupForMaterial(mat, drv, scene))
00571 {
00572 drv->activeVertexBuffer(*vb);
00573 }
00574 }
00575
00576
00577 void CMeshVPPerPixelLight::setupForMaterial(const CMaterial &mat,
00578 IDriver *drv,
00579 CScene *scene,
00580 IVertexBufferHard *vb)
00581 {
00582
00583 if (setupForMaterial(mat, drv, scene))
00584 {
00585 drv->activeVertexBufferHard(vb);
00586 }
00587 }
00588
00589
00590 }