webgl_lights_deferred_pointlights.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>redPlant WebGL Deferred Rendering with Three.js</title>
  6. <style>
  7. body {
  8. background-color: #000;
  9. margin: 0px;
  10. overflow: hidden;
  11. }
  12. #info {
  13. position: absolute;
  14. top: 0px; width: 100%;
  15. color: #ffffff;
  16. padding: 5px;
  17. font-family: Monospace;
  18. font-size: 13px;
  19. text-align: center;
  20. }
  21. a {
  22. color: #ff0080;
  23. text-decoration: none;
  24. }
  25. a:hover {
  26. color: #0080ff;
  27. }
  28. </style>
  29. </head>
  30. <body>
  31. <div id="info">
  32. <a href="http://threejs.org" target="_blank">three.js</a> - deferred point lights WebGL demo by <a href="http://de.redplant.de" target=_blank>redPlant</a>.<br />
  33. Walt Disney head by <a href="http://davidoreilly.com/post/18087489343/disneyhead" target="_blank">David OReilly</a><br>
  34. Point Light attenuation formula by <a href="http://imdoingitwrong.wordpress.com/tag/glsl/" target=_blank>Tom Madams</a>
  35. </div>
  36. <div id="container">
  37. </div>
  38. </body>
  39. <script src="js/three/three.js"></script>
  40. <script src="js/three/Stats.js"></script>
  41. <script src="js/scripts/requestAnimationFrame.js"></script>
  42. <script src="js/scripts/ShaderExtras.js"></script>
  43. <script src="js/postprocessing/EffectComposer.js"></script>
  44. <script src="js/postprocessing/RenderPass.js"></script>
  45. <script src="js/postprocessing/ShaderPass.js"></script>
  46. <script src="js/postprocessing/MaskPass.js"></script>
  47. <script>
  48. var WIDTH = window.innerWidth;
  49. HEIGHT = window.innerHeight;
  50. var NEAR = 1.0, FAR = 250.0;
  51. var VIEW_ANGLE = 45;
  52. var ASPECT = WIDTH / HEIGHT;
  53. // core
  54. var renderer, camera, controls, stats, clock;
  55. // scenes and scene nodes
  56. var lightScene, lightNode, scene, sceneNode, emitterScene, emitterNode, quadScene, quadNode;
  57. // rendertargets
  58. var rtNormals, rtDepth, rtLightBuffer, rtEmitter;
  59. // composer
  60. var compNormals, compDepth, compLightBuffer, compFinal, compEmitter, compositePass;
  61. // materials
  62. var matNormal, matClipDepth, matBasic, matUnlit;
  63. var numLights = 0;
  64. var lights = new Array();
  65. // -----------------------
  66. // shader definitions
  67. // -----------------------
  68. var clipdepth_frag = ""+
  69. "varying vec4 clipPos;"+
  70. "void main() {"+
  71. "gl_FragColor = vec4(clipPos.z / clipPos.w, 1.0, 1.0, 1.0);"+
  72. "}";
  73. var clipdepth_vert = "" +
  74. "varying vec4 clipPos;"+
  75. "void main() {"+
  76. "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );"+
  77. "clipPos = gl_Position;"+
  78. "}";
  79. // -----------------------
  80. var normals_vert = "" +
  81. "varying vec3 normalView;"+
  82. "void main() {"+
  83. "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );"+
  84. "normalView = normalize(normalMatrix * normal);"+
  85. "}";
  86. var normals_frag = "" +
  87. "varying vec3 normalView;"+
  88. "void main() {"+
  89. "gl_FragColor = vec4(vec3(normalView * 0.5 + 0.5), 1.0);"+
  90. "}";
  91. // -----------------------
  92. var unlit_vert = "" +
  93. "varying vec4 clipPos;"+
  94. "void main() {"+
  95. "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );"+
  96. "clipPos = gl_Position;"+
  97. "}";
  98. var unlit_frag = "" +
  99. "varying vec4 clipPos;"+
  100. "uniform sampler2D samplerDepth;"+
  101. "uniform float viewHeight;"+
  102. "uniform float viewWidth;"+
  103. "uniform vec3 lightColor;" +
  104. "void main() {"+
  105. "vec2 texCoord = gl_FragCoord.xy / vec2(viewWidth, viewHeight);"+
  106. "float z = texture2D(samplerDepth, texCoord).x;"+
  107. "vec4 color = vec4(lightColor, 1.0);"+
  108. "float depth = (clipPos.z/clipPos.w);"+
  109. "if(depth > z && z > 0.0) color.w = 0.0;"+
  110. "gl_FragColor = color;"+
  111. "}";
  112. // -----------------------
  113. var deferredlight_vert = "" +
  114. "varying vec3 lightView;" +
  115. "uniform vec3 lightPos;" +
  116. "uniform mat4 matView;" +
  117. "void main()" +
  118. "{" +
  119. "gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.),lightView=vec3(matView*vec4(lightPos,1.));" +
  120. "}"
  121. var deferredlight_frag = "" +
  122. "varying vec3 lightView;"+
  123. "uniform sampler2D samplerDepth;"+
  124. "uniform sampler2D samplerNormals;"+
  125. "uniform sampler2D samplerLightBuffer;"+
  126. "uniform float lightRadius;"+
  127. "uniform float lightIntensity;"+
  128. "uniform float viewHeight;"+
  129. "uniform float viewWidth;"+
  130. "uniform vec3 lightColor;"+
  131. "uniform mat4 matProjInverse;"+
  132. "void main()"+
  133. "{"+
  134. "vec2 texCoord = gl_FragCoord.xy / vec2(viewWidth, viewHeight);"+
  135. "float z = texture2D(samplerDepth, texCoord).x;"+
  136. "if(z == 0.0)"+
  137. "{"+
  138. "gl_FragColor = vec4(vec3(0.0), 1.0);"+
  139. "return;"+
  140. "}"+
  141. "float x = texCoord.x * 2.0 - 1.0;"+
  142. "float y = texCoord.y * 2.0 - 1.0;"+
  143. "vec4 projectedPos = vec4(x, y, z, 1.0);"+
  144. "vec4 viewPos = matProjInverse * projectedPos;"+
  145. "viewPos.xyz /= viewPos.w;"+
  146. "viewPos.w = 1.0;"+
  147. "vec3 lightDir = lightView - viewPos.xyz;"+
  148. "float dist = length(lightDir);"+
  149. "float cutoff = 0.3;"+
  150. "float denom = dist/lightRadius + 1.0;"+
  151. "float attenuation = 1.0 / (denom*denom);"+
  152. "attenuation = (attenuation - cutoff) / (1.0 - cutoff);"+
  153. "attenuation = max(attenuation, 0.0);"+
  154. "vec3 normal = texture2D( samplerNormals, texCoord).xyz * 2.0 - 1.0;" +
  155. "float diffuse = max(dot(normal, normalize(lightDir)), 0.0);" +
  156. "vec4 color = vec4(0.0);"+
  157. "color.xyz = lightColor * lightIntensity;"+
  158. "color.w = attenuation;"+
  159. "gl_FragColor = color * diffuse;"+
  160. "}";
  161. var composite_vert = "" +
  162. "varying vec2 texCoord;"+
  163. "void main() {"+
  164. "vec4 pos = vec4(sign(position.xy),0.0,1.0);"+
  165. "texCoord=pos.xy*vec2(0.5,0.5)+0.5;"+
  166. "gl_Position = pos;"+
  167. "}";
  168. var composite_frag = "" +
  169. "varying vec2 texCoord;"+
  170. "uniform sampler2D samplerLightBuffer;" +
  171. "uniform sampler2D samplerEmitter;" +
  172. "uniform vec3 lightPos;" +
  173. "void main()" +
  174. "{" +
  175. "vec3 color = texture2D(samplerLightBuffer, texCoord).xyz;" +
  176. "vec3 emitter = texture2D(samplerEmitter, texCoord).xyz;"+
  177. "if(emitter != vec3(0.0)){"+
  178. "gl_FragColor = vec4(emitter, 1.0);" +
  179. "}"+
  180. "else{"+
  181. "gl_FragColor = vec4(color, 1.0);}" +
  182. "}"
  183. // -----------------------
  184. var normalShader = {
  185. uniforms: {},
  186. vertexShader: normals_vert,
  187. fragmentShader: normals_frag
  188. };
  189. // -----------------------
  190. var clipDepthShader = {
  191. uniforms: {},
  192. vertexShader: clipdepth_vert,
  193. fragmentShader: clipdepth_frag
  194. };
  195. // -----------------------
  196. var unlitShader = {
  197. uniforms: {
  198. samplerDepth: { type: "t", value: 0, texture: null },
  199. viewWidth: { type: "f", value: WIDTH},
  200. viewHeight: { type: "f", value: HEIGHT},
  201. lightColor: { type: "v3", value: new THREE.Vector3( 0, 0, 0 )}
  202. },
  203. vertexShader: unlit_vert,
  204. fragmentShader: unlit_frag
  205. };
  206. // -----------------------
  207. var lightShader = {
  208. uniforms: {
  209. samplerLightBuffer: { type: "t", value: 0, texture: null },
  210. samplerNormals: { type: "t", value: 1, texture: null },
  211. samplerDepth: { type: "t", value: 2, texture: null },
  212. matView : { type: "m4", value: new THREE.Matrix4()},
  213. matProjInverse : { type: "m4", value: new THREE.Matrix4()},
  214. viewWidth: { type: "f", value: WIDTH},
  215. viewHeight: { type: "f", value: HEIGHT},
  216. lightPos: { type: "v3", value: new THREE.Vector3( 0, 0, 0 )},
  217. lightColor: { type: "v3", value: new THREE.Vector3( 0, 0, 0 )},
  218. lightIntensity: { type: "f", value: 1.0},
  219. lightRadius: { type: "f", value: 1.0}
  220. },
  221. vertexShader: deferredlight_vert,
  222. fragmentShader: deferredlight_frag
  223. };
  224. // -----------------------
  225. var compositeShader = {
  226. uniforms: {
  227. samplerLightBuffer: { type: "t", value: 0, texture: null },
  228. samplerEmitter: { type: "t", value: 1, texture: null }
  229. },
  230. vertexShader: composite_vert,
  231. fragmentShader: composite_frag
  232. };
  233. // -----------------------------
  234. function bootstrap()
  235. {
  236. renderer = new THREE.WebGLRenderer();
  237. renderer.setSize(WIDTH, HEIGHT);
  238. renderer.setClearColorHex(0x000000);
  239. var container = document.getElementById( 'container' );
  240. container.appendChild(renderer.domElement);
  241. // scene camera and shadow camera
  242. camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
  243. camera.position.z = 150;
  244. controls = new THREE.TrackballControls( camera, renderer.domElement );
  245. // scene for walt's head model
  246. scene = new THREE.Scene();
  247. sceneNode = new THREE.Object3D();
  248. scene.add(sceneNode);
  249. scene.add(camera);
  250. // scene for light proxy geometry
  251. lightScene = new THREE.Scene();
  252. lightNode = new THREE.Object3D();
  253. lightScene.add(lightNode);
  254. // scene for the coloured emitter spheres
  255. emitterScene = new THREE.Scene();
  256. emitterNode = new THREE.Object3D();
  257. emitterScene.add(emitterNode);
  258. // full screen quad for compositing
  259. quadScene = new THREE.Scene();
  260. quadNode = new THREE.Object3D();
  261. quadScene.add(quadNode);
  262. quadNode.add(new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 )));
  263. // stats
  264. stats = new Stats();
  265. stats.domElement.style.position = 'absolute';
  266. stats.domElement.style.top = '8px';
  267. stats.domElement.style.zIndex = 100;
  268. container.appendChild( stats.domElement );
  269. // clock
  270. clock = new THREE.Clock();
  271. }
  272. // -----------------------------
  273. function createRenderTargets(){
  274. var rtParams = {minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter,
  275. format: THREE.RGBAFormat, type:THREE.FloatType};
  276. // ----------------------------------------------------------
  277. // g-buffer
  278. // ----------------------------------------------------------
  279. rtNormals = new THREE.WebGLRenderTarget( WIDTH, HEIGHT, rtParams );
  280. rtDepth = new THREE.WebGLRenderTarget( WIDTH, HEIGHT, rtParams );
  281. var passNormals = new THREE.RenderPass( scene, camera);
  282. compNormals = new THREE.EffectComposer( renderer, rtNormals );
  283. compNormals.addPass(passNormals );
  284. var passDepth = new THREE.RenderPass( scene, camera);
  285. compDepth = new THREE.EffectComposer( renderer, rtDepth );
  286. compDepth.addPass( passDepth );
  287. // ----------------------------------------------------------
  288. // light emitter spheres
  289. // ----------------------------------------------------------
  290. var emitterPass = new THREE.RenderPass( emitterScene, camera);
  291. rtEmitter = new THREE.WebGLRenderTarget( WIDTH, HEIGHT, rtParams );
  292. compEmitter = new THREE.EffectComposer( renderer, rtEmitter);
  293. compEmitter.addPass( emitterPass );
  294. // ----------------------------------------------------------
  295. // lighting pass
  296. // ----------------------------------------------------------
  297. rtLightBuffer = new THREE.WebGLRenderTarget( WIDTH, HEIGHT, rtParams );
  298. rtLightBuffer.generateMipmaps = false;
  299. var passLight = new THREE.RenderPass( lightScene, camera);
  300. compLightBuffer = new THREE.EffectComposer( renderer, rtLightBuffer );
  301. compLightBuffer.addPass(passLight);
  302. lightShader.uniforms['samplerNormals'].texture = compNormals.renderTarget2;
  303. lightShader.uniforms['samplerDepth'].texture = compDepth.renderTarget2;
  304. lightShader.uniforms['samplerLightBuffer'].texture = rtLightBuffer;
  305. for(var x = 0; x < numLights; x++){
  306. // setup material
  307. var matLight = new THREE.ShaderMaterial({
  308. uniforms: THREE.UniformsUtils.clone( lightShader.uniforms ),
  309. vertexShader: lightShader.vertexShader,
  310. fragmentShader: lightShader.fragmentShader
  311. });
  312. matLight.blending = THREE.AdditiveBlending;
  313. matLight.transparent = true;
  314. matLight.depthWrite = false;
  315. matLight.uniforms["lightPos"].value = lights[x].position;
  316. matLight.uniforms["lightRadius"].value = lights[x].distance;
  317. matLight.uniforms["lightIntensity"].value = lights[x].intensity;
  318. matLight.uniforms["lightColor"].value = lights[x].color;
  319. // setup proxy geometry for this light
  320. var geomLight = new THREE.SphereGeometry(lights[x].distance, 10, 10);
  321. var meshLight = new THREE.Mesh(geomLight, matLight);
  322. lightNode.add(meshLight);
  323. // create emitter sphere
  324. var geomEmitter = new THREE.SphereGeometry(0.7, 7, 7);
  325. var matEmitter = new THREE.ShaderMaterial({
  326. uniforms: THREE.UniformsUtils.clone( unlitShader.uniforms ),
  327. vertexShader: unlitShader.vertexShader,
  328. fragmentShader: unlitShader.fragmentShader
  329. });
  330. var meshEmitter = new THREE.Mesh(geomEmitter, matEmitter);
  331. meshEmitter.position = lights[x].position;
  332. emitterNode.add(meshEmitter);
  333. // add emitter to light node
  334. meshLight.emitter = meshEmitter;
  335. }
  336. // ----------------------------------------------------------
  337. // composite
  338. // ----------------------------------------------------------
  339. compositeShader.uniforms['samplerLightBuffer'].texture = compLightBuffer.renderTarget2;
  340. compositeShader.uniforms['samplerEmitter'].texture = compEmitter.renderTarget2;
  341. compositePass = new THREE.ShaderPass( compositeShader );
  342. compositePass.needsSwap = true;
  343. compositePass.renderToScreen = true;
  344. compFinal = new THREE.EffectComposer( renderer, quadScene );
  345. compFinal.addPass( compositePass );
  346. }
  347. // -----------------------------
  348. function initScene(geometry){
  349. geometry.computeVertexNormals();
  350. var meshHead = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial());
  351. meshHead.position.y = -35;
  352. sceneNode.add(meshHead);
  353. }
  354. // -----------------------------
  355. function initMaterials(){
  356. //
  357. matNormal = new THREE.ShaderMaterial({
  358. uniforms: normalShader.uniforms,
  359. vertexShader: normalShader.vertexShader,
  360. fragmentShader: normalShader.fragmentShader
  361. });
  362. matClipDepth = new THREE.ShaderMaterial({
  363. uniforms: clipDepthShader.uniforms,
  364. vertexShader: clipDepthShader.vertexShader,
  365. fragmentShader: clipDepthShader.fragmentShader
  366. });
  367. }
  368. // -----------------------------
  369. function initLights(){
  370. var tmp = new THREE.PointLight();
  371. tmp.color = new THREE.Vector3( 0.0, 0.0, 1.0);
  372. tmp.intensity = 1.0;
  373. tmp.distance = 50;
  374. lights[0] = tmp;
  375. var tmp = new THREE.PointLight();
  376. tmp.color = new THREE.Vector3( 0.0, 1.0, 0.0);
  377. tmp.intensity = 1.0;
  378. tmp.distance = 50;
  379. lights[1] = tmp;
  380. var tmp = new THREE.PointLight();
  381. tmp.color = new THREE.Vector3( 1.0, 0.0, 0.0);
  382. tmp.intensity = 1.0;
  383. tmp.distance = 50;
  384. lights[2] = tmp;
  385. var tmp = new THREE.PointLight();
  386. tmp.color = new THREE.Vector3( 0.0, 1.0, 1.0);
  387. tmp.intensity = 1.0;
  388. tmp.distance = 50;
  389. lights[3] = tmp;
  390. numLights = 4;
  391. }
  392. // -----------------------------
  393. function animate()
  394. {
  395. requestAnimFrame(animate);
  396. controls.update();
  397. stats.update();
  398. render();
  399. }
  400. // -----------------------------
  401. function render()
  402. {
  403. // -----------------------------
  404. // g-buffer depth
  405. for(var idx in sceneNode.children)
  406. {
  407. var tmp = sceneNode.children[idx];
  408. tmp.material = matClipDepth;
  409. }
  410. compDepth.render();
  411. // -----------------------------
  412. // g-buffer normals
  413. for(var idx in sceneNode.children)
  414. {
  415. var tmp = sceneNode.children[idx];
  416. tmp.material = matNormal;
  417. }
  418. compNormals.render();
  419. // -----------------------------
  420. // emitter pass
  421. for(var idx in lightNode.children)
  422. {
  423. var light = lightNode.children[idx];
  424. var color = light.material.uniforms["lightColor"].value;
  425. var emitter = light.emitter;
  426. emitter.material.uniforms['samplerDepth'].texture = compDepth.renderTarget2;
  427. emitter.material.uniforms["lightColor"].value = color;
  428. }
  429. compEmitter.render();
  430. // -----------------------------
  431. // light pass
  432. for(var idx in lightNode.children)
  433. {
  434. camera.projectionMatrixInverse.getInverse(camera.projectionMatrix);
  435. lightNode.children[idx].material.uniforms["matProjInverse"].value = camera.projectionMatrixInverse;
  436. lightNode.children[idx].material.uniforms["matView"].value = camera.matrixWorldInverse;
  437. }
  438. var time = Date.now() * 0.0005;
  439. // update lights
  440. var lightPosition = lightNode.children[0].material.uniforms["lightPos"].value;
  441. lightPosition.x = Math.sin( time * 0.7 ) * 30;
  442. lightPosition.y = Math.cos( time * 0.5 ) * 40;
  443. lightPosition.z = Math.cos( time * 0.3 ) * 30;
  444. lightNode.children[0].emitter.position = lightPosition;
  445. lightPosition = lightNode.children[1].material.uniforms["lightPos"].value;
  446. lightPosition.x = Math.sin( time * 0.5 ) * 30;
  447. lightPosition.y = Math.cos( time * 0.5 ) * 40;
  448. lightPosition.z = Math.cos( time * 0.7 ) * 30;
  449. lightNode.children[1].emitter.position = lightPosition;
  450. lightPosition = lightNode.children[2].material.uniforms["lightPos"].value;
  451. lightPosition.x = Math.sin( time * 0.7 ) * 30;
  452. lightPosition.y = Math.cos( time * 0.3 ) * 40;
  453. lightPosition.z = Math.cos( time * 0.5 ) * 30;
  454. lightNode.children[2].emitter.position = lightPosition;
  455. lightPosition = lightNode.children[3].material.uniforms["lightPos"].value;
  456. lightPosition.x = Math.sin( time * 0.3 ) * 30;
  457. lightPosition.y = Math.cos( time * 0.7 ) * 40;
  458. lightPosition.z = Math.cos( time * 0.5 ) * 30;
  459. lightNode.children[3].emitter.position = lightPosition;
  460. compLightBuffer.render();
  461. // -----------------------------
  462. // composite pass
  463. compFinal.render();
  464. }
  465. // -----------------------------
  466. // entry point
  467. var binLoader = new THREE.BinaryLoader();
  468. binLoader.load( "assets/models/waltdisney.js", function(geometry) {
  469. bootstrap();
  470. initScene(geometry);
  471. initMaterials();
  472. initLights();
  473. createRenderTargets();
  474. animate();
  475. });
  476. </script>
  477. </html>
粤ICP备19079148号