├── .gitignore ├── 100-intro.md ├── 200-setup-and-gamma-notes.md ├── 200-setup-and-gamma.md ├── 201-init └── main.js ├── 202-lambert-diffuse ├── Material.frag ├── Material.vert └── main.js ├── 203-gamma ├── Material.frag ├── Material.vert └── main.js ├── 204-gamma-color ├── Material.frag ├── Material.vert └── main.js ├── 205-gamma-texture ├── Material.frag ├── Material.vert └── main.js ├── 206-gamma-ext-srgb ├── Material.frag ├── Material.vert └── main.js ├── 300-cubemap-anim └── main.js ├── 300-hdr-histogram └── main.js ├── 300-hdr.md ├── 301-load-cubemap ├── Reflection.frag ├── Reflection.vert ├── Skybox.frag ├── Skybox.vert ├── main.js └── mainNoDebug.js ├── 301-reflections └── main.js ├── 302-load-equirect ├── Reflection.frag ├── Reflection.vert ├── Skybox.frag ├── Skybox.vert └── main.js ├── 303-fullscreenquad-skybox ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert ├── SkyboxQuadDebug.vert └── main.js ├── 304-load-hdr ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert └── main.js ├── 305-exposure-basic ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert └── main.js ├── 306-tonemap-reinhard ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert └── main.js ├── 307-tonemap-compare ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert ├── main.js └── mainObj.js ├── 308-exposure-camera ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert └── main.js ├── 400-hammersley-point-set └── main.js ├── 400-realtime-filtering ├── README.md ├── Reflection.frag ├── Reflection.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert ├── hammersley.js ├── hammersleyTest.js ├── main.js └── rays.js ├── 500-pbr ├── PBRImportanceSampled.js ├── PBRMaterial.js ├── UberMaterial.js ├── glsl │ ├── PBR.frag │ ├── PBR.vert │ ├── PBRImportanceSampled.frag │ ├── PBRImportanceSampled.vert │ ├── ShowColors.frag │ ├── ShowColors.vert │ ├── ShowNormals.frag │ ├── ShowNormals.vert │ ├── SkyboxQuad.frag │ ├── SkyboxQuad.vert │ ├── SolidColor.frag │ ├── SolidColor.vert │ ├── SpecularCookTorrance.frag │ ├── SpecularCookTorrance.vert │ ├── SpecularGGX.frag │ ├── SpecularGGX.vert │ ├── SpecularPhong.frag │ ├── SpecularPhong.vert │ ├── UberShader.frag │ └── UberShader.vert └── main.js ├── 501-pbr-textured ├── PBR.frag ├── PBR.vert ├── PBRMaterial.js ├── ShowColors.frag ├── ShowColors.vert ├── SkyboxQuad.frag ├── SkyboxQuad.vert └── main.js ├── README.md ├── assets ├── brdf │ └── lut.png ├── envmaps │ ├── pisa.txt │ ├── pisa_latlong_256.hdr │ ├── pisa_negx.jpg │ ├── pisa_negy.jpg │ ├── pisa_negz.jpg │ ├── pisa_posx.jpg │ ├── pisa_posy.jpg │ ├── pisa_posz.jpg │ ├── pisa_preview.jpg │ ├── test.jpg │ ├── test.txt │ ├── test_nx.png │ ├── test_ny.png │ ├── test_nz.png │ ├── test_px.png │ ├── test_py.png │ └── test_pz.png ├── glsl │ ├── Basic.frag │ ├── Basic.vert │ ├── ShowColors.frag │ ├── ShowColors.vert │ ├── ShowNormals.frag │ └── ShowNormals.vert ├── html │ └── index.template.html ├── models │ ├── blob.obj │ ├── dragon.obj │ └── dragon.txt └── textures │ ├── Pink_tile_pxr128.jpg │ └── Pink_tile_pxr128.txt ├── build_all.sh ├── img ├── 100_bunny_env3.jpg ├── 100_demo_exposure.jpg ├── 100_demo_materials.jpg ├── 100_demo_mixing.jpg ├── 100_dielectric_roughness_sml.jpg ├── 100_exploded_cube.jpg ├── 100_exploded_cube_thumb.jpg ├── 100_frame_stages.jpg ├── 100_materials3x2.jpg ├── 100_metal_roughness_sml.jpg ├── 200.jpg ├── 201.jpg ├── 202.jpg ├── 202_angles.jpg ├── 202_lambert_diffuse.jpg ├── 202_transformation_spaces.jpg ├── 203.jpg ├── 203_gamma_graph.png ├── 203_gamma_graph.txt ├── 203_gamma_moon.png ├── 203_gamma_moon.txt ├── 203_gamma_video.jpg ├── 204.jpg ├── 204_comparison.jpg ├── 205.jpg ├── 205_pixar_textures.jpg ├── 205_pixar_textures.txt ├── 206_incorrect.jpg ├── 300.jpg ├── 300_hdr.jpg ├── 301_cube_anim.gif ├── 301_cube_cross_and_debug.jpg ├── 301_cube_faces.jpg ├── 301_cube_faces_debug.png ├── 301_cube_orientation.png ├── 301_load_cubemap.jpg ├── 301_pisa_streetview.jpg ├── 301_reflection_angle.png ├── 301_reflections.png ├── 302_latlong_and_debug.jpg ├── 302_latlong_sampler.png ├── 303_fullscreen_quad.jpg ├── 304_banding.jpg ├── 304_load_hdr.jpg ├── 305_exposure_basic.jpg ├── 306_tonemap.jpg ├── 306_tonemap_func.png ├── 306_tonemap_reinhard.jpg ├── 307_tonemap_compare.jpg └── 308_exposure_camera.jpg ├── local_modules ├── convolve-cubemap │ ├── glsl │ │ ├── convolve.frag │ │ └── convolve.vert │ ├── index.js │ └── package.json ├── cubemap-to-octmap │ ├── glsl │ │ ├── CubemapToOctmap.frag │ │ └── CubemapToOctmap.vert │ ├── index.js │ └── test.js ├── downsample-cubemap │ ├── glsl │ │ ├── downsample.frag │ │ └── downsample.vert │ ├── index.js │ └── package.json ├── envmap-to-cubemap │ ├── glsl │ │ ├── SkyboxQuad.frag │ │ └── SkyboxQuad.vert │ ├── index.js │ └── package.json ├── geom-center-and-resize │ ├── .gitignore │ ├── .npmignore │ ├── LICENSE.md │ ├── README.md │ ├── index.js │ └── package.json ├── geom-compute-normals │ ├── index.js │ └── package.json ├── geom-parse-obj │ └── index.js ├── geom-subdivide-triangles │ └── index.js ├── geom-to-flat-geometry │ └── index.js ├── geom-triangulate │ ├── index.js │ └── package.json ├── glsl-envmap-cube │ └── index.glsl ├── glsl-envmap-equirect │ └── index.glsl ├── glsl-rgbe2rgb │ └── index.glsl ├── glsl-sky │ └── index.glsl ├── glsl-tonemap-filmic │ └── index.glsl ├── glsl-tonemap-reinhard │ └── index.glsl ├── glsl-tonemap-uncharted2 │ └── index.glsl ├── parse-hdr │ ├── package.json │ └── parse-hdr.js ├── prefilter-cubemap │ ├── glsl │ │ ├── prefilter.frag │ │ └── prefilter.vert │ ├── index.js │ └── package.json ├── prefilter-octmap │ ├── glsl │ │ ├── PrefilterOctmap.frag │ │ └── PrefilterOctmap.vert │ └── index.js ├── primitive-icosahedron │ └── index.js ├── primitive-octahedron │ └── index.js └── render-to-cubemap │ └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .atom-build.json 4 | index.html 5 | main.web.js 6 | *-orig 7 | *-old 8 | temp 9 | -------------------------------------------------------------------------------- /200-setup-and-gamma-notes.md: -------------------------------------------------------------------------------- 1 | # Gamma correction and linear space 2 | 3 | #### [The Importance of Being Linear](http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html) from GPU Gems 3 4 | 5 | > The automatic sRGB corrections are free and are preferred to performing the corrections manually in a shader after each texture access, as shown in Listing 24-1, because each pow instruction is scalar and expanded to two instructions. Also, manual correction happens after filtering, which is incorrectly performed in a nonlinear space. 6 | 7 | #### [Linear-Space Lighting (i.e. Gamma)](http://filmicgames.com/archives/299) 2010 8 | 9 | #### [EXT_sRGB](https://www.khronos.org/registry/webgl/extensions/EXT_sRGB) 10 | 11 | > The sRGB color space is based on typical (non-linear) 12 | 13 | According to [WebGL Report](http://webglreport.com/?v=1) supported in: 14 | 15 | - [x] Chrome 43+ on OSX 16 | - [x] Firefox 39+ on OSX 17 | - [x] Webkit Nighly r186719 on OSX 18 | - [ ] Safari 8.0.7 on OSX 19 | 20 | EXT_sRGB will be in core WebGL 2.0 21 | 22 | #### [Udacity Interactive 3D Graphics: Gamma Correction ](https://www.udacity.com/course/viewer#!/c-cs291/l-124106597/m-176585829) 2013? 23 | 24 | ``` 25 | renderer.gammaInput = true 26 | renderer.gammaOutput = true 27 | ``` 28 | 29 | 30 | #### [ThreeJS: Improving correctness of gamma application](https://github.com/mrdoob/three.js/issues/5838) 2014 31 | #### [ThreeJS: Texture encoding example code, and thoughts on a correct implementation](https://github.com/mrdoob/three.js/issues/6593) 2015 32 | 33 | ``` 34 | THREE.Linear = 3000; 35 | THREE.sRGB = 3001; 36 | THREE.RGBE = 3002; 37 | THREE.LogLuv = 3003; 38 | ``` 39 | 40 | # sRGB 41 | 42 | SRGB in WebGL (core in WebGL 2.0) is enabled through 43 | [EXT_sRGB](https://www.khronos.org/registry/gles/extensions/EXT/EXT_sRGB.txt) 44 | 45 | Which is based on 46 | [ARB_framebuffer_sRGB](https://www.opengl.org/registry/specs/ARB/framebuffer_sRGB.txt) 47 | [EXT_texture_sRGB](https://www.opengl.org/registry/specs/EXT/texture_sRGB.txt) 48 | 49 | 50 | # Other 51 | 52 | http://www.pauldebevec.com/Probes/ 53 | http://gl.ict.usc.edu/Data/HighResProbes/ 54 | 55 | [Gamma correct and HDR rendering in a 32 bits buffer](http://lousodrome.net/blog/light/tag/rgbm/) 56 | 57 | 58 | http://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/ ?? 59 | http://d.hatena.ne.jp/hanecci/20120108 ?? 60 | -------------------------------------------------------------------------------- /201-init/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | 3 | var frame = 0; 4 | 5 | Window.create({ 6 | settings: { 7 | width: 1024, 8 | height: 576 9 | }, 10 | draw: function() { 11 | var ctx = this.getContext(); 12 | frame++; 13 | var r = 0.5 + 0.5 * Math.sin(frame/10); 14 | var g = 0.5 + 0.5 * Math.cos(frame/10 + Math.PI/2); 15 | var b = 0.5 + 0.5 * Math.sin(frame/10 + Math.PI/4); 16 | ctx.setClearColor(r, g, b, 1.0); 17 | ctx.clear(ctx.COLOR_BIT); 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /202-lambert-diffuse/Material.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | //require the lambert diffuse formula from a module via glslify 6 | #pragma glslify: lambert = require(glsl-diffuse-lambert) 7 | 8 | //vertex position, normal and light position in the eye/view space 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | varying vec3 ecLightPos; 12 | 13 | 14 | void main() { 15 | //normalize the normal, we do it here instead of vertex 16 | //shader for smoother gradients 17 | vec3 N = normalize(ecNormal); 18 | 19 | //calculate direction towards the light 20 | vec3 L = normalize(ecLightPos - ecPosition); 21 | 22 | //diffuse intensity 23 | float Id = lambert(L, N); 24 | 25 | //surface and light color, full white 26 | vec4 baseColor = vec4(1.0); 27 | vec4 lightColor = vec4(1.0); 28 | 29 | vec4 finalColor = vec4(baseColor.rgb * lightColor.rgb * Id, 1.0); 30 | gl_FragColor = finalColor; 31 | } 32 | -------------------------------------------------------------------------------- /202-lambert-diffuse/Material.vert: -------------------------------------------------------------------------------- 1 | //vertex position in the model space 2 | attribute vec4 aPosition; 3 | //vertex normal in the model space 4 | attribute vec3 aNormal; 5 | 6 | //current transformation matrices coming from the Context 7 | uniform mat4 uProjectionMatrix; 8 | uniform mat4 uViewMatrix; 9 | uniform mat4 uModelMatrix; 10 | uniform mat3 uNormalMatrix; 11 | 12 | //user supplied light position 13 | uniform vec3 uLightPos; 14 | 15 | //vertex position in the eye coordinates (view space) 16 | varying vec3 ecPosition; 17 | //normal in the eye coordinates (view space) 18 | varying vec3 ecNormal; 19 | //light position in the eye coordinates (view space) 20 | varying vec3 ecLightPos; 21 | 22 | void main() { 23 | //transform vertex into the eye space 24 | vec4 pos = uViewMatrix * uModelMatrix * aPosition; 25 | ecPosition = pos.xyz; 26 | ecNormal = uNormalMatrix * aNormal; 27 | 28 | ecLightPos = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos, 1.0)); 29 | 30 | //project the vertex, the rest is handled by WebGL 31 | gl_Position = uProjectionMatrix * pos; 32 | } 33 | -------------------------------------------------------------------------------- /202-lambert-diffuse/main.js: -------------------------------------------------------------------------------- 1 | //Import all the dependencies 2 | var Window = require('pex-sys/Window'); 3 | var Mat4 = require('pex-math/Mat4'); 4 | var Vec3 = require('pex-math/Vec3'); 5 | var glslify = require('glslify-promise'); 6 | var createSphere = require('primitive-sphere'); 7 | 8 | //Create window - in the borwser this will: 9 | //- create new Canvas element with width/height specified in the `settings` 10 | //- append it to 11 | //- get WebGL context 12 | //- add event listeners for mouse and keyboard events 13 | //- load all requested resources 14 | //- call init() 15 | //- keep calling draw() using Window.requestAnimationFrame() 16 | Window.create({ 17 | //Window / canvas properties 18 | settings: { 19 | width: 1024, 20 | height: 576 21 | }, 22 | //Files (text, json, glsl vis glslify, images) to load before init 23 | resources: { 24 | vert: { glsl: glslify(__dirname + '/Material.vert') }, 25 | frag: { glsl: glslify(__dirname + '/Material.frag') } 26 | }, 27 | //Init is called after creating WebGL context and successfuly loading all the resources 28 | init: function() { 29 | //pex-context/Context object - the pex's WebGL context wrapper 30 | var ctx = this.getContext(); 31 | 32 | //Model transformation matrix 33 | //An Array with 16 numbers initialized to an identity matrix 34 | this.model = Mat4.create(); 35 | 36 | //Camera projection matrix 37 | this.projection = Mat4.perspective( 38 | Mat4.create(), //new matrix 39 | 45, //45' deg fov 40 | this.getAspectRatio(), //window aspect ratio width/height 41 | 0.001, //near clipping plane 42 | 10.0 //far clipping plane 43 | ); 44 | 45 | //Camera view matrix 46 | this.view = Mat4.create(); 47 | //[0,1,5] - eye position 48 | //[0,0,0] - target position 49 | //[0,1,0] - camera up vector 50 | Mat4.lookAt(this.view, [0, 1, 5], [0, 0, 0], [0, 1, 0]); 51 | 52 | //The Context keeps a separate matrix stack for the projection, 53 | //view and model matrix. Additionaly it will compute normal matrix 54 | //and inverse view matrix whenever view matrix changes 55 | ctx.setProjectionMatrix(this.projection); 56 | ctx.setViewMatrix(this.view); 57 | ctx.setModelMatrix(this.model); 58 | 59 | //Get reference to all loaded resources 60 | var res = this.getResources(); 61 | 62 | //Each resource of type `glsl` will be replace by string with the loaded GLSL code 63 | //We can use that code to create a WebGL Program object 64 | this.program = ctx.createProgram(res.vert, res.frag); 65 | 66 | //Create sphere geometry - an object with positions, normals and cells/faces 67 | var g = createSphere(); 68 | 69 | //Define mesh attribute layout 70 | //ATTRIB_POSITION and ATTRIB_NORMAL are slot numbers 71 | //matching attributes in the shader aPosition and aNormal 72 | var attributes = [ 73 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 74 | { data: g.normals, location: ctx.ATTRIB_NORMAL } 75 | ]; 76 | 77 | //Define vertices data 78 | var indices = { data: g.cells }; 79 | 80 | //Create mesh to be rendered as a list of TRIANGLEs 81 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 82 | }, 83 | //This function is called as close as possible to 60fps via requestAnimationFrame 84 | draw: function() { 85 | var ctx = this.getContext(); 86 | 87 | //Set gl clear color to dark grey 88 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 89 | 90 | //Clear the color and depth buffers 91 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 92 | 93 | //Enable depth testing 94 | ctx.setDepthTest(true); 95 | 96 | //Activate our GLSL program 97 | ctx.bindProgram(this.program); 98 | 99 | //Set the light's position uniform 100 | //There is no need to set matrix uniforms like uProjectionMatrix as 101 | //these are handled by the context. List of all handled uniforms is 102 | //in pex-context/ProgramUniform.js 103 | this.program.setUniform('uLightPos', [10, 10, 10]) 104 | 105 | //Activate the sphere mesh 106 | ctx.bindMesh(this.mesh); 107 | 108 | //Draw the currently active mesh (sphere in this example) 109 | ctx.drawMesh(); 110 | } 111 | }) 112 | -------------------------------------------------------------------------------- /203-gamma/Material.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | //require the lambert diffuse formula from a module via glslify 6 | #pragma glslify: lambert = require(glsl-diffuse-lambert) 7 | 8 | //glsl-gamma module exports two functions that we can import separately 9 | #pragma glslify: toLinear = require(glsl-gamma/in) 10 | #pragma glslify: toGamma = require(glsl-gamma/out) 11 | 12 | //vertex position, normal and light position in the eye/view space 13 | varying vec3 ecPosition; 14 | varying vec3 ecNormal; 15 | varying vec3 ecLightPos; 16 | 17 | float PI = 3.14159265; 18 | 19 | void main() { 20 | vec3 N = normalize(ecNormal); 21 | vec3 L = normalize(ecLightPos - ecPosition); 22 | 23 | //diffuse intensity 24 | float Id = lambert(L, N); 25 | 26 | //surface and light color, full white 27 | vec4 baseColor = toLinear(vec4(1.0)); 28 | vec4 lightColor = toLinear(vec4(1.0)); 29 | 30 | vec4 finalColor = vec4(baseColor.rgb * lightColor.rgb * Id, 1.0); 31 | gl_FragColor = toGamma(finalColor); 32 | } 33 | -------------------------------------------------------------------------------- /203-gamma/Material.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | uniform vec3 uLightPos; 10 | 11 | //vertex position, normal and light position in the eye/view space 12 | varying vec3 ecPosition; 13 | varying vec3 ecNormal; 14 | varying vec3 ecLightPos; 15 | 16 | void main() { 17 | vec4 pos = uViewMatrix * uModelMatrix * aPosition; 18 | ecPosition = pos.xyz; 19 | ecNormal = uNormalMatrix * aNormal; 20 | 21 | ecLightPos = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos, 1.0)); 22 | 23 | gl_Position = uProjectionMatrix * pos; 24 | } 25 | -------------------------------------------------------------------------------- /203-gamma/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | 7 | Window.create({ 8 | settings: { 9 | width: 1024, 10 | height: 576 11 | }, 12 | resources: { 13 | vert: { glsl: glslify(__dirname + '/Material.vert') }, 14 | frag: { glsl: glslify(__dirname + '/Material.frag') } 15 | }, 16 | init: function() { 17 | var ctx = this.getContext(); 18 | 19 | this.model = Mat4.create(); 20 | this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0); 21 | this.view = Mat4.lookAt([], [0, 1, 5], [0, 0, 0], [0, 1, 0]); 22 | 23 | ctx.setProjectionMatrix(this.projection); 24 | ctx.setViewMatrix(this.view); 25 | ctx.setModelMatrix(this.model); 26 | 27 | var res = this.getResources(); 28 | 29 | this.program = ctx.createProgram(res.vert, res.frag); 30 | 31 | var g = createSphere(); 32 | 33 | var attributes = [ 34 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 35 | { data: g.normals, location: ctx.ATTRIB_NORMAL } 36 | ]; 37 | var indices = { data: g.cells, usage: ctx.STATIC_DRAW }; 38 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 39 | }, 40 | draw: function() { 41 | var ctx = this.getContext(); 42 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 43 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 44 | ctx.setDepthTest(true); 45 | 46 | ctx.bindProgram(this.program); 47 | this.program.setUniform('uLightPos', [10, 10, 10]) 48 | 49 | ctx.bindMesh(this.mesh); 50 | ctx.drawMesh(); 51 | } 52 | }) 53 | -------------------------------------------------------------------------------- /204-gamma-color/Material.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: lambert = require(glsl-diffuse-lambert) 6 | #pragma glslify: toLinear = require(glsl-gamma/in) 7 | #pragma glslify: toGamma = require(glsl-gamma/out) 8 | 9 | //vec3 toLinear(vec3 v) { return v; } 10 | //vec4 toLinear(vec4 v) { return v; } 11 | //vec4 toGamma(vec4 v) { return v; } 12 | 13 | varying vec3 ecPosition; 14 | varying vec3 ecNormal; 15 | varying vec3 ecLightPos1; 16 | varying vec3 ecLightPos2; 17 | 18 | uniform vec4 uLightColor1; 19 | uniform vec4 uLightColor2; 20 | 21 | uniform bool uLinearSpace; 22 | uniform bool uCorrectGamma; 23 | 24 | float PI = 3.14159265; 25 | 26 | void main() { 27 | vec3 N = normalize(ecNormal); 28 | vec3 L1 = normalize(ecLightPos1 - ecPosition); 29 | vec3 L2 = normalize(ecLightPos2 - ecPosition); 30 | 31 | float diffuse1 = lambert(L1, N); 32 | float diffuse2 = lambert(L2, N); 33 | 34 | vec3 lightColor1 = uLinearSpace ? toLinear(uLightColor1.rgb) : uLightColor1.rgb; 35 | vec3 lightColor2 = uLinearSpace ? toLinear(uLightColor2.rgb) : uLightColor2.rgb; 36 | 37 | //albedo 38 | vec4 baseColor = uLinearSpace ? toLinear(vec4(1.0)) : vec4(1.0); 39 | 40 | vec4 finalColor = vec4(0.0, 0.0, 0.0, 1.0); 41 | finalColor.rgb = baseColor.rgb * diffuse1 * lightColor1 + baseColor.rgb * diffuse2 * lightColor2; 42 | gl_FragColor = uCorrectGamma ? toGamma(finalColor) : finalColor; 43 | } 44 | -------------------------------------------------------------------------------- /204-gamma-color/Material.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | uniform vec3 uLightPos1; 10 | uniform vec3 uLightPos2; 11 | 12 | varying vec3 ecPosition; 13 | varying vec3 ecNormal; 14 | varying vec3 ecLightPos1; 15 | varying vec3 ecLightPos2; 16 | 17 | void main() { 18 | vec4 pos = uViewMatrix * uModelMatrix * aPosition; 19 | ecPosition = pos.xyz; 20 | ecNormal = uNormalMatrix * aNormal; 21 | 22 | ecLightPos1 = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos1, 1.0)); 23 | ecLightPos2 = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos2, 1.0)); 24 | 25 | gl_Position = uProjectionMatrix * pos; 26 | } 27 | -------------------------------------------------------------------------------- /204-gamma-color/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | var GUI = require('pex-gui'); 7 | 8 | Window.create({ 9 | settings: { 10 | width: 1024, 11 | height: 576 12 | }, 13 | resources: { 14 | vert: { glsl: glslify(__dirname + '/Material.vert') }, 15 | frag: { glsl: glslify(__dirname + '/Material.frag') } 16 | }, 17 | init: function() { 18 | var ctx = this.getContext(); 19 | 20 | this.lightColor1 = [0.0, 0.9, 0.0, 1.0]; 21 | this.lightColor2 = [0.9, 0.0, 0.0, 1.0]; 22 | this.correctGamma = true; 23 | this.linearSpace = true; 24 | 25 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 26 | this.addEventListener(this.gui); 27 | this.gui.addHeader('Settings'); 28 | this.gui.addParam('Linear space', this, 'linearSpace'); 29 | this.gui.addParam('Correct gamma', this, 'correctGamma'); 30 | this.gui.addParam('Light 1', this, 'lightColor1', { type: 'color'}); 31 | this.gui.addParam('Light 2', this, 'lightColor2', { type: 'color'}); 32 | 33 | this.model = Mat4.create(); 34 | this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0); 35 | this.view = Mat4.lookAt([], [0, 1, 5], [0, 0, 0], [0, 1, 0]); 36 | 37 | ctx.setProjectionMatrix(this.projection); 38 | ctx.setViewMatrix(this.view); 39 | ctx.setModelMatrix(this.model); 40 | 41 | var res = this.getResources(); 42 | 43 | this.program = ctx.createProgram(res.vert, res.frag); 44 | 45 | var g = createSphere(1); 46 | 47 | var attributes = [ 48 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 49 | { data: g.normals, location: ctx.ATTRIB_NORMAL } 50 | ]; 51 | var indices = { data: g.cells, usage: ctx.STATIC_DRAW }; 52 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 53 | }, 54 | draw: function() { 55 | var ctx = this.getContext(); 56 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 57 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 58 | ctx.setDepthTest(true); 59 | 60 | ctx.bindProgram(this.program); 61 | this.program.setUniform('uLightPos1', [-10, 10, 5]); 62 | this.program.setUniform('uLightPos2', [10, 10, 5]); 63 | this.program.setUniform('uLightColor1', this.lightColor1); 64 | this.program.setUniform('uLightColor2', this.lightColor2); 65 | this.program.setUniform('uLinearSpace', this.linearSpace); 66 | this.program.setUniform('uCorrectGamma', this.correctGamma); 67 | 68 | ctx.bindMesh(this.mesh); 69 | ctx.drawMesh(); 70 | 71 | this.gui.draw(); 72 | } 73 | }) 74 | -------------------------------------------------------------------------------- /205-gamma-texture/Material.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: lambert = require(glsl-diffuse-lambert) 6 | #pragma glslify: toLinear = require(glsl-gamma/in) 7 | #pragma glslify: toGamma = require(glsl-gamma/out) 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | varying vec3 ecLightPos; 12 | varying vec2 vTexCoord0; 13 | 14 | uniform sampler2D uAlbedoTex; 15 | 16 | uniform bool uLinearSpace; 17 | uniform bool uCorrectGamma; 18 | 19 | float PI = 3.14159265; 20 | 21 | void main() { 22 | vec3 N = normalize(ecNormal); 23 | vec3 L = normalize(ecLightPos - ecPosition); 24 | 25 | float diffuse = lambert(L, N); 26 | 27 | vec4 baseColor = texture2D(uAlbedoTex, vTexCoord0 * vec2(3.0, 2.0)); 28 | baseColor.rgb = uLinearSpace ? toLinear(baseColor.rgb) : baseColor.rgb; 29 | 30 | //linear space lighting 31 | vec4 finalColor = vec4(baseColor.rgb * diffuse, 1.0); 32 | gl_FragColor = uCorrectGamma ? toGamma(finalColor) : finalColor; 33 | } 34 | -------------------------------------------------------------------------------- /205-gamma-texture/Material.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | attribute vec2 aTexCoord0; 4 | 5 | uniform mat4 uProjectionMatrix; 6 | uniform mat4 uViewMatrix; 7 | uniform mat4 uModelMatrix; 8 | uniform mat3 uNormalMatrix; 9 | 10 | uniform vec3 uLightPos; 11 | 12 | varying vec3 ecPosition; 13 | varying vec3 ecNormal; 14 | varying vec3 ecLightPos; 15 | varying vec2 vTexCoord0; 16 | 17 | void main() { 18 | vec4 pos = uViewMatrix * uModelMatrix * aPosition; 19 | ecPosition = pos.xyz; 20 | gl_Position = uProjectionMatrix * pos; 21 | ecLightPos = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos, 1.0)); 22 | ecNormal = uNormalMatrix * aNormal; 23 | vTexCoord0 = aTexCoord0; 24 | } 25 | -------------------------------------------------------------------------------- /205-gamma-texture/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createTorus = require('primitive-torus'); 6 | var createSphere = require('primitive-sphere'); 7 | var isBrowser = require('is-browser'); 8 | var GUI = require('pex-gui'); 9 | 10 | //define path to the assets directory, here it's above (..) the example 11 | //folder so all examples can share the assets. `__dirname` is a nodejs 12 | //built-in variable pointing to the folder where the js script lives, 13 | //We need that to make it work in Plask. 14 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 15 | 16 | Window.create({ 17 | settings: { 18 | width: 1024, 19 | height: 576 20 | }, 21 | resources: { 22 | vert: { glsl: glslify(__dirname + '/Material.vert') }, 23 | frag: { glsl: glslify(__dirname + '/Material.frag') }, 24 | texture: { image: ASSETS_DIR + '/textures/Pink_tile_pxr128.jpg'} 25 | }, 26 | init: function() { 27 | var ctx = this.getContext(); 28 | 29 | this.model = Mat4.create(); 30 | this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0); 31 | this.view = Mat4.lookAt([], [0, 1, 5], [0, 0, 0], [0, 1, 0]); 32 | 33 | this.correctGamma = true; 34 | this.linearSpace = true; 35 | 36 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 37 | this.addEventListener(this.gui); 38 | this.gui.addHeader('Settings'); 39 | this.gui.addParam('Linear space', this, 'linearSpace'); 40 | this.gui.addParam('Correct gamma', this, 'correctGamma'); 41 | 42 | ctx.setProjectionMatrix(this.projection); 43 | ctx.setViewMatrix(this.view); 44 | ctx.setModelMatrix(this.model); 45 | 46 | var res = this.getResources(); 47 | 48 | this.program = ctx.createProgram(res.vert, res.frag); 49 | 50 | this.texture = ctx.createTexture2D(res.texture, res.texture.width, res.texture.height, { repeat: true }); 51 | 52 | var g = createSphere(); 53 | 54 | var attributes = [ 55 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 56 | { data: g.normals, location: ctx.ATTRIB_NORMAL }, 57 | { data: g.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 58 | ]; 59 | var indices = { data: g.cells, usage: ctx.STATIC_DRAW }; 60 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 61 | }, 62 | draw: function() { 63 | var ctx = this.getContext(); 64 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 65 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 66 | ctx.setDepthTest(true); 67 | 68 | ctx.bindProgram(this.program); 69 | this.program.setUniform('uLightPos', [10, 10, 10]); 70 | this.program.setUniform('uAlbedoTex', 0); 71 | this.program.setUniform('uLinearSpace', this.linearSpace); 72 | this.program.setUniform('uCorrectGamma', this.correctGamma); 73 | 74 | ctx.bindTexture(this.texture, 0); 75 | this.program.setUniform('uAlbedoTex', 0); 76 | 77 | 78 | ctx.bindMesh(this.mesh); 79 | ctx.drawMesh(); 80 | 81 | this.gui.draw(); 82 | } 83 | }) 84 | -------------------------------------------------------------------------------- /206-gamma-ext-srgb/Material.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: lambert = require(glsl-diffuse-lambert) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | 8 | varying vec3 ecNormal; 9 | varying vec3 ecLight; 10 | varying vec3 ecPosition; 11 | varying vec2 vTexCoord0; 12 | 13 | uniform sampler2D uAlbedoTex; 14 | 15 | float PI = 3.14159265; 16 | 17 | void main() { 18 | vec3 N = normalize(ecNormal); 19 | vec3 L = normalize(ecLight - ecPosition); 20 | vec3 V = normalize(-ecPosition); 21 | float diffuse = lambert(L, N); 22 | 23 | //sample color as usual, the RGB values will be converted to linear space for you 24 | vec4 baseColor = texture2D(uAlbedoTex, vTexCoord0 * vec2(3.0, 2.0)); 25 | vec4 finalColor = vec4(baseColor.rgb * diffuse, 1.0); 26 | 27 | //we still need to bring it back to the gamma color space as we don't have sRGB aware render buffer here 28 | gl_FragColor = toGamma(finalColor); 29 | } 30 | -------------------------------------------------------------------------------- /206-gamma-ext-srgb/Material.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | attribute vec2 aTexCoord0; 4 | 5 | uniform mat4 uProjectionMatrix; 6 | uniform mat4 uViewMatrix; 7 | uniform mat4 uModelMatrix; 8 | uniform mat3 uNormalMatrix; 9 | 10 | uniform vec3 uLightPos; 11 | 12 | varying vec3 ecNormal; 13 | varying vec3 ecLight; 14 | varying vec3 ecPosition; 15 | varying vec2 vTexCoord0; 16 | 17 | void main() { 18 | vec4 pos = uViewMatrix * uModelMatrix * aPosition; 19 | ecPosition = pos.xyz; 20 | gl_Position = uProjectionMatrix * pos; 21 | ecLight = vec3(uViewMatrix * uModelMatrix * vec4(uLightPos, 1.0)); 22 | ecNormal = uNormalMatrix * aNormal; 23 | vTexCoord0 = aTexCoord0; 24 | } 25 | -------------------------------------------------------------------------------- /206-gamma-ext-srgb/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createTorus = require('primitive-torus'); 6 | var createSphere = require('primitive-sphere'); 7 | var isBrowser = require('is-browser'); 8 | 9 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 10 | 11 | Window.create({ 12 | settings: { 13 | width: 1024, 14 | height: 576 15 | }, 16 | resources: { 17 | vert: { glsl: glslify(__dirname + '/Material.vert') }, 18 | frag: { glsl: glslify(__dirname + '/Material.frag') }, 19 | texture: { image: ASSETS_DIR + '/textures/Pink_tile_pxr128.jpg'} 20 | }, 21 | init: function() { 22 | var ctx = this.getContext(); 23 | 24 | this.model = Mat4.create(); 25 | this.projection = Mat4.perspective(Mat4.create(), 45, this.getAspectRatio(), 0.001, 10.0); 26 | this.view = Mat4.lookAt([], [0, 1, 5], [0, 0, 0], [0, 1, 0]); 27 | 28 | ctx.setProjectionMatrix(this.projection); 29 | ctx.setViewMatrix(this.view); 30 | ctx.setModelMatrix(this.model); 31 | 32 | var res = this.getResources(); 33 | 34 | this.program = ctx.createProgram(res.vert, res.frag); 35 | 36 | this.texture = ctx.createTexture2D(res.texture, res.texture.width, res.texture.height, { repeat: true, format: ctx.SRGB }); 37 | 38 | var g = createSphere(); 39 | 40 | var attributes = [ 41 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 42 | { data: g.normals, location: ctx.ATTRIB_NORMAL }, 43 | { data: g.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 44 | ]; 45 | var indices = { data: g.cells, usage: ctx.STATIC_DRAW }; 46 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 47 | }, 48 | draw: function() { 49 | var ctx = this.getContext(); 50 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 51 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 52 | ctx.setDepthTest(true); 53 | 54 | ctx.bindProgram(this.program); 55 | this.program.setUniform('uLightPos', [10, 10, 10]); 56 | this.program.setUniform('uAlbedoTex', 0); 57 | ctx.bindTexture(this.texture, 0); 58 | 59 | ctx.bindMesh(this.mesh); 60 | ctx.drawMesh(); 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /301-load-cubemap/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | //envMapCube samples a cubemap envmap by mirroring the sampling ray along X axis 6 | #pragma glslify: envMapCube = require(../local_modules/glsl-envmap-cube) 7 | 8 | uniform mat4 uInverseViewMatrix; 9 | uniform samplerCube uEnvMap; 10 | 11 | varying vec3 ecPosition; 12 | varying vec3 ecNormal; 13 | 14 | void main() { 15 | //direction towards they eye (camera) in the view (eye) space 16 | vec3 ecEyeDir = normalize(-ecPosition); 17 | //direction towards the camera in the world space 18 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 19 | //surface normal in the world space 20 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 21 | 22 | //reflection vector in the world space. We negate wcEyeDir as the reflect function expect incident vector pointing towards the surface 23 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 24 | 25 | gl_FragColor = textureCube(uEnvMap, envMapCube(reflectionWorld)); 26 | } 27 | -------------------------------------------------------------------------------- /301-load-cubemap/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /301-load-cubemap/Skybox.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapCube = require(../local_modules/glsl-envmap-cube) 6 | 7 | varying vec3 wcNormal; 8 | 9 | uniform samplerCube uEnvMap; 10 | 11 | void main() { 12 | gl_FragColor = textureCube(uEnvMap, envMapCube(normalize(wcNormal))); 13 | } 14 | -------------------------------------------------------------------------------- /301-load-cubemap/Skybox.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | 8 | varying vec3 wcNormal; 9 | 10 | void main() { 11 | wcNormal = aPosition.xyz; 12 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 13 | } 14 | -------------------------------------------------------------------------------- /301-load-cubemap/mainNoDebug.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | var createCube = require('primitive-cube'); 7 | var PerspCamera = require('pex-cam/PerspCamera'); 8 | var Arcball = require('pex-cam/Arcball'); 9 | var isBrowser = require('is-browser'); 10 | 11 | Window.create({ 12 | settings: { 13 | width: 1024, 14 | height: 576, 15 | fullscreen: isBrowser 16 | }, 17 | resources: { 18 | reflectionVert: { glsl: glslify(__dirname + '/Reflection.vert') }, 19 | reflectionFrag: { glsl: glslify(__dirname + '/Reflection.frag') }, 20 | skyboxVert: { glsl: glslify(__dirname + '/Skybox.vert') }, 21 | skyboxFrag: { glsl: glslify(__dirname + '/Skybox.frag') }, 22 | showColorsVert: { glsl: glslify(__dirname + '/../assets/glsl/ShowColors.vert') }, 23 | showColorsFrag: { glsl: glslify(__dirname + '/../assets/glsl/ShowColors.frag') }, 24 | lake_px: { image: __dirname + '/../assets/envmaps/lake_right.jpg' }, 25 | lake_nx: { image: __dirname + '/../assets/envmaps/lake_left.jpg' }, 26 | lake_py: { image: __dirname + '/../assets/envmaps/lake_top.jpg' }, 27 | lake_ny: { image: __dirname + '/../assets/envmaps/lake_bottom.jpg' }, 28 | lake_pz: { image: __dirname + '/../assets/envmaps/lake_back.jpg' }, //+x is 'back'! 29 | lake_nz: { image: __dirname + '/../assets/envmaps/lake_front.jpg' }//-z is 'front'! 30 | }, 31 | init: function() { 32 | var ctx = this.getContext(); 33 | 34 | this.camera = new PerspCamera(45, this.getAspectRatio(), 0.1, 20); 35 | this.camera.lookAt([0, 1, 4], [0, 0, 0], [0, 1, 0]); 36 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 37 | this.addEventListener(this.arcball); 38 | 39 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 40 | ctx.setViewMatrix(this.camera.getViewMatrix()); 41 | 42 | this.modelMatrix = Mat4.create(); 43 | ctx.setModelMatrix(this.modelMatrix); 44 | 45 | var res = this.getResources(); 46 | 47 | this.reflectionProgram = ctx.createProgram(res.reflectionVert, res.reflectionFrag); 48 | this.skyboxProgram = ctx.createProgram(res.skyboxVert, res.skyboxFrag); 49 | 50 | var g = createSphere(); 51 | var attributes = [ 52 | { data: g.positions, location: ctx.ATTRIB_POSITION }, 53 | { data: g.normals, location: ctx.ATTRIB_NORMAL } 54 | ]; 55 | var indices = { data: g.cells }; 56 | this.mesh = ctx.createMesh(attributes, indices, ctx.TRIANGLES); 57 | 58 | var cube = createCube(20); 59 | this.skyboxMesh = ctx.createMesh( 60 | [ { data: cube.positions, location: ctx.ATTRIB_POSITION }], 61 | { data: cube.cells }, 62 | ctx.TRIANGLES 63 | ); 64 | 65 | this.reflectionMap = ctx.createTextureCube([ 66 | { face: 0, data: res.lake_px }, 67 | { face: 1, data: res.lake_nx }, 68 | { face: 2, data: res.lake_py }, 69 | { face: 3, data: res.lake_ny }, 70 | { face: 4, data: res.lake_pz }, 71 | { face: 5, data: res.lake_nz } 72 | ]) 73 | }, 74 | draw: function() { 75 | var ctx = this.getContext(); 76 | 77 | this.arcball.apply(); 78 | ctx.setViewMatrix(this.camera.getViewMatrix()); 79 | 80 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 81 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 82 | 83 | ctx.bindTexture(this.reflectionMap, 0); 84 | 85 | ctx.setDepthTest(false); 86 | ctx.bindProgram(this.skyboxProgram); 87 | this.skyboxProgram.setUniform('uReflectionMap', 0); 88 | ctx.setCullFace(true); 89 | ctx.setCullFaceMode(ctx.FRONT); 90 | ctx.pushModelMatrix(); 91 | ctx.translate(this.camera.getPosition()); 92 | ctx.bindMesh(this.skyboxMesh); 93 | ctx.drawMesh(); 94 | ctx.popModelMatrix(); 95 | ctx.setCullFaceMode(ctx.BACK); 96 | 97 | ctx.setDepthTest(true); 98 | ctx.bindProgram(this.reflectionProgram); 99 | this.reflectionProgram.setUniform('uReflectionMap', 0); 100 | ctx.bindMesh(this.mesh); 101 | ctx.drawMesh(); 102 | } 103 | }) 104 | -------------------------------------------------------------------------------- /302-load-equirect/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | 7 | uniform mat4 uInverseViewMatrix; 8 | uniform sampler2D uEnvMap; 9 | 10 | varying vec3 ecPosition; 11 | varying vec3 ecNormal; 12 | 13 | void main() { 14 | vec3 ecEyeDir = normalize(-ecPosition); 15 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 16 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 17 | 18 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 19 | gl_FragColor = texture2D(uEnvMap, envMapEquirect(reflectionWorld)); 20 | } 21 | -------------------------------------------------------------------------------- /302-load-equirect/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /302-load-equirect/Skybox.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | 7 | varying vec3 wcNormal; 8 | 9 | uniform sampler2D uEnvMap; 10 | 11 | void main() { 12 | gl_FragColor = texture2D(uEnvMap, envMapEquirect(normalize(wcNormal))); 13 | } 14 | -------------------------------------------------------------------------------- /302-load-equirect/Skybox.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | 8 | varying vec3 wcNormal; 9 | 10 | void main() { 11 | wcNormal = aPosition.xyz; 12 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 13 | } 14 | -------------------------------------------------------------------------------- /303-fullscreenquad-skybox/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | 7 | uniform mat4 uInverseViewMatrix; 8 | uniform sampler2D uEnvMap; 9 | 10 | varying vec3 ecPosition; 11 | varying vec3 ecNormal; 12 | 13 | void main() { 14 | vec3 ecEyeDir = normalize(-ecPosition); 15 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 16 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 17 | 18 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 19 | 20 | gl_FragColor = texture2D(uEnvMap, envMapEquirect(reflectionWorld)); 21 | } 22 | -------------------------------------------------------------------------------- /303-fullscreenquad-skybox/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /303-fullscreenquad-skybox/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | 7 | varying vec3 wcNormal; 8 | 9 | uniform sampler2D uEnvMap; 10 | 11 | void main() { 12 | vec3 N = normalize(wcNormal); 13 | gl_FragColor = texture2D(uEnvMap, envMapEquirect(N)); 14 | } 15 | -------------------------------------------------------------------------------- /303-fullscreenquad-skybox/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | 17 | //transform from the normalized device coordinates back to the view space 18 | vec3 unprojected = (inverseProjection * aPosition).xyz; 19 | 20 | //transfrom from the view space back to the world space 21 | //and use it as a sampling vector 22 | wcNormal = inverseModelview * unprojected; 23 | 24 | gl_Position = aPosition; 25 | } 26 | -------------------------------------------------------------------------------- /303-fullscreenquad-skybox/SkyboxQuadDebug.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | attribute vec4 aPosition; 3 | 4 | #pragma glslify: inverse = require('glsl-inverse') 5 | #pragma glslify: transpose = require('glsl-transpose') 6 | 7 | uniform mat4 uProjectionMatrix; 8 | uniform mat4 uViewMatrix; 9 | 10 | uniform mat4 uOrigProjectionMatrix; 11 | uniform mat4 uOrigViewMatrix; 12 | 13 | uniform float uFarNearRatio; 14 | uniform vec3 uRightRight; 15 | uniform vec3 uUpTop; 16 | uniform vec3 uFrontNear; 17 | uniform vec3 uCamPosition; 18 | 19 | varying vec3 wcNormal; 20 | 21 | void main2() { 22 | mat4 inverseProjection = inverse(uOrigProjectionMatrix); 23 | mat3 transposedView = transpose(mat3(uOrigViewMatrix)); 24 | vec3 unprojected = (inverseProjection * aPosition).xyz; 25 | wcNormal = transposedView * unprojected; 26 | 27 | vec3 wcPos = uCamPosition + (uFrontNear + aPosition.x * uRightRight + aPosition.y * uUpTop) * uFarNearRatio; 28 | 29 | gl_Position = uProjectionMatrix * uViewMatrix * vec4(wcPos, 1.0); 30 | } 31 | 32 | void main() { 33 | main2(); 34 | return; 35 | mat4 inverseProjection = inverse(uProjectionMatrix); 36 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 37 | vec3 unprojected = (inverseProjection * aPosition).xyz; 38 | wcNormal = inverseModelview * unprojected; 39 | 40 | gl_Position = aPosition; 41 | } 42 | -------------------------------------------------------------------------------- /304-load-hdr/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | 8 | uniform mat4 uInverseViewMatrix; 9 | uniform sampler2D uEnvMap; 10 | uniform bool uCorrectGamma; 11 | 12 | varying vec3 ecPosition; 13 | varying vec3 ecNormal; 14 | 15 | void main() { 16 | vec3 ecEyeDir = normalize(-ecPosition); 17 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 18 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 19 | 20 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 21 | 22 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(reflectionWorld)).rgb; 23 | 24 | if (uCorrectGamma) { 25 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 26 | } 27 | gl_FragColor.a = 1.0; 28 | } 29 | -------------------------------------------------------------------------------- /304-load-hdr/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /304-load-hdr/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | 8 | uniform sampler2D uEnvMap; 9 | uniform bool uCorrectGamma; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | vec3 N = normalize(wcNormal); 15 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(N)).rgb; 16 | 17 | if (uCorrectGamma) { 18 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 19 | } 20 | 21 | gl_FragColor.a = 1.0; 22 | } 23 | -------------------------------------------------------------------------------- /304-load-hdr/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | vec3 unprojected = (inverseProjection * aPosition).xyz; 17 | wcNormal = inverseModelview * unprojected; 18 | 19 | gl_Position = aPosition; 20 | } 21 | -------------------------------------------------------------------------------- /304-load-hdr/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | var parseHdr = require('../local_modules/parse-hdr'); 7 | var isBrowser = require('is-browser'); 8 | var GUI = require('pex-gui'); 9 | var PerspCamera = require('pex-cam/PerspCamera'); 10 | var Arcball = require('pex-cam/Arcball'); 11 | 12 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 13 | 14 | Window.create({ 15 | settings: { 16 | width: 1024, 17 | height: 576, 18 | fullscreen: isBrowser 19 | }, 20 | resources: { 21 | skyboxVert: { glsl: glslify(__dirname + '/SkyboxQuad.vert') }, 22 | skyboxFrag: { glsl: glslify(__dirname + '/SkyboxQuad.frag') }, 23 | reflectionVert: { glsl: glslify(__dirname + '/Reflection.vert') }, 24 | reflectionFrag: { glsl: glslify(__dirname + '/Reflection.frag') }, 25 | envMap: { binary: ASSETS_DIR + '/envmaps/pisa_latlong_256.hdr' } 26 | }, 27 | gamma: false, 28 | init: function() { 29 | var ctx = this.getContext(); 30 | 31 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 32 | this.gui.addParam('Gamma', this, 'gamma'); 33 | this.addEventListener(this.gui); 34 | 35 | this.camera = new PerspCamera(45, this.getAspectRatio(), 0.1, 50); 36 | this.camera.lookAt([0, 0, -5], [0, 0, 0], [0, 1, 0]); 37 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 38 | this.addEventListener(this.arcball); 39 | 40 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 41 | ctx.setViewMatrix(this.camera.getViewMatrix()); 42 | 43 | var res = this.getResources(); 44 | 45 | this.skyboxProgram = ctx.createProgram(res.skyboxVert, res.skyboxFrag); 46 | ctx.bindProgram(this.skyboxProgram); 47 | this.skyboxProgram.setUniform('uEnvMap', 0); 48 | 49 | this.reflectionProgram = ctx.createProgram(res.reflectionVert, res.reflectionFrag); 50 | ctx.bindProgram(this.reflectionProgram); 51 | this.reflectionProgram.setUniform('uEnvMap', 0); 52 | 53 | var hdrInfo = parseHdr(res.envMap); 54 | this.envMap = ctx.createTexture2D(hdrInfo.data, hdrInfo.shape[0], hdrInfo.shape[1], { 55 | type: ctx.FLOAT 56 | }); 57 | 58 | var skyboxPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 59 | var skyboxFaces = [ [0, 1, 2], [0, 2, 3]]; 60 | var skyboxAttributes = [ 61 | { data: skyboxPositions, location: ctx.ATTRIB_POSITION }, 62 | ]; 63 | var skyboxIndices = { data: skyboxFaces }; 64 | this.skyboxMesh = ctx.createMesh(skyboxAttributes, skyboxIndices); 65 | 66 | var sphere = createSphere(); 67 | var attributes = [ 68 | { data: sphere.positions, location: ctx.ATTRIB_POSITION }, 69 | { data: sphere.normals, location: ctx.ATTRIB_NORMAL }, 70 | { data: sphere.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 71 | ]; 72 | var sphereIndices = { data: sphere.cells, usage: ctx.STATIC_DRAW }; 73 | this.sphereMesh = ctx.createMesh(attributes, sphereIndices, ctx.TRIANGLES); 74 | }, 75 | draw: function() { 76 | var ctx = this.getContext(); 77 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 78 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 79 | 80 | this.arcball.apply(); 81 | ctx.setViewMatrix(this.camera.getViewMatrix()); 82 | 83 | ctx.bindTexture(this.envMap, 0); 84 | ctx.bindProgram(this.skyboxProgram); 85 | this.skyboxProgram.setUniform('uCorrectGamma', this.gamma); 86 | 87 | ctx.setDepthTest(false); 88 | ctx.bindMesh(this.skyboxMesh); 89 | ctx.drawMesh(); 90 | 91 | ctx.bindProgram(this.reflectionProgram); 92 | this.reflectionProgram.setUniform('uCorrectGamma', this.gamma); 93 | ctx.setDepthTest(true); 94 | 95 | ctx.bindMesh(this.sphereMesh); 96 | ctx.drawMesh(); 97 | 98 | this.gui.draw(); 99 | } 100 | }) 101 | -------------------------------------------------------------------------------- /305-exposure-basic/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | 8 | uniform mat4 uInverseViewMatrix; 9 | uniform sampler2D uEnvMap; 10 | uniform bool uCorrectGamma; 11 | uniform float uExposure; 12 | 13 | varying vec3 ecPosition; 14 | varying vec3 ecNormal; 15 | 16 | void main() { 17 | vec3 ecEyeDir = normalize(-ecPosition); 18 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 19 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 20 | 21 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 22 | 23 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(reflectionWorld)).rgb; 24 | 25 | gl_FragColor.rgb *= uExposure; 26 | 27 | if (uCorrectGamma) { 28 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 29 | } 30 | gl_FragColor.a = 1.0; 31 | } 32 | -------------------------------------------------------------------------------- /305-exposure-basic/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /305-exposure-basic/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | 8 | uniform sampler2D uEnvMap; 9 | uniform bool uCorrectGamma; 10 | uniform float uExposure; 11 | 12 | varying vec3 wcNormal; 13 | 14 | void main() { 15 | vec3 N = normalize(wcNormal); 16 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(N)).rgb; 17 | 18 | gl_FragColor.rgb *= uExposure; 19 | 20 | if (uCorrectGamma) { 21 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 22 | } 23 | 24 | gl_FragColor.a = 1.0; 25 | } 26 | -------------------------------------------------------------------------------- /305-exposure-basic/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | vec3 unprojected = (inverseProjection * aPosition).xyz; 17 | wcNormal = inverseModelview * unprojected; 18 | 19 | gl_Position = aPosition; 20 | } 21 | -------------------------------------------------------------------------------- /305-exposure-basic/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | var parseHdr = require('../local_modules/parse-hdr'); 7 | var isBrowser = require('is-browser'); 8 | var GUI = require('pex-gui'); 9 | var PerspCamera = require('pex-cam/PerspCamera'); 10 | var Arcball = require('pex-cam/Arcball'); 11 | 12 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 13 | 14 | Window.create({ 15 | settings: { 16 | width: 1024, 17 | height: 576, 18 | fullscreen: isBrowser 19 | }, 20 | resources: { 21 | skyboxVert: { glsl: glslify(__dirname + '/SkyboxQuad.vert') }, 22 | skyboxFrag: { glsl: glslify(__dirname + '/SkyboxQuad.frag') }, 23 | reflectionVert: { glsl: glslify(__dirname + '/Reflection.vert') }, 24 | reflectionFrag: { glsl: glslify(__dirname + '/Reflection.frag') }, 25 | envMap: { binary: ASSETS_DIR + '/envmaps/pisa_latlong_256.hdr' } 26 | }, 27 | gamma: true, 28 | exposure: 1, 29 | init: function() { 30 | var ctx = this.getContext(); 31 | 32 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 33 | this.gui.addParam('Gamma', this, 'gamma'); 34 | this.gui.addParam('Exposure', this, 'exposure', { min: 0, max: 3 }); 35 | this.addEventListener(this.gui); 36 | 37 | this.camera = new PerspCamera(45, this.getAspectRatio(), 0.1, 50); 38 | this.camera.lookAt([0, 0, -5], [0, 0, 0], [0, 1, 0]); 39 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 40 | this.addEventListener(this.arcball); 41 | 42 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 43 | ctx.setViewMatrix(this.camera.getViewMatrix()); 44 | 45 | var res = this.getResources(); 46 | 47 | this.skyboxProgram = ctx.createProgram(res.skyboxVert, res.skyboxFrag); 48 | ctx.bindProgram(this.skyboxProgram); 49 | this.skyboxProgram.setUniform('uEnvMap', 0); 50 | 51 | this.reflectionProgram = ctx.createProgram(res.reflectionVert, res.reflectionFrag); 52 | ctx.bindProgram(this.reflectionProgram); 53 | this.reflectionProgram.setUniform('uEnvMap', 0); 54 | 55 | var hdrInfo = parseHdr(res.envMap); 56 | this.envMap = ctx.createTexture2D(hdrInfo.data, hdrInfo.shape[0], hdrInfo.shape[1], { 57 | type: ctx.FLOAT 58 | }); 59 | 60 | var skyboxPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 61 | var skyboxFaces = [ [0, 1, 2], [0, 2, 3]]; 62 | var skyboxAttributes = [ 63 | { data: skyboxPositions, location: ctx.ATTRIB_POSITION }, 64 | ]; 65 | var skyboxIndices = { data: skyboxFaces }; 66 | this.skyboxMesh = ctx.createMesh(skyboxAttributes, skyboxIndices); 67 | 68 | var sphere = createSphere(); 69 | var attributes = [ 70 | { data: sphere.positions, location: ctx.ATTRIB_POSITION }, 71 | { data: sphere.normals, location: ctx.ATTRIB_NORMAL }, 72 | { data: sphere.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 73 | ]; 74 | var sphereIndices = { data: sphere.cells, usage: ctx.STATIC_DRAW }; 75 | this.sphereMesh = ctx.createMesh(attributes, sphereIndices, ctx.TRIANGLES); 76 | }, 77 | draw: function() { 78 | var ctx = this.getContext(); 79 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 80 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 81 | 82 | this.arcball.apply(); 83 | ctx.setViewMatrix(this.camera.getViewMatrix()); 84 | 85 | ctx.bindTexture(this.envMap, 0); 86 | 87 | ctx.bindProgram(this.skyboxProgram); 88 | this.skyboxProgram.setUniform('uCorrectGamma', this.gamma); 89 | this.skyboxProgram.setUniform('uExposure', this.exposure); 90 | 91 | ctx.setDepthTest(false); 92 | ctx.bindMesh(this.skyboxMesh); 93 | ctx.drawMesh(); 94 | 95 | ctx.bindProgram(this.reflectionProgram); 96 | this.reflectionProgram.setUniform('uCorrectGamma', this.gamma); 97 | this.reflectionProgram.setUniform('uExposure', this.exposure); 98 | ctx.setDepthTest(true); 99 | 100 | ctx.bindMesh(this.sphereMesh); 101 | ctx.drawMesh(); 102 | 103 | this.gui.draw(); 104 | } 105 | }) 106 | -------------------------------------------------------------------------------- /306-tonemap-reinhard/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 7 | #pragma glslify: toGamma = require(glsl-gamma/out) 8 | 9 | uniform mat4 uInverseViewMatrix; 10 | uniform sampler2D uEnvMap; 11 | uniform bool uCorrectGamma; 12 | uniform bool uTonemap; 13 | uniform float uExposure; 14 | 15 | varying vec3 ecPosition; 16 | varying vec3 ecNormal; 17 | 18 | void main() { 19 | vec3 ecEyeDir = normalize(-ecPosition); 20 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 21 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 22 | 23 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 24 | 25 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(reflectionWorld)).rgb; 26 | 27 | gl_FragColor.rgb *= uExposure; 28 | 29 | if (uTonemap) { 30 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 31 | } 32 | 33 | if (uCorrectGamma) { 34 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 35 | } 36 | gl_FragColor.a = 1.0; 37 | } 38 | -------------------------------------------------------------------------------- /306-tonemap-reinhard/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /306-tonemap-reinhard/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 7 | #pragma glslify: toGamma = require(glsl-gamma/out) 8 | 9 | uniform sampler2D uEnvMap; 10 | uniform bool uCorrectGamma; 11 | uniform bool uTonemap; 12 | uniform float uExposure; 13 | 14 | varying vec3 wcNormal; 15 | 16 | void main() { 17 | vec3 N = normalize(wcNormal); 18 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(N)).rgb; 19 | 20 | gl_FragColor.rgb *= uExposure; 21 | 22 | if (uTonemap) { 23 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 24 | } 25 | 26 | if (uCorrectGamma) { 27 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 28 | } 29 | 30 | gl_FragColor.a = 1.0; 31 | } 32 | -------------------------------------------------------------------------------- /306-tonemap-reinhard/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | vec3 unprojected = (inverseProjection * aPosition).xyz; 17 | wcNormal = inverseModelview * unprojected; 18 | 19 | gl_Position = aPosition; 20 | } 21 | -------------------------------------------------------------------------------- /306-tonemap-reinhard/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var glslify = require('glslify-promise'); 5 | var createSphere = require('primitive-sphere'); 6 | var parseHdr = require('../local_modules/parse-hdr'); 7 | var isBrowser = require('is-browser'); 8 | var GUI = require('pex-gui'); 9 | var PerspCamera = require('pex-cam/PerspCamera'); 10 | var Arcball = require('pex-cam/Arcball'); 11 | 12 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 13 | 14 | Window.create({ 15 | settings: { 16 | width: 1024, 17 | height: 576, 18 | fullscreen: isBrowser 19 | }, 20 | resources: { 21 | skyboxVert: { glsl: glslify(__dirname + '/SkyboxQuad.vert') }, 22 | skyboxFrag: { glsl: glslify(__dirname + '/SkyboxQuad.frag') }, 23 | reflectionVert: { glsl: glslify(__dirname + '/Reflection.vert') }, 24 | reflectionFrag: { glsl: glslify(__dirname + '/Reflection.frag') }, 25 | envMap: { binary: ASSETS_DIR + '/envmaps/pisa_latlong_256.hdr' } 26 | }, 27 | gamma: true, 28 | tonemap: true, 29 | exposure: 1, 30 | init: function() { 31 | var ctx = this.getContext(); 32 | 33 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 34 | this.gui.addParam('Gamma', this, 'gamma'); 35 | this.gui.addParam('Tonemap', this, 'tonemap'); 36 | this.gui.addParam('Exposure', this, 'exposure', { min: 0, max: 3 }); 37 | this.addEventListener(this.gui); 38 | 39 | this.camera = new PerspCamera(45, this.getAspectRatio(), 0.1, 50); 40 | this.camera.lookAt([0, 0, -5], [0, 0, 0], [0, 1, 0]); 41 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 42 | this.addEventListener(this.arcball); 43 | 44 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 45 | ctx.setViewMatrix(this.camera.getViewMatrix()); 46 | 47 | var res = this.getResources(); 48 | 49 | this.skyboxProgram = ctx.createProgram(res.skyboxVert, res.skyboxFrag); 50 | ctx.bindProgram(this.skyboxProgram); 51 | this.skyboxProgram.setUniform('uEnvMap', 0); 52 | 53 | this.reflectionProgram = ctx.createProgram(res.reflectionVert, res.reflectionFrag); 54 | ctx.bindProgram(this.reflectionProgram); 55 | this.reflectionProgram.setUniform('uEnvMap', 0); 56 | 57 | var hdrInfo = parseHdr(res.envMap); 58 | this.envMap = ctx.createTexture2D(hdrInfo.data, hdrInfo.shape[0], hdrInfo.shape[1], { 59 | type: ctx.FLOAT 60 | }); 61 | 62 | var skyboxPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 63 | var skyboxFaces = [ [0, 1, 2], [0, 2, 3]]; 64 | var skyboxAttributes = [ 65 | { data: skyboxPositions, location: ctx.ATTRIB_POSITION }, 66 | ]; 67 | var skyboxIndices = { data: skyboxFaces }; 68 | this.skyboxMesh = ctx.createMesh(skyboxAttributes, skyboxIndices); 69 | 70 | var sphere = createSphere(); 71 | var attributes = [ 72 | { data: sphere.positions, location: ctx.ATTRIB_POSITION }, 73 | { data: sphere.normals, location: ctx.ATTRIB_NORMAL }, 74 | { data: sphere.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 75 | ]; 76 | var sphereIndices = { data: sphere.cells, usage: ctx.STATIC_DRAW }; 77 | this.sphereMesh = ctx.createMesh(attributes, sphereIndices, ctx.TRIANGLES); 78 | }, 79 | draw: function() { 80 | var ctx = this.getContext(); 81 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 82 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 83 | 84 | this.arcball.apply(); 85 | ctx.setViewMatrix(this.camera.getViewMatrix()); 86 | 87 | ctx.bindTexture(this.envMap, 0); 88 | 89 | ctx.bindProgram(this.skyboxProgram); 90 | this.skyboxProgram.setUniform('uCorrectGamma', this.gamma); 91 | this.skyboxProgram.setUniform('uTonemap', this.tonemap); 92 | this.skyboxProgram.setUniform('uExposure', this.exposure); 93 | 94 | ctx.setDepthTest(false); 95 | ctx.bindMesh(this.skyboxMesh); 96 | ctx.drawMesh(); 97 | 98 | ctx.bindProgram(this.reflectionProgram); 99 | this.reflectionProgram.setUniform('uCorrectGamma', this.gamma); 100 | this.reflectionProgram.setUniform('uTonemap', this.tonemap); 101 | this.reflectionProgram.setUniform('uExposure', this.exposure); 102 | ctx.setDepthTest(true); 103 | 104 | ctx.bindMesh(this.sphereMesh); 105 | ctx.drawMesh(); 106 | 107 | this.gui.draw(); 108 | } 109 | }) 110 | -------------------------------------------------------------------------------- /307-tonemap-compare/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 8 | #pragma glslify: tonemapFilmic = require(../local_modules/glsl-tonemap-filmic) 9 | #pragma glslify: tonemapUncharted2 = require(../local_modules/glsl-tonemap-uncharted2) 10 | 11 | uniform mat4 uInverseViewMatrix; 12 | uniform sampler2D uEnvMap; 13 | uniform float uExposure; 14 | uniform float uTonemappingMethod; 15 | 16 | varying vec3 ecPosition; 17 | varying vec3 ecNormal; 18 | 19 | void main() { 20 | vec3 ecEyeDir = normalize(-ecPosition); 21 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 22 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 23 | 24 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 25 | 26 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(reflectionWorld)).rgb; 27 | gl_FragColor.rgb *= uExposure; 28 | 29 | if (uTonemappingMethod == 0.0) { 30 | //no tonemapping 31 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 32 | } 33 | else if (uTonemappingMethod == 1.0) { 34 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 35 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 36 | } 37 | else if (uTonemappingMethod == 2.0) { 38 | gl_FragColor.rgb = tonemapFilmic(gl_FragColor.rgb); 39 | } 40 | else if (uTonemappingMethod == 3.0) { 41 | gl_FragColor.rgb = tonemapUncharted2(gl_FragColor.rgb); 42 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 43 | } 44 | 45 | gl_FragColor.a = 1.0; 46 | } 47 | -------------------------------------------------------------------------------- /307-tonemap-compare/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /307-tonemap-compare/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 8 | #pragma glslify: tonemapFilmic = require(../local_modules/glsl-tonemap-filmic) 9 | #pragma glslify: tonemapUncharted2 = require(../local_modules/glsl-tonemap-uncharted2) 10 | 11 | varying vec3 wcNormal; 12 | 13 | uniform sampler2D uEnvMap; 14 | uniform float uExposure; 15 | uniform float uTonemappingMethod; 16 | 17 | void main() { 18 | vec3 N = normalize(wcNormal); 19 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(N)).rgb; 20 | gl_FragColor.rgb *= uExposure; 21 | 22 | if (uTonemappingMethod == 0.0) { 23 | //no tonemapping 24 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 25 | } 26 | else if (uTonemappingMethod == 1.0) { 27 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 28 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 29 | } 30 | else if (uTonemappingMethod == 2.0) { 31 | gl_FragColor.rgb = tonemapFilmic(gl_FragColor.rgb); 32 | } 33 | else if (uTonemappingMethod == 3.0) { 34 | gl_FragColor.rgb = tonemapUncharted2(gl_FragColor.rgb); 35 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 36 | } 37 | 38 | gl_FragColor.a = 1.0; 39 | } 40 | -------------------------------------------------------------------------------- /307-tonemap-compare/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 wcNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | vec3 unprojected = (inverseProjection * aPosition).xyz; 17 | wcNormal = inverseModelview * unprojected; 18 | 19 | gl_Position = aPosition; 20 | } 21 | -------------------------------------------------------------------------------- /308-exposure-camera/Reflection.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 8 | 9 | uniform mat4 uInverseViewMatrix; 10 | uniform sampler2D uEnvMap; 11 | uniform float uAperture; 12 | uniform float uShutterSpeed; 13 | uniform float uIso; 14 | uniform float uMiddleGrey; 15 | 16 | varying vec3 ecPosition; 17 | varying vec3 ecNormal; 18 | 19 | //White balance middle grey we are targetting for a good scene exposure 20 | //https://en.wikipedia.org/wiki/Middle_gray 21 | const float MIDDLE_GREY = 0.18; 22 | 23 | /* 24 | * Get an exposure using the Standard Output Sensitivity method. 25 | * Accepts an additional parameter of the target middle grey. 26 | */ 27 | float getStandardOutputBasedExposure(float aperture, 28 | float shutterSpeed, 29 | float iso) 30 | { 31 | float q = 0.65; 32 | //float l_avg = (1000.0f / 65.0f) * sqrt(aperture) / (iso * shutterSpeed); 33 | float l_avg = (1.0 / q) * sqrt(aperture) / (iso * shutterSpeed); 34 | //float l_avg = sqrt(aperture) / (iso * shutterSpeed); 35 | return MIDDLE_GREY / l_avg; 36 | } 37 | 38 | void main() { 39 | vec3 ecEyeDir = normalize(-ecPosition); 40 | vec3 wcEyeDir = vec3(uInverseViewMatrix * vec4(ecEyeDir, 0.0)); 41 | vec3 wcNormal = vec3(uInverseViewMatrix * vec4(ecNormal, 0.0)); 42 | 43 | vec3 reflectionWorld = reflect(-wcEyeDir, normalize(wcNormal)); 44 | 45 | //gl_FragColor.rgb = rgbe2rgb(texture2DEnvLatLong(uEnvMap, reflectionWorld)); 46 | //gl_FragColor.rgb *= log(uExposure); 47 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(reflectionWorld)).rgb; 48 | gl_FragColor.rgb *= getStandardOutputBasedExposure(uAperture, uShutterSpeed, uIso); 49 | //gl_FragColor.rgb *= getStandardOutputBasedExposure(16, uExposure, 100.0, 0.18); 50 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 51 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 52 | 53 | gl_FragColor.a = 1.0; 54 | } 55 | -------------------------------------------------------------------------------- /308-exposure-camera/Reflection.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec3 aNormal; 3 | 4 | uniform mat4 uProjectionMatrix; 5 | uniform mat4 uViewMatrix; 6 | uniform mat4 uModelMatrix; 7 | uniform mat3 uNormalMatrix; 8 | 9 | varying vec3 ecPosition; 10 | varying vec3 ecNormal; 11 | 12 | void main() { 13 | gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * aPosition; 14 | ecPosition = vec3(uViewMatrix * uModelMatrix * aPosition); 15 | ecNormal = uNormalMatrix * aNormal; 16 | } 17 | -------------------------------------------------------------------------------- /308-exposure-camera/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../local_modules/glsl-envmap-equirect) 6 | #pragma glslify: toGamma = require(glsl-gamma/out) 7 | #pragma glslify: tonemapReinhard = require(../local_modules/glsl-tonemap-reinhard) 8 | 9 | /* 10 | * Get an exposure using the Saturation-based Speed method. 11 | */ 12 | float getSaturationBasedExposure(float aperture, 13 | float shutterSpeed, 14 | float iso) 15 | { 16 | float l_max = (7800.0 / 65.0) * sqrt(aperture) / (iso * shutterSpeed); 17 | return 1.0 / l_max; 18 | } 19 | 20 | //White balance middle grey we are targetting for a good scene exposure 21 | //https://en.wikipedia.org/wiki/Middle_gray 22 | const float MIDDLE_GREY = 0.18; 23 | 24 | /* 25 | * Get an exposure using the Standard Output Sensitivity method. 26 | * Accepts an additional parameter of the target middle grey. 27 | */ 28 | float getStandardOutputBasedExposure(float aperture, 29 | float shutterSpeed, 30 | float iso) 31 | { 32 | //https://placeholderart.wordpress.com/2014/11/21/implementing-a-physically-based-camera-manual-exposure/ 33 | //https://en.wikipedia.org/wiki/Film_speed#Standard_output_sensitivity_.28SOS.29 34 | //photometric exposure magic 35 | //represents the properties of lens 36 | float q = 0.65; 37 | 38 | //float l_avg = (1000.0f / 65.0f) * sqrt(aperture) / (iso * shutterSpeed); 39 | float l_avg = (1.0 / q) * sqrt(aperture) / (iso * shutterSpeed); 40 | //float l_avg = sqrt(aperture) / (iso * shutterSpeed); 41 | return MIDDLE_GREY / l_avg; 42 | } 43 | 44 | varying vec3 vNormal; 45 | 46 | uniform sampler2D uEnvMap; 47 | uniform float uAperture; 48 | uniform float uShutterSpeed; 49 | uniform float uIso; 50 | 51 | void main() { 52 | vec3 N = normalize(vNormal); 53 | //gl_FragColor.rgb = rgbe2rgb(texture2DEnvLatLong(uEnvMap, N)); 54 | //gl_FragColor.rgb *= log(uExposure); 55 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(N)).rgb; 56 | gl_FragColor.rgb *= getStandardOutputBasedExposure(uAperture, uShutterSpeed, uIso); 57 | //gl_FragColor.rgb *= getStandardOutputBasedExposure(16, uExposure, 100.0, 0.18); 58 | gl_FragColor.rgb = tonemapReinhard(gl_FragColor.rgb); 59 | gl_FragColor.rgb = toGamma(gl_FragColor.rgb); 60 | gl_FragColor.a = 1.0; 61 | } 62 | -------------------------------------------------------------------------------- /308-exposure-camera/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #pragma glslify: transpose = require('glsl-transpose') 7 | 8 | uniform mat4 uProjectionMatrix; 9 | uniform mat4 uViewMatrix; 10 | 11 | varying vec3 vNormal; 12 | 13 | void main() { 14 | mat4 inverseProjection = inverse(uProjectionMatrix); 15 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 16 | vec3 unprojected = (inverseProjection * aPosition).xyz; 17 | vNormal = inverseModelview * unprojected; 18 | 19 | gl_Position = aPosition; 20 | } 21 | -------------------------------------------------------------------------------- /308-exposure-camera/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var Mat4 = require('pex-math/Mat4'); 3 | var Vec3 = require('pex-math/Vec3'); 4 | var MathUtils = require('pex-math/Utils'); 5 | var glslify = require('glslify-promise'); 6 | var createSphere = require('primitive-sphere'); 7 | var createCube = require('primitive-cube'); 8 | var parseHdr = require('../local_modules/parse-hdr'); 9 | var isBrowser = require('is-browser'); 10 | var GUI = require('pex-gui'); 11 | var PerspCamera = require('pex-cam/PerspCamera'); 12 | var Arcball = require('pex-cam/Arcball'); 13 | 14 | var ASSETS_DIR = isBrowser ? '../assets' : __dirname + '/../assets'; 15 | 16 | Window.create({ 17 | settings: { 18 | width: 1024, 19 | height: 576, 20 | fullscreen: isBrowser 21 | }, 22 | resources: { 23 | skyboxVert: { glsl: glslify(__dirname + '/SkyboxQuad.vert') }, 24 | skyboxFrag: { glsl: glslify(__dirname + '/SkyboxQuad.frag') }, 25 | reflectionVert: { glsl: glslify(__dirname + '/Reflection.vert') }, 26 | reflectionFrag: { glsl: glslify(__dirname + '/Reflection.frag') }, 27 | envMap: { binary: ASSETS_DIR + '/envmaps/pisa_latlong_256.hdr' } 28 | }, 29 | aperture: 16, 30 | shutterSpeed: 0.5, 31 | iso: 100, 32 | onMouseMove: function(e) { 33 | var w = this.getWidth(); 34 | //this.exposure = MathUtils.clamp(MathUtils.map(e.x, 0, w, 1/60, 1), 0, 1); 35 | }, 36 | init: function() { 37 | var ctx = this.getContext(); 38 | 39 | this.gui = new GUI(ctx, this.getWidth(), this.getHeight()); 40 | this.addEventListener(this.gui); 41 | this.gui.addParam('Aperture - f', this, 'aperture', { min: 1.4, max: 32 }); 42 | this.gui.addParam('Sutter Speed (sec)', this, 'shutterSpeed', {min: 1/1000, max: 1/2}); 43 | this.gui.addParam('ISO', this, 'iso', { min: 100, max: 1600 }); 44 | this.gui.addParam('Middle grey', this, 'middleGrey', { min: 0, max: 1 }); 45 | 46 | this.camera = new PerspCamera(45, this.getAspectRatio(), 0.1, 100); 47 | this.camera.lookAt([0, 0, -5], [0, 0, 0], [0, 1, 0]); 48 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 49 | this.addEventListener(this.arcball); 50 | 51 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 52 | ctx.setViewMatrix(this.camera.getViewMatrix()); 53 | 54 | this.modelMatrix = Mat4.create(); 55 | ctx.setModelMatrix(this.modelMatrix); 56 | 57 | var res = this.getResources(); 58 | 59 | this.skyboxProgram = ctx.createProgram(res.skyboxVert, res.skyboxFrag); 60 | ctx.bindProgram(this.skyboxProgram); 61 | this.skyboxProgram.setUniform('uEnvMap', 0); 62 | this.skyboxProgram.setUniform('uAperture', this.aperture); 63 | this.skyboxProgram.setUniform('uShutterSpeed', this.shutterSpeed); 64 | this.skyboxProgram.setUniform('uIso', this.iso); 65 | 66 | 67 | this.reflectionProgram = ctx.createProgram(res.reflectionVert, res.reflectionFrag); 68 | ctx.bindProgram(this.reflectionProgram); 69 | this.reflectionProgram.setUniform('uEnvMap', 0); 70 | this.reflectionProgram.setUniform('uAperture', this.aperture); 71 | this.reflectionProgram.setUniform('uShutterSpeed', this.shutterSpeed); 72 | this.reflectionProgram.setUniform('uIso', this.iso); 73 | 74 | var hdrInfo = parseHdr(res.envMap); 75 | this.envMap = ctx.createTexture2D(hdrInfo.data, hdrInfo.shape[0], hdrInfo.shape[1], { 76 | type: ctx.FLOAT 77 | }); 78 | 79 | var skyboxPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 80 | var skyboxFaces = [ [0, 1, 2], [0, 2, 3]]; 81 | var skyboxAttributes = [ 82 | { data: skyboxPositions, location: ctx.ATTRIB_POSITION }, 83 | ]; 84 | var skyboxIndices = { data: skyboxFaces }; 85 | this.skyboxMesh = ctx.createMesh(skyboxAttributes, skyboxIndices); 86 | 87 | var sphere = createSphere(); 88 | var attributes = [ 89 | { data: sphere.positions, location: ctx.ATTRIB_POSITION }, 90 | { data: sphere.normals, location: ctx.ATTRIB_NORMAL }, 91 | { data: sphere.uvs, location: ctx.ATTRIB_TEX_COORD_0 }, 92 | ]; 93 | var sphereIndices = { data: sphere.cells, usage: ctx.STATIC_DRAW }; 94 | this.sphereMesh = ctx.createMesh(attributes, sphereIndices, ctx.TRIANGLES); 95 | }, 96 | draw: function() { 97 | var ctx = this.getContext(); 98 | ctx.setClearColor(0.2, 0.2, 0.2, 1); 99 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 100 | ctx.setDepthTest(true); 101 | 102 | this.arcball.apply(); 103 | ctx.setViewMatrix(this.camera.getViewMatrix()); 104 | 105 | ctx.bindTexture(this.envMap, 0); 106 | 107 | //move skybox to the camera position 108 | ctx.setDepthTest(false); 109 | ctx.bindProgram(this.skyboxProgram); 110 | this.skyboxProgram.setUniform('uAperture', this.aperture); 111 | this.skyboxProgram.setUniform('uShutterSpeed', this.shutterSpeed); 112 | this.skyboxProgram.setUniform('uIso', this.iso); 113 | ctx.bindMesh(this.skyboxMesh); 114 | ctx.drawMesh(); 115 | 116 | ctx.setDepthTest(true); 117 | ctx.bindProgram(this.reflectionProgram); 118 | this.reflectionProgram.setUniform('uAperture', this.aperture); 119 | this.reflectionProgram.setUniform('uShutterSpeed', this.shutterSpeed); 120 | this.reflectionProgram.setUniform('uIso', this.iso); 121 | ctx.bindMesh(this.sphereMesh); 122 | ctx.drawMesh(); 123 | 124 | this.gui.draw(); 125 | } 126 | }) 127 | -------------------------------------------------------------------------------- /400-hammersley-point-set/main.js: -------------------------------------------------------------------------------- 1 | var Window = require('pex-sys/Window'); 2 | var glslify = require('glslify-promise'); 3 | var PerspCamera = require('pex-cam/PerspCamera'); 4 | var Arcball = require('pex-cam/Arcball'); 5 | var hammersley = require('hammersley'); 6 | var GUI = require('pex-gui'); 7 | var Draw = require('pex-draw'); 8 | var isBrowser = require('is-browser'); 9 | var createSphere = require('primitive-sphere'); 10 | var random = require('pex-random'); 11 | var Vec3 = require('pex-math/Vec3'); 12 | 13 | Window.create({ 14 | settings: { 15 | width: 1024, 16 | height: 576, 17 | fullscreen: isBrowser 18 | }, 19 | resources: { 20 | showColorsVert: { glsl: glslify(__dirname + '/../assets/glsl/ShowColors.vert') }, 21 | showColorsFrag: { glsl: glslify(__dirname + '/../assets/glsl/ShowColors.frag') } 22 | }, 23 | init: function() { 24 | var ctx = this.getContext(); 25 | var res = this.getResources(); 26 | 27 | this.camera = new PerspCamera(60, this.getAspectRatio(), 0.1, 100); 28 | this.camera.lookAt([0, 1, 3], [0, 0, 0], [0, 1, 0]); 29 | this.arcball = new Arcball(this.camera, this.getWidth(), this.getHeight()); 30 | this.addEventListener(this.arcball); 31 | 32 | ctx.setProjectionMatrix(this.camera.getProjectionMatrix()); 33 | ctx.setViewMatrix(this.camera.getViewMatrix()); 34 | 35 | var sphere = createSphere(1, { segments: 16}); 36 | var colors = sphere.positions.map(function() { return [1, 1, 1, 0.25]; }) 37 | var attributes = [ 38 | { data: sphere.positions, location: ctx.ATTRIB_POSITION }, 39 | { data: colors, location: ctx.ATTRIB_COLOR }, 40 | ]; 41 | var sphereIndices = { data: sphere.cells, usage: ctx.STATIC_DRAW }; 42 | this.sphereMesh = ctx.createMesh(attributes, sphereIndices, ctx.LINES); 43 | 44 | this.debugDraw = new Draw(ctx); 45 | this.showColorsProgram = ctx.createProgram(res.showColorsVert, res.showColorsFrag); 46 | 47 | this.center = [0, 0, 0]; 48 | this.samplingDir = Vec3.normalize([1, 1, 1]); 49 | this.samples = this.resamplePoints(this.samplingDir); 50 | }, 51 | resamplePoints: function(N) { 52 | var numSamples = 1024; 53 | var points = []; 54 | for(var i=0; i> 16))>>>0; 6 | bits[0] = ((bits[0] & 0x55555555) << 1) | ((bits[0] & 0xAAAAAAAA) >>> 1) >>>0; 7 | bits[0] = ((bits[0] & 0x33333333) << 2) | ((bits[0] & 0xCCCCCCCC) >>> 2) >>>0; 8 | bits[0] = ((bits[0] & 0x0F0F0F0F) << 4) | ((bits[0] & 0xF0F0F0F0) >>> 4) >>>0; 9 | bits[0] = ((bits[0] & 0x00FF00FF) << 8) | ((bits[0] & 0xFF00FF00) >>> 8) >>>0; 10 | return bits[0] * 2.3283064365386963e-10; // / 0x100000000 or / 4294967296 11 | } 12 | 13 | function hammersley(i, n) { 14 | return [i/n, radicalInverse_VdC(i)]; 15 | } 16 | 17 | module.exports = hammersley; 18 | -------------------------------------------------------------------------------- /400-realtime-filtering/hammersleyTest.js: -------------------------------------------------------------------------------- 1 | var plask = require('plask'); 2 | var hammersley = require('./hammersley'); 3 | 4 | plask.simpleWindow({ 5 | settings: { 6 | width: 512, 7 | height: 512, 8 | type: '2d', 9 | borderless: true 10 | }, 11 | init: function() { 12 | var numSamples = 300; 13 | var canvas = this.canvas; 14 | canvas.drawColor(240,240,240,255); 15 | var paint = this.paint; 16 | paint.setFill(); 17 | paint.setColor(255, 0, 0, 255); 18 | paint.setAntiAlias(true); 19 | 20 | var w = this.width; 21 | var h = this.height; 22 | 23 | for(var i=0; i 2 | 3 | 4 | 5 | Pragmatic PBR 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/models/dragon.txt: -------------------------------------------------------------------------------- 1 | This file brought to you by the geniuses at Stanford and MrBluesummers.com! -------------------------------------------------------------------------------- /assets/textures/Pink_tile_pxr128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/assets/textures/Pink_tile_pxr128.jpg -------------------------------------------------------------------------------- /assets/textures/Pink_tile_pxr128.txt: -------------------------------------------------------------------------------- 1 | https://community.renderman.pixar.com/article/114/library-pixar-one-twenty-eight.html?hootPostID=b341652bc97105327e2a5b7564487072 -------------------------------------------------------------------------------- /build_all.sh: -------------------------------------------------------------------------------- 1 | browserify 201-init/main.js -i plask -o 201-init/main.web.js 2 | browserify 202-lambert-diffuse/main.js -i plask -g glslify-promise/transform -o 202-lambert-diffuse/main.web.js 3 | browserify 203-gamma/main.js -i plask -g glslify-promise/transform -o 203-gamma/main.web.js 4 | browserify 204-gamma-color/main.js -i plask -g glslify-promise/transform -o 204-gamma-color/main.web.js 5 | browserify 205-gamma-texture/main.js -i plask -g glslify-promise/transform -o 205-gamma-texture/main.web.js 6 | browserify 206-gamma-ext-srgb/main.js -i plask -g glslify-promise/transform -o 206-gamma-ext-srgb/main.web.js 7 | 8 | browserify 301-load-cubemap/main.js -i plask -g glslify-promise/transform -o 301-load-cubemap/main.web.js 9 | browserify 301-reflections/main.js -i plask -g glslify-promise/transform -o 301-reflections/main.web.js 10 | browserify 302-load-equirect/main.js -i plask -g glslify-promise/transform -o 302-load-equirect/main.web.js 11 | browserify 303-fullscreenquad-skybox/main.js -i plask -g glslify-promise/transform -o 303-fullscreenquad-skybox/main.web.js 12 | browserify 304-load-hdr/main.js -i plask -g glslify-promise/transform -o 304-load-hdr/main.web.js 13 | browserify 305-exposure-basic/main.js -i plask -g glslify-promise/transform -o 305-exposure-basic/main.web.js 14 | browserify 306-tonemap-reinhard/main.js -i plask -g glslify-promise/transform -o 306-tonemap-reinhard/main.web.js 15 | browserify 307-tonemap-compare/main.js -i plask -g glslify-promise/transform -o 307-tonemap-compare/main.web.js 16 | browserify 308-exposure-camera/main.js -i plask -g glslify-promise/transform -o 308-exposure-camera/main.web.js 17 | 18 | cp assets/html/index.template.html 201-init/index.html 19 | cp assets/html/index.template.html 202-lambert-diffuse/index.html 20 | cp assets/html/index.template.html 203-gamma/index.html 21 | cp assets/html/index.template.html 204-gamma-color/index.html 22 | cp assets/html/index.template.html 205-gamma-texture/index.html 23 | cp assets/html/index.template.html 206-gamma-ext-srgb/index.html 24 | cp assets/html/index.template.html 301-load-cubemap/index.html 25 | cp assets/html/index.template.html 301-reflections/index.html 26 | cp assets/html/index.template.html 302-load-equirect/index.html 27 | cp assets/html/index.template.html 303-fullscreenquad-skybox/index.html 28 | cp assets/html/index.template.html 304-load-hdr/index.html 29 | cp assets/html/index.template.html 305-exposure-basic/index.html 30 | cp assets/html/index.template.html 306-tonemap-reinhard/index.html 31 | cp assets/html/index.template.html 307-tonemap-compare/index.html 32 | cp assets/html/index.template.html 308-exposure-camera/index.html 33 | -------------------------------------------------------------------------------- /img/100_bunny_env3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_bunny_env3.jpg -------------------------------------------------------------------------------- /img/100_demo_exposure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_demo_exposure.jpg -------------------------------------------------------------------------------- /img/100_demo_materials.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_demo_materials.jpg -------------------------------------------------------------------------------- /img/100_demo_mixing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_demo_mixing.jpg -------------------------------------------------------------------------------- /img/100_dielectric_roughness_sml.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_dielectric_roughness_sml.jpg -------------------------------------------------------------------------------- /img/100_exploded_cube.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_exploded_cube.jpg -------------------------------------------------------------------------------- /img/100_exploded_cube_thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_exploded_cube_thumb.jpg -------------------------------------------------------------------------------- /img/100_frame_stages.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_frame_stages.jpg -------------------------------------------------------------------------------- /img/100_materials3x2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_materials3x2.jpg -------------------------------------------------------------------------------- /img/100_metal_roughness_sml.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/100_metal_roughness_sml.jpg -------------------------------------------------------------------------------- /img/200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/200.jpg -------------------------------------------------------------------------------- /img/201.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/201.jpg -------------------------------------------------------------------------------- /img/202.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/202.jpg -------------------------------------------------------------------------------- /img/202_angles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/202_angles.jpg -------------------------------------------------------------------------------- /img/202_lambert_diffuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/202_lambert_diffuse.jpg -------------------------------------------------------------------------------- /img/202_transformation_spaces.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/202_transformation_spaces.jpg -------------------------------------------------------------------------------- /img/203.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/203.jpg -------------------------------------------------------------------------------- /img/203_gamma_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/203_gamma_graph.png -------------------------------------------------------------------------------- /img/203_gamma_graph.txt: -------------------------------------------------------------------------------- 1 | https://en.wikipedia.org/wiki/Gamma_correction -------------------------------------------------------------------------------- /img/203_gamma_moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/203_gamma_moon.png -------------------------------------------------------------------------------- /img/203_gamma_moon.txt: -------------------------------------------------------------------------------- 1 | http://beautifulpixels.blogspot.co.uk/2009/10/gamma-correct-lighting-on-moon.html -------------------------------------------------------------------------------- /img/203_gamma_video.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/203_gamma_video.jpg -------------------------------------------------------------------------------- /img/204.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/204.jpg -------------------------------------------------------------------------------- /img/204_comparison.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/204_comparison.jpg -------------------------------------------------------------------------------- /img/205.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/205.jpg -------------------------------------------------------------------------------- /img/205_pixar_textures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/205_pixar_textures.jpg -------------------------------------------------------------------------------- /img/205_pixar_textures.txt: -------------------------------------------------------------------------------- 1 | https://community.renderman.pixar.com/article/114/library-pixar-one-twenty-eight.html -------------------------------------------------------------------------------- /img/206_incorrect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/206_incorrect.jpg -------------------------------------------------------------------------------- /img/300.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/300.jpg -------------------------------------------------------------------------------- /img/300_hdr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/300_hdr.jpg -------------------------------------------------------------------------------- /img/301_cube_anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_cube_anim.gif -------------------------------------------------------------------------------- /img/301_cube_cross_and_debug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_cube_cross_and_debug.jpg -------------------------------------------------------------------------------- /img/301_cube_faces.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_cube_faces.jpg -------------------------------------------------------------------------------- /img/301_cube_faces_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_cube_faces_debug.png -------------------------------------------------------------------------------- /img/301_cube_orientation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_cube_orientation.png -------------------------------------------------------------------------------- /img/301_load_cubemap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_load_cubemap.jpg -------------------------------------------------------------------------------- /img/301_pisa_streetview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_pisa_streetview.jpg -------------------------------------------------------------------------------- /img/301_reflection_angle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_reflection_angle.png -------------------------------------------------------------------------------- /img/301_reflections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/301_reflections.png -------------------------------------------------------------------------------- /img/302_latlong_and_debug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/302_latlong_and_debug.jpg -------------------------------------------------------------------------------- /img/302_latlong_sampler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/302_latlong_sampler.png -------------------------------------------------------------------------------- /img/303_fullscreen_quad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/303_fullscreen_quad.jpg -------------------------------------------------------------------------------- /img/304_banding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/304_banding.jpg -------------------------------------------------------------------------------- /img/304_load_hdr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/304_load_hdr.jpg -------------------------------------------------------------------------------- /img/305_exposure_basic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/305_exposure_basic.jpg -------------------------------------------------------------------------------- /img/306_tonemap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/306_tonemap.jpg -------------------------------------------------------------------------------- /img/306_tonemap_func.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/306_tonemap_func.png -------------------------------------------------------------------------------- /img/306_tonemap_reinhard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/306_tonemap_reinhard.jpg -------------------------------------------------------------------------------- /img/307_tonemap_compare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/307_tonemap_compare.jpg -------------------------------------------------------------------------------- /img/308_exposure_camera.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vorg/pragmatic-pbr/8c6b9f2d6b6fc34c8c5128c9be6ce5257dc1e11a/img/308_exposure_camera.jpg -------------------------------------------------------------------------------- /local_modules/convolve-cubemap/glsl/convolve.frag: -------------------------------------------------------------------------------- 1 | //Based on Article - Physically Based Rendering by Marco Alamia 2 | //http://www.codinglabs.net/article_physically_based_rendering.aspx 3 | 4 | #ifdef GL_ES 5 | precision highp float; 6 | #endif 7 | 8 | varying vec3 wcNormal; 9 | varying vec2 scPosition; 10 | 11 | uniform samplerCube uEnvMap; 12 | uniform float uFace; 13 | uniform bool uHighQuality; 14 | 15 | const float PI = 3.1415926536; 16 | 17 | void main() { 18 | vec3 normal = normalize( wcNormal ); 19 | vec3 up = vec3(0.0, 1.0, 0.0); 20 | vec3 right = normalize(cross(up,normal)); 21 | up = cross(normal,right); 22 | 23 | vec3 sampledColour = vec3(0,0,0); 24 | float index = 0.0; 25 | 26 | if (uHighQuality) { 27 | const float dphi = 2.0 * PI / 180.0; 28 | const float dtheta = 0.5 * PI / 64.0; 29 | for(float phi = 0.0; phi < 6.283; phi += dphi) { 30 | for(float theta = 0.0; theta < 1.57; theta += dtheta) { 31 | vec3 temp = cos(phi) * right + sin(phi) * up; 32 | vec3 sampleVector = cos(theta) * normal + sin(theta) * temp; 33 | sampledColour += textureCube( uEnvMap, sampleVector ).rgb * cos(theta) * sin(theta); 34 | index++; 35 | } 36 | } 37 | } 38 | else { 39 | const float dphi = 2.0 * PI / 180.0 * 4.0; 40 | const float dtheta = 0.5 * PI / 64.0 * 4.0; 41 | for(float phi = 0.0; phi < 6.283; phi += dphi) { 42 | for(float theta = 0.0; theta < 1.57; theta += dtheta) { 43 | vec3 temp = cos(phi) * right + sin(phi) * up; 44 | vec3 sampleVector = cos(theta) * normal + sin(theta) * temp; 45 | sampledColour += textureCube( uEnvMap, sampleVector ).rgb * cos(theta) * sin(theta); 46 | index++; 47 | } 48 | } 49 | } 50 | 51 | gl_FragColor = vec4(PI * sampledColour / index, 1.0); 52 | } 53 | -------------------------------------------------------------------------------- /local_modules/convolve-cubemap/glsl/convolve.vert: -------------------------------------------------------------------------------- 1 | #pragma glslify: inverse = require('glsl-inverse') 2 | 3 | #ifdef GL_ES 4 | #pragma glslify: transpose = require('glsl-transpose') 5 | #endif 6 | 7 | attribute vec4 aPosition; 8 | 9 | uniform mat4 uProjectionMatrix; 10 | uniform mat4 uViewMatrix; 11 | uniform mat4 uInverseViewMatrix; 12 | 13 | varying vec3 wcNormal; 14 | varying vec2 scPosition; 15 | 16 | void main() { 17 | mat4 inverseProjection = inverse(uProjectionMatrix); 18 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 19 | vec3 unprojected = (inverseProjection * aPosition).xyz; 20 | wcNormal = inverseModelview * unprojected; 21 | gl_Position = aPosition; 22 | scPosition = aPosition.xy; 23 | } 24 | -------------------------------------------------------------------------------- /local_modules/convolve-cubemap/index.js: -------------------------------------------------------------------------------- 1 | var renderToCubemap = require('../render-to-cubemap'); 2 | var glslifySync = require('glslify-sync'); 3 | 4 | var VERT = glslifySync(__dirname + '/glsl/convolve.vert'); 5 | var FRAG = glslifySync(__dirname + '/glsl/convolve.frag'); 6 | 7 | var quadPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 8 | var quadFaces = [ [0, 1, 2], [0, 2, 3]]; 9 | 10 | var quadMesh = null; 11 | var convolveProgram = null; 12 | 13 | function convolveCubemap(ctx, fromCubemap, toCubemap, options) { 14 | options = options || {}; 15 | var highQuality = (options.highQuality !== undefined) ? options.highQuality : true; 16 | 17 | ctx.pushState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 18 | if (!quadMesh) { 19 | var quadAttributes = [ { data: quadPositions, location: ctx.ATTRIB_POSITION } ]; 20 | var quadIndices = { data: quadFaces }; 21 | quadMesh = ctx.createMesh(quadAttributes, quadIndices); 22 | 23 | convolveProgram = ctx.createProgram(VERT, FRAG); 24 | } 25 | renderToCubemap(ctx, toCubemap, function() { 26 | ctx.bindTexture(fromCubemap, 0); 27 | ctx.bindProgram(convolveProgram); 28 | convolveProgram.setUniform('uEnvMap', 0); 29 | convolveProgram.setUniform('uHighQuality', highQuality); 30 | ctx.bindMesh(quadMesh); 31 | ctx.drawMesh(); 32 | }); 33 | ctx.popState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 34 | } 35 | 36 | module.exports = convolveCubemap; 37 | -------------------------------------------------------------------------------- /local_modules/convolve-cubemap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "convolve-cubemap", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "Marcin Ignac (http://marcinignac.com/)", 7 | "license": "MIT", 8 | "dependencies": { 9 | "glsl-inverse": "^1.0.0", 10 | "glsl-transpose": "^1.0.0", 11 | "hammersley": "^1.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /local_modules/cubemap-to-octmap/glsl/CubemapToOctmap.frag: -------------------------------------------------------------------------------- 1 | varying vec2 vTexCoord0; 2 | 3 | #pragma glslify: envMapCube = require(../../glsl-envmap-cube) 4 | 5 | //if < 0 return -1, otherwise 1 6 | vec2 sign(vec2 v) { 7 | return step(0.0, v) * 2.0 - 1.0; 8 | } 9 | 10 | vec3 octUvToDir(vec2 uv) { 11 | uv = uv * 2.0 - 1.0; 12 | 13 | vec2 auv = abs(uv); 14 | float len = dot(auv, vec2(1.0)); 15 | 16 | if (len > 1.0) { 17 | //y < 0 case 18 | uv = (auv.yx - 1.0) * -1.0 * sign(uv); 19 | } 20 | 21 | return normalize(vec3(uv.x, 1.0 - len, uv.y)); 22 | } 23 | 24 | uniform samplerCube uCubemap; 25 | uniform float uCubemapFlipEnvMap; 26 | 27 | void main() { 28 | vec3 dir = octUvToDir(vTexCoord0); 29 | gl_FragColor = textureCube(uCubemap, envMapCube(dir, uCubemapFlipEnvMap)); 30 | } 31 | -------------------------------------------------------------------------------- /local_modules/cubemap-to-octmap/glsl/CubemapToOctmap.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec2 aTexCoord0; 3 | 4 | varying vec2 vTexCoord0; 5 | 6 | void main() { 7 | vTexCoord0 = aTexCoord0; 8 | gl_Position = aPosition; 9 | } 10 | -------------------------------------------------------------------------------- /local_modules/cubemap-to-octmap/index.js: -------------------------------------------------------------------------------- 1 | var glslifySync = require('glslify-sync'); 2 | var VERT = glslifySync(__dirname + '/glsl/CubemapToOctmap.vert'); 3 | var FRAG = glslifySync(__dirname + '/glsl/CubemapToOctmap.frag'); 4 | 5 | var fbo = null 6 | var mesh = null 7 | var program = null 8 | 9 | function cubemapToOctmap(ctx, fromCubemap, toOctmap) { 10 | if (!fbo) { 11 | fbo = ctx.createFramebuffer() 12 | 13 | var positions = [[-1, -1], [1, -1], [1, 1], [-1, 1]] 14 | var uvs = [[0,0], [1,0], [1,1], [0,1]] 15 | var indices = [[0, 1, 2], [0, 2, 3]] 16 | mesh = ctx.createMesh([ 17 | { data: positions, location: ctx.ATTRIB_POSITION }, 18 | { data: uvs, location: ctx.ATTRIB_TEX_COORD_0 } 19 | ], { data: indices }, ctx.TRIANGLES) 20 | 21 | program = ctx.createProgram(VERT, FRAG) 22 | } 23 | ctx.pushState(ctx.FRAMEBUFFER_BIT | ctx.MESH_BIT | ctx.PROGRAM_BIT | ctx.VIEWPORT_BIT | ctx.TEXTURE_BIT) 24 | ctx.bindFramebuffer(fbo) 25 | ctx.bindTexture(fromCubemap, 0) 26 | ctx.bindMesh(mesh) 27 | ctx.bindProgram(program) 28 | program.setUniform('uCubemap', 0) 29 | program.setUniform('uCubemapFlipEnvMap', fromCubemap.getFlipEnvMap()) 30 | fbo.setColorAttachment(0, toOctmap.getTarget(), toOctmap.getHandle()) 31 | ctx.setViewport(0, 0, toOctmap.getWidth(), toOctmap.getHeight()) 32 | ctx.drawMesh() 33 | ctx.popState() 34 | } 35 | 36 | module.exports = cubemapToOctmap; 37 | -------------------------------------------------------------------------------- /local_modules/cubemap-to-octmap/test.js: -------------------------------------------------------------------------------- 1 | /* 2 | mediump vec2 octahedralProjection(mediump vec3 dir) { 3 | dir/= dot(vec3(1.0), abs(dir)); 4 | mediump vec2 rev = abs(dir.zx) - vec2(1.0,1.0); 5 | mediump vec2 neg = vec2( 6 | dir.x < 0.0 ? rev.x : -rev.x, 7 | dir.z < 0.0 ? rev.y : -rev.y 8 | ); 9 | mediump vec2 uv = dir.y < 0.0 ? neg : dir.xz; 10 | return 0.5*uv + vec2(0.5,0.5); 11 | } 12 | */ 13 | 14 | var Vec3 = require('pex-math/Vec3') 15 | var Vec2 = require('pex-math/Vec2') 16 | var abs = Math.abs 17 | var random = Math.random 18 | 19 | //based on 20 | //https://webglinsights.github.io/downloads/WebGL-Insights-Chapter-16.pdf 21 | //https://gist.github.com/pyalot/cc7c3e5f144fb825d626 22 | //https://github.com/mrdoob/three.js/issues/5847 23 | 24 | function dirToOctUv(dir) { 25 | var dot = Vec3.dot([1,1,1], [abs(dir[0]), abs(dir[1]), abs(dir[2])]) 26 | dir = Vec3.scale(Vec3.copy(dir), 1/dot) 27 | var rev = Vec2.sub([abs(dir[2]), abs(dir[0])], [1, 1]) 28 | var neg = [ 29 | (dir[0] < 0) ? rev[0] : -rev[0], 30 | (dir[2] < 0) ? rev[1] : -rev[1], 31 | ] 32 | var uv = dir[1] < 0 ? neg : [dir[0], dir[2]] 33 | Vec2.add(Vec2.scale(uv, 0.5), [0.5, 0.5]) 34 | return uv 35 | } 36 | 37 | function dirToOctUv2(dir) { 38 | //#define sum(value) dot(clamp((value), 1.0, 1.0), (value)) 39 | var dot = Vec3.dot([1,1,1], [abs(dir[0]), abs(dir[1]), abs(dir[2])]) 40 | dir = Vec3.scale(Vec3.copy(dir), 1/dot) 41 | var uv; 42 | if (dir[1] >= 0) { 43 | uv = [dir[0], dir[2]] 44 | } 45 | else { 46 | var rev = Vec2.sub([abs(dir[2]), abs(dir[0])], [1, 1]) 47 | uv = [ 48 | (dir[0] < 0) ? rev[0] : -rev[0], 49 | (dir[2] < 0) ? rev[1] : -rev[1], 50 | ] 51 | // if (dirX < 0) 52 | // u = abs(dirZ) - 1 53 | // u = -1..0 54 | // else 55 | // u = -(abs(dirZ) - 1) 56 | // u = 1..0 57 | // if (dirZ < 0) 58 | // v = abs(dirX) - 1 59 | // v = -1..0 60 | // else 61 | // v = -(abs(dirX) - 1) 62 | // v = 1..0 63 | } 64 | return Vec2.add(Vec2.scale(uv, 0.5), [0.5, 0.5]) 65 | } 66 | 67 | var iter = 0; 68 | 69 | function sectorize(uv) { 70 | return [ 71 | (uv[0] > 0 ? 1 : 0) * 2 - 1, 72 | (uv[1] > 0 ? 1 : 0) * 2 - 1 73 | ] 74 | } 75 | 76 | function octUvToDir(uv) { 77 | var dir = [0,0,0] 78 | //uv = [0..1, 0..1] 79 | uv = Vec2.sub(Vec2.scale(Vec2.copy(uv), 2), [1, 1]) 80 | //uv = [-1..1, -1..1] 81 | var auv = [abs(uv[0]), abs(uv[1])] 82 | var len = Vec2.dot(auv, [1,1]) 83 | var suv = sectorize(uv) 84 | if (len > 1.0) { 85 | //y < 0 case 86 | uv = [ 87 | (auv[1] - 1) * (uv[0] > 0 ? -1 : 1), 88 | (auv[0] - 1) * (uv[1] > 0 ? -1 : 1), 89 | ] 90 | } 91 | 92 | return Vec3.normalize([ 93 | uv[0], 94 | 1 - len, 95 | uv[1] 96 | ]) 97 | } 98 | 99 | var plask = require('plask') 100 | 101 | plask.simpleWindow({ 102 | settings: { 103 | type: '2d', 104 | width: 256, 105 | height: 256 106 | }, 107 | init: function() { 108 | var paint = this.paint; 109 | var canvas = this.canvas; 110 | var W = 256 111 | var H = 256 112 | for(var i=0; i<100000; i++) { 113 | var dir = Vec3.normalize([ 114 | random() * 2 - 1, 115 | random() * 2 - 1, 116 | random() * 2 - 1 117 | ]) 118 | var dirOrig = Vec3.copy(dir) 119 | var uv = dirToOctUv2(dir) 120 | var uvOrig = Vec2.copy(uv) 121 | dir = octUvToDir(uv) 122 | uv = dirToOctUv2(dir) 123 | var s = (dir[1] >= 0) ? 1 : 0.5 124 | if (dir[0] >= 0 && dir[2] >= 0) { 125 | paint.setColor(255*s, 0, 0, 255) 126 | } else if (dir[0] <= 0 && dir[2] >= 0) { 127 | paint.setColor(255*s, 255*s, 0, 255) 128 | } else if (dir[0] <= 0 && dir[2] <= 0) { 129 | paint.setColor(0, 105*s, 255*s, 255) 130 | } else if (dir[0] >= 0 && dir[2] <= 0) { 131 | paint.setColor(0, 255*s, 55*s, 255) 132 | } else { 133 | paint.setColor(50, 50, 50) 134 | } 135 | paint.setColor( 136 | (dirOrig[0]*0.5+0.5)*255, 137 | (dirOrig[1]*0.5+0.5)*255, 138 | (dirOrig[2]*0.5+0.5)*255, 139 | 255 140 | ) 141 | var x = uv[0] * W 142 | var y = uv[1] * H 143 | canvas.drawRect(paint, x - 1, y - 1, x + 1, y + 1) 144 | } 145 | }, 146 | draw: function() { 147 | } 148 | }) 149 | -------------------------------------------------------------------------------- /local_modules/downsample-cubemap/glsl/downsample.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | 7 | uniform samplerCube uEnvMap; 8 | 9 | uniform mat4 uProjectionMatrix; 10 | uniform mat4 uInverseViewMatrix; 11 | uniform mat4 uViewMatrix; 12 | 13 | uniform float uTextureSize; 14 | 15 | vec4 sample(vec2 screenPos, mat4 inverseProjectionMatrix) { 16 | vec4 position = vec4(screenPos.x / uTextureSize * 2.0 - 1.0, screenPos.y / uTextureSize * 2.0 - 1.0, 0.0, 1.0); 17 | vec3 N = (uInverseViewMatrix * inverseProjectionMatrix * position).xyz; 18 | return textureCube(uEnvMap, N); 19 | } 20 | 21 | void main() { 22 | mat4 inverseProjectionMatrix = inverse(uProjectionMatrix); 23 | 24 | vec4 color = vec4(0.0); 25 | color += sample(gl_FragCoord.xy + vec2(-0.5, -0.5), inverseProjectionMatrix); 26 | color += sample(gl_FragCoord.xy + vec2(-0.5, +0.5), inverseProjectionMatrix); 27 | color += sample(gl_FragCoord.xy + vec2(+0.5, +0.5), inverseProjectionMatrix); 28 | color += sample(gl_FragCoord.xy + vec2(+0.5, -0.5), inverseProjectionMatrix); 29 | color *= 0.25; 30 | 31 | gl_FragColor = color; 32 | } 33 | -------------------------------------------------------------------------------- /local_modules/downsample-cubemap/glsl/downsample.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | 3 | void main() { 4 | gl_Position = aPosition; 5 | } 6 | -------------------------------------------------------------------------------- /local_modules/downsample-cubemap/index.js: -------------------------------------------------------------------------------- 1 | var renderToCubemap = require('../render-to-cubemap'); 2 | var glslifySync = require('glslify-sync'); 3 | 4 | var VERT = glslifySync(__dirname + '/glsl/downsample.vert'); 5 | var FRAG = glslifySync(__dirname + '/glsl/downsample.frag'); 6 | 7 | var quadPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 8 | var quadFaces = [ [0, 1, 2], [0, 2, 3]]; 9 | 10 | var quadMesh = null; 11 | var downsampleProgram = null; 12 | 13 | function downsampleCubemap(ctx, fromCubemap, toCubemap) { 14 | ctx.pushState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 15 | if (!quadMesh) { 16 | var quadAttributes = [ { data: quadPositions, location: ctx.ATTRIB_POSITION } ]; 17 | var quadIndices = { data: quadFaces }; 18 | quadMesh = ctx.createMesh(quadAttributes, quadIndices); 19 | 20 | downsampleProgram = ctx.createProgram(VERT, FRAG); 21 | } 22 | 23 | renderToCubemap(ctx, toCubemap, function() { 24 | ctx.bindTexture(fromCubemap, 0); 25 | ctx.bindProgram(downsampleProgram); 26 | downsampleProgram.setUniform('uEnvMap', 0); 27 | downsampleProgram.setUniform('uTextureSize', toCubemap.getWidth()) 28 | ctx.bindMesh(quadMesh); 29 | ctx.drawMesh(); 30 | }); 31 | ctx.popState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 32 | } 33 | 34 | module.exports = downsampleCubemap; 35 | -------------------------------------------------------------------------------- /local_modules/downsample-cubemap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "downsample-cubemap", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "Marcin Ignac (http://marcinignac.com/)", 7 | "license": "MIT", 8 | "dependencies": { 9 | "glsl-inverse": "^1.0.0", 10 | "glsl-transpose": "^1.0.0", 11 | "glslify": "^2.3.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /local_modules/envmap-to-cubemap/glsl/SkyboxQuad.frag: -------------------------------------------------------------------------------- 1 | #ifdef GL_ES 2 | precision highp float; 3 | #endif 4 | 5 | #pragma glslify: envMapEquirect = require(../../glsl-envmap-equirect) 6 | #pragma glslify: tonemapUncharted2 = require(../../glsl-tonemap-uncharted2) 7 | 8 | varying vec3 wcNormal; 9 | 10 | uniform sampler2D uEnvMap; 11 | 12 | void main() { 13 | gl_FragColor.rgb = texture2D(uEnvMap, envMapEquirect(normalize(wcNormal), 1.0)).rgb; 14 | gl_FragColor.a = 1.0; 15 | } 16 | -------------------------------------------------------------------------------- /local_modules/envmap-to-cubemap/glsl/SkyboxQuad.vert: -------------------------------------------------------------------------------- 1 | //Based on http://gamedev.stackexchange.com/questions/60313/implementing-a-skybox-with-glsl-version-330 2 | // 3 | attribute vec4 aPosition; 4 | 5 | #pragma glslify: inverse = require('glsl-inverse') 6 | #ifdef GL_ES 7 | #pragma glslify: transpose = require('glsl-transpose') 8 | #endif 9 | 10 | uniform mat4 uProjectionMatrix; 11 | uniform mat4 uViewMatrix; 12 | 13 | varying vec3 wcNormal; 14 | 15 | void main() { 16 | mat4 inverseProjection = inverse(uProjectionMatrix); 17 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 18 | vec3 unprojected = (inverseProjection * aPosition).xyz; 19 | wcNormal = inverseModelview * unprojected; 20 | 21 | gl_Position = aPosition; 22 | } 23 | -------------------------------------------------------------------------------- /local_modules/envmap-to-cubemap/index.js: -------------------------------------------------------------------------------- 1 | var renderToCubemap = require('../render-to-cubemap'); 2 | var glslifySync = require('glslify-sync'); 3 | var hammersley = require('hammersley'); 4 | 5 | var VERT = glslifySync(__dirname + '/glsl/SkyboxQuad.vert'); 6 | var FRAG = glslifySync(__dirname + '/glsl/SkyboxQuad.frag'); 7 | 8 | var quadPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 9 | var quadFaces = [ [0, 1, 2], [0, 2, 3]]; 10 | 11 | var quadMesh = null; 12 | var convertProgram = null; 13 | 14 | function envmapToCubemap(ctx, fromEnvmap, toCubemap) { 15 | ctx.pushState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 16 | if (!quadMesh) { 17 | var quadAttributes = [ { data: quadPositions, location: ctx.ATTRIB_POSITION } ]; 18 | var quadIndices = { data: quadFaces }; 19 | quadMesh = ctx.createMesh(quadAttributes, quadIndices); 20 | 21 | convertProgram = ctx.createProgram(VERT, FRAG); 22 | } 23 | renderToCubemap(ctx, toCubemap, function() { 24 | ctx.bindTexture(fromEnvmap, 0); 25 | ctx.bindProgram(convertProgram); 26 | convertProgram.setUniform('uEnvMap', 0); 27 | ctx.bindMesh(quadMesh); 28 | ctx.drawMesh(); 29 | }); 30 | ctx.popState(ctx.MESH_BIT | ctx.PROGRAM_BIT); //ctx.TEXTURE_BIT 31 | } 32 | 33 | module.exports = envmapToCubemap; 34 | -------------------------------------------------------------------------------- /local_modules/envmap-to-cubemap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "convolve-cubemap", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "Marcin Ignac (http://marcinignac.com/)", 7 | "license": "MIT", 8 | "dependencies": { 9 | "glsl-inverse": "^1.0.0", 10 | "glsl-transpose": "^1.0.0", 11 | "hammersley": "^1.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /local_modules/geom-center-and-resize/.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | -------------------------------------------------------------------------------- /local_modules/geom-center-and-resize/.npmignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | test 7 | test.js 8 | demo/ 9 | .npmignore 10 | LICENSE.md -------------------------------------------------------------------------------- /local_modules/geom-center-and-resize/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Marcin Ignac 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /local_modules/geom-center-and-resize/README.md: -------------------------------------------------------------------------------- 1 | # geom-center-and-scale 2 | 3 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 4 | 5 | Centers the geometry and scales it to fill 1x1x1 bounding box 6 | 7 | ## Usage 8 | 9 | [![NPM](https://nodei.co/npm/geom-center-and-scale.png)](https://www.npmjs.com/package/geom-center-and-scale) 10 | 11 | ## License 12 | 13 | MIT, see [LICENSE.md](http://github.com/vorg/geom-center-and-scale/blob/master/LICENSE.md) for details. 14 | -------------------------------------------------------------------------------- /local_modules/geom-center-and-resize/index.js: -------------------------------------------------------------------------------- 1 | var AABB = require('pex-geom/AABB'); 2 | var Vec3 = require('pex-math/Vec3'); 3 | 4 | function centerAndResize(positions, size) { 5 | size = size || 1; 6 | var aabb = AABB.fromPoints(positions); 7 | var center = AABB.center(aabb); 8 | var currentSize = AABB.size(aabb); 9 | var scale = Math.max(currentSize[0], Math.max(currentSize[1], currentSize[2])); 10 | 11 | var newPositions = []; 12 | for(var i=0; i 0) ? Number(val0) : null; 64 | tokenValues[1] = (val1 && val1.length > 0) ? Number(val1) : null; 65 | tokenValues[2] = (val2 && val2.length > 0) ? Number(val2) : null; 66 | vertices.push(tokenValues); 67 | } 68 | 69 | //make a triangle fan 70 | for(var v=1, vertexCount=vertices.length; v 0) ? (pi - 1) : (g.positionOffset + pi); 134 | 135 | var ti = triangle[v][1]; 136 | ti = (ti > 0) ? (ti - 1) : (g.uvOffset + ti ); 137 | 138 | var ni = triangle[v][2]; 139 | ni = (ni > 0) ? (ni - 1) : (g.normalOffset + ni); 140 | 141 | geom.positions[index] = positions[pi]; 142 | if (g.hasUVs) geom.uvs[index] = uvs[ti]; 143 | if (g.hasNormals) geom.normals[index] = normals[ni]; 144 | } 145 | geom.cells.push(face); 146 | } 147 | } 148 | if (geometries.length > 1) { 149 | return geometries 150 | } 151 | else { 152 | return geometries[0]; 153 | } 154 | }; 155 | 156 | module.exports = parseObj; 157 | -------------------------------------------------------------------------------- /local_modules/geom-subdivide-triangles/index.js: -------------------------------------------------------------------------------- 1 | var clone = require('clone'); 2 | var copy = require('pex-math/Vec3').copy; 3 | var add = require('pex-math/Vec3').add; 4 | var scale = require('pex-math/Vec3').scale; 5 | 6 | function subdivideTriangles(geometry) { 7 | var newPositions = clone(geometry.positions); 8 | var newCells = []; 9 | 10 | var cells = geometry.cells; 11 | var positions = geometry.positions; 12 | 13 | var cache = []; 14 | 15 | function edgeCenter(a, b) { 16 | //this can fail if the cached index would be 0 but if we had vertices before this will neve happen 17 | if (cache[a] && cache[a][b]) { 18 | return cache[a][b]; 19 | } 20 | if (cache[b] && cache[b][a]) { 21 | return cache[b][a]; 22 | } 23 | var center = copy(positions[a]); 24 | add(center, positions[b]); 25 | scale(center, 0.5); 26 | 27 | //console.log(a, b, positions[a], positions[b], center) 28 | 29 | if (!cache[a]) cache[a] = []; 30 | var newCenterIndex = newPositions.length; 31 | cache[a][b] = newCenterIndex; 32 | newPositions.push(center); 33 | 34 | //console.log(a, b, '->', newCenterIndex) 35 | return newCenterIndex; 36 | } 37 | 38 | //for each face 39 | for(var i=0; i", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /local_modules/prefilter-cubemap/glsl/prefilter.frag: -------------------------------------------------------------------------------- 1 | //Based on Article - Physically Based Rendering by Marco Alamia 2 | //http://www.codinglabs.net/article_physically_based_rendering.aspx 3 | 4 | #ifdef GL_ES 5 | precision highp float; 6 | #endif 7 | 8 | #pragma glslify: random = require(glsl-random) 9 | #pragma glslify: envMapCube = require(../../glsl-envmap-cube) 10 | 11 | varying vec3 wcNormal; 12 | varying vec2 scPosition; 13 | 14 | uniform samplerCube uEnvMap; 15 | uniform sampler2D uHammersleyPointSetMap; 16 | uniform float uRoughness; 17 | uniform int uNumSamples; 18 | 19 | const float PI = 3.1415926536; 20 | 21 | float saturate(float f) { 22 | return clamp(f, 0.0, 1.0); 23 | } 24 | 25 | vec3 saturate(vec3 v) { 26 | return clamp(v, vec3(0.0), vec3(1.0)); 27 | } 28 | 29 | //Sampled from a texture generated by code based on 30 | //http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html 31 | vec2 Hammersley(int i, int N) { 32 | return texture2D(uHammersleyPointSetMap, vec2(0.5, (float(i) + 0.5)/float(N))).rg; 33 | } 34 | 35 | //Based on Real Shading in Unreal Engine 4 36 | vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { 37 | //this is mapping 2d point to a hemisphere but additionally we add spread by roughness 38 | float a = Roughness * Roughness; 39 | float Phi = 2.0 * PI * Xi.x + random(N.xz) * 0.1; 40 | float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); 41 | float SinTheta = sqrt(1.0 - CosTheta * CosTheta); 42 | vec3 H; 43 | H.x = SinTheta * cos(Phi); 44 | H.y = SinTheta * sin(Phi); 45 | H.z = CosTheta; 46 | 47 | //Tangent space vectors 48 | vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); 49 | vec3 TangentX = normalize(cross(UpVector, N)); 50 | vec3 TangentY = normalize(cross(N, TangentX)); 51 | 52 | //Tangent to World Space 53 | return TangentX * H.x + TangentY * H.y + N * H.z; 54 | 55 | // 56 | //vec3 n = N; 57 | //float aa = 1.0 / (1.0 + n.z); 58 | //float b = -n.x * n.y * aa; 59 | //vec3 b1 = vec3(1.0 - n.x * n.x * aa, b, -n.x); 60 | //vec3 b2 = vec3(b, 1.0 - n.y * n.y * aa, -n.y); 61 | //mat3 vecSpace = mat3(b1, b2, n); 62 | //return normalize(mix(vecSpace * H, N, 1.0 - Roughness)); 63 | } 64 | 65 | vec3 PrefilterEnvMap( float Roughness, vec3 R ) { 66 | vec3 N = R; 67 | vec3 V = R; 68 | vec3 PrefilteredColor = vec3(0.0); 69 | const int NumSamples = 1024;//1024 70 | float TotalWeight = 0.0; 71 | for( int i = 0; i < NumSamples; i++ ) { 72 | if (i > uNumSamples) { 73 | break; 74 | } 75 | vec2 Xi = Hammersley( i, NumSamples ); 76 | vec3 H = ImportanceSampleGGX( Xi, Roughness, N ); 77 | vec3 L = 2.0 * dot( V, H ) * H - V; 78 | float NoL = saturate( dot( N, L ) ); 79 | if( NoL > 0.0 ) { 80 | PrefilteredColor += textureCube( uEnvMap, L).rgb * NoL; 81 | TotalWeight += NoL; 82 | } 83 | } 84 | return PrefilteredColor / TotalWeight; 85 | } 86 | 87 | void main() { 88 | vec3 normal = normalize( wcNormal ); 89 | 90 | gl_FragColor.rgb = PrefilterEnvMap(uRoughness, normal); 91 | gl_FragColor.a = 1.0; 92 | } 93 | -------------------------------------------------------------------------------- /local_modules/prefilter-cubemap/glsl/prefilter.vert: -------------------------------------------------------------------------------- 1 | #pragma glslify: inverse = require('glsl-inverse') 2 | 3 | #ifdef GL_ES 4 | #pragma glslify: transpose = require('glsl-transpose') 5 | #endif 6 | 7 | attribute vec4 aPosition; 8 | 9 | uniform mat4 uProjectionMatrix; 10 | uniform mat4 uViewMatrix; 11 | uniform mat4 uInverseViewMatrix; 12 | 13 | varying vec3 wcNormal; 14 | varying vec2 scPosition; 15 | 16 | void main() { 17 | mat4 inverseProjection = inverse(uProjectionMatrix); 18 | mat3 inverseModelview = transpose(mat3(uViewMatrix)); 19 | vec3 unprojected = (inverseProjection * aPosition).xyz; 20 | wcNormal = inverseModelview * unprojected; 21 | gl_Position = aPosition; 22 | scPosition = aPosition.xy; 23 | } 24 | -------------------------------------------------------------------------------- /local_modules/prefilter-cubemap/index.js: -------------------------------------------------------------------------------- 1 | var renderToCubemap = require('../render-to-cubemap'); 2 | var glslifySync = require('glslify-sync'); 3 | var hammersley = require('hammersley'); 4 | var isBrowser = require('is-browser'); 5 | 6 | var VERT = glslifySync(__dirname + '/glsl/prefilter.vert'); 7 | var FRAG = glslifySync(__dirname + '/glsl/prefilter.frag'); 8 | 9 | var quadPositions = [[-1,-1],[1,-1], [1,1],[-1,1]]; 10 | var quadFaces = [ [0, 1, 2], [0, 2, 3]]; 11 | 12 | var quadMesh = null; 13 | var prefilterProgram = null; 14 | 15 | function prefilterCubemap(ctx, fromCubemap, toCubemap, options) { 16 | options = options || {}; 17 | var highQuality = (options.highQuality !== undefined) ? options.highQuality : true; 18 | 19 | var numSamples = highQuality ? 1024 : 128; 20 | var hammersleyPointSet = new Float32Array(4 * numSamples); 21 | for(var i=0; i (http://marcinignac.com/)", 7 | "license": "MIT", 8 | "dependencies": { 9 | "glsl-inverse": "^1.0.0", 10 | "glsl-transpose": "^1.0.0", 11 | "hammersley": "^1.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /local_modules/prefilter-octmap/glsl/PrefilterOctmap.frag: -------------------------------------------------------------------------------- 1 | //Based on Article - Physically Based Rendering by Marco Alamia 2 | //http://www.codinglabs.net/article_physically_based_rendering.aspx 3 | 4 | #ifdef GL_ES 5 | precision highp float; 6 | #define GLSLIFY 1 7 | #else 8 | //this is invalid but i don't have anything better for Plask now 9 | #define texture2DLod texture2D 10 | #endif 11 | 12 | float random(vec2 co) 13 | { 14 | return fract(sin(dot(co.xy,vec2(12.9898,78.233))) * 43758.5453); 15 | } 16 | 17 | //if < 0 return -1, otherwise 1 18 | vec2 sign(vec2 v) { 19 | return step(0.0, v) * 2.0 - 1.0; 20 | } 21 | 22 | vec3 octUvToDir(vec2 uv) { 23 | uv = uv * 2.0 - 1.0; 24 | 25 | vec2 auv = abs(uv); 26 | float len = dot(auv, vec2(1.0)); 27 | 28 | if (len > 1.0) { 29 | //y < 0 case 30 | uv = (auv.yx - 1.0) * -1.0 * sign(uv); 31 | } 32 | 33 | return normalize(vec3(uv.x, 1.0 - len, uv.y)); 34 | } 35 | 36 | 37 | varying vec2 vTexCoord0; 38 | 39 | uniform sampler2D uOctMap; 40 | uniform sampler2D uHammersleyPointSetMap; 41 | uniform float uRoughness; 42 | uniform int uNumSamples; 43 | 44 | const float PI = 3.1415926536; 45 | 46 | float saturate(float f) { 47 | return clamp(f, 0.0, 1.0); 48 | } 49 | 50 | vec3 saturate(vec3 v) { 51 | return clamp(v, vec3(0.0), vec3(1.0)); 52 | } 53 | 54 | //Sampled from a texture generated by code based on 55 | //http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html 56 | vec2 Hammersley(int i, int N) { 57 | return texture2D(uHammersleyPointSetMap, vec2(0.5, (float(i) + 0.5)/float(N))).rg; 58 | } 59 | 60 | //Based on Real Shading in Unreal Engine 4 61 | vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { 62 | //this is mapping 2d point to a hemisphere but additionally we add spread by roughness 63 | float a = Roughness * Roughness; 64 | float Phi = 2.0 * PI * Xi.x + random(N.xz) * 0.1; 65 | float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); 66 | float SinTheta = sqrt(1.0 - CosTheta * CosTheta); 67 | vec3 H; 68 | H.x = SinTheta * cos(Phi); 69 | H.y = SinTheta * sin(Phi); 70 | H.z = CosTheta; 71 | 72 | //Tangent space vectors 73 | vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); 74 | vec3 TangentX = normalize(cross(UpVector, N)); 75 | vec3 TangentY = normalize(cross(N, TangentX)); 76 | 77 | //Tangent to World Space 78 | return TangentX * H.x + TangentY * H.y + N * H.z; 79 | 80 | // 81 | //vec3 n = N; 82 | //float aa = 1.0 / (1.0 + n.z); 83 | //float b = -n.x * n.y * aa; 84 | //vec3 b1 = vec3(1.0 - n.x * n.x * aa, b, -n.x); 85 | //vec3 b2 = vec3(b, 1.0 - n.y * n.y * aa, -n.y); 86 | //mat3 vecSpace = mat3(b1, b2, n); 87 | //return normalize(mix(vecSpace * H, N, 1.0 - Roughness)); 88 | } 89 | 90 | //TODO: optimize this using sign() 91 | //Source: http://webglinsights.github.io/downloads/WebGL-Insights-Chapter-16.pdf 92 | vec2 octahedralProjection(vec3 dir) { 93 | dir/= dot(vec3(1.0), abs(dir)); 94 | vec2 rev = abs(dir.zx) - vec2(1.0,1.0); 95 | vec2 neg = vec2( 96 | dir.x < 0.0 ? rev.x : -rev.x, 97 | dir.z < 0.0 ? rev.y : -rev.y 98 | ); 99 | vec2 uv = dir.y < 0.0 ? neg : dir.xz; 100 | return 0.5 * uv + vec2(0.5, 0.5); 101 | } 102 | 103 | vec3 PrefilterEnvMap( float Roughness, vec3 R ) { 104 | vec3 N = R; 105 | vec3 V = R; 106 | vec3 PrefilteredColor = vec3(0.0); 107 | const int NumSamples = 1024;//1024 108 | float TotalWeight = 0.0; 109 | for( int i = 0; i < NumSamples; i++ ) { 110 | if (i > uNumSamples) { 111 | break; 112 | } 113 | vec2 Xi = Hammersley( i, NumSamples ); 114 | vec3 H = ImportanceSampleGGX( Xi, Roughness, N ); 115 | vec3 L = 2.0 * dot( V, H ) * H - V; 116 | float NoL = saturate( dot( N, L ) ); 117 | if( NoL > 0.0 ) { 118 | PrefilteredColor += texture2DLod( uOctMap, octahedralProjection(L), 0.0).rgb * NoL; 119 | TotalWeight += NoL; 120 | } 121 | } 122 | return PrefilteredColor / TotalWeight; 123 | } 124 | 125 | void main() { 126 | vec3 normal = octUvToDir(vTexCoord0); 127 | 128 | gl_FragColor.rgb = PrefilterEnvMap(uRoughness, normal); 129 | gl_FragColor.a = 1.0; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /local_modules/prefilter-octmap/glsl/PrefilterOctmap.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aPosition; 2 | attribute vec2 aTexCoord0; 3 | 4 | varying vec2 vTexCoord0; 5 | 6 | void main() { 7 | vTexCoord0 = aTexCoord0; 8 | gl_Position = aPosition; 9 | } 10 | -------------------------------------------------------------------------------- /local_modules/prefilter-octmap/index.js: -------------------------------------------------------------------------------- 1 | var glslifySync = require('glslify-sync'); 2 | var hammersley = require('hammersley'); 3 | 4 | var VERT = glslifySync(__dirname + '/glsl/PrefilterOctmap.vert'); 5 | var FRAG = glslifySync(__dirname + '/glsl/PrefilterOctmap.frag'); 6 | 7 | var fbo = null 8 | var mesh = null 9 | var program = null 10 | var hammersleyPointSetMap = null 11 | 12 | function prefilterOctmap(ctx, fromOctmap, toOctmapAtlas) { 13 | var highQuality = true; 14 | var numSamples = highQuality ? 1024 : 128; 15 | 16 | if (!fbo) { 17 | fbo = ctx.createFramebuffer() 18 | 19 | var positions = [[-1, -1], [1, -1], [1, 1], [-1, 1]] 20 | var uvs = [[0,0], [1,0], [1,1], [0,1]] 21 | var indices = [[0, 1, 2], [0, 2, 3]] 22 | 23 | mesh = ctx.createMesh([ 24 | { data: positions, location: ctx.ATTRIB_POSITION }, 25 | { data: uvs, location: ctx.ATTRIB_TEX_COORD_0 } 26 | ], { data: indices }, ctx.TRIANGLES) 27 | 28 | program = ctx.createProgram(VERT, FRAG) 29 | 30 | var hammersleyPointSet = new Float32Array(4 * numSamples); 31 | for(var i=0; i>= 1 66 | h >>= 1 67 | } 68 | 69 | // program.setUniform('uOctmap', 0) 70 | ctx.popState() 71 | } 72 | 73 | module.exports = prefilterOctmap; 74 | -------------------------------------------------------------------------------- /local_modules/primitive-icosahedron/index.js: -------------------------------------------------------------------------------- 1 | function createIcosahedron(r) { 2 | r = r || 0.5; 3 | 4 | var phi = (1 + Math.sqrt(5)) / 2; 5 | var a = r * 1 / 2; 6 | var b = r * 1 / (2 * phi); 7 | 8 | var positions = [ 9 | [ 0, b, -a ], 10 | [ b, a, 0 ], 11 | [ -b, a, 0 ], 12 | [ 0, b, a ], 13 | [ 0, -b, a ], 14 | [ -a, 0, b ], 15 | [ a, 0, b ], 16 | [ 0, -b, -a ], 17 | [ a, 0, -b ], 18 | [ -a, 0, -b ], 19 | [ b, -a, 0 ], 20 | [ -b, -a, 0 ] 21 | ]; 22 | 23 | var normals = positions.map(function(p) { 24 | var len = Math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]); 25 | return [ p[0] / len, p[1] / len, p[2] / len ]; 26 | }); 27 | 28 | var cells = [ 29 | [ 1, 0, 2 ], 30 | [ 2, 3, 1 ], 31 | [ 4, 3, 5 ], 32 | [ 6, 3, 4 ], 33 | [ 7, 0, 8 ], 34 | [ 9, 0, 7 ], 35 | [ 10, 4, 11 ], 36 | [ 11, 7, 10 ], 37 | [ 5, 2, 9 ], 38 | [ 9, 11, 5 ], 39 | [ 8, 1, 6 ], 40 | [ 6, 10, 8 ], 41 | [ 5, 3, 2 ], 42 | [ 1, 3, 6 ], 43 | [ 2, 0, 9 ], 44 | [ 8, 0, 1 ], 45 | [ 9, 7, 11 ], 46 | [ 10, 7, 8 ], 47 | [ 11, 4, 5 ], 48 | [ 6, 4, 10 ] 49 | ]; 50 | 51 | return { 52 | positions: positions, 53 | normals: normals, 54 | cells: cells 55 | } 56 | } 57 | 58 | module.exports = createIcosahedron; 59 | -------------------------------------------------------------------------------- /local_modules/primitive-octahedron/index.js: -------------------------------------------------------------------------------- 1 | function createOctahedron(r) { 2 | r = r || 0.5; 3 | 4 | var a = 1 / (2 * Math.sqrt(2)); 5 | var b = 1 / 2; 6 | 7 | var s3 = Math.sqrt(3); 8 | var s6 = Math.sqrt(6); 9 | 10 | var positions = [ 11 | [ -a, 0, a ], 12 | [ a, 0, a ], 13 | [ a, 0,-a ], 14 | [ -a, 0,-a ], 15 | [ 0, b, 0 ], 16 | [ 0,-b, 0 ] 17 | ]; 18 | 19 | positions.forEach(function(p) { 20 | var len = Math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]); 21 | p[0] = p[0] / len * r; 22 | p[1] = p[1] / len * r; 23 | p[2] = p[2] / len * r; 24 | }) 25 | 26 | var normals = positions.map(function(p) { 27 | var len = Math.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]); 28 | return [ p[0] / len, p[1] / len, p[2] / len ]; 29 | }); 30 | 31 | var cells = [ 32 | [3, 0, 4], 33 | [2, 3, 4], 34 | [1, 2, 4], 35 | [0, 1, 4], 36 | [3, 2, 5], 37 | [0, 3, 5], 38 | [2, 1, 5], 39 | [1, 0, 5] 40 | ]; 41 | 42 | return { 43 | positions: positions, 44 | normals: normals, 45 | cells: cells 46 | } 47 | } 48 | 49 | module.exports = createOctahedron; 50 | -------------------------------------------------------------------------------- /local_modules/render-to-cubemap/index.js: -------------------------------------------------------------------------------- 1 | var Mat4 = require('pex-math/Mat4'); 2 | 3 | //Flipping up by -1 inspired by http://www.mbroecker.com/project_dynamic_cubemaps.html 4 | var sides = [ 5 | { eye: [0, 0, 0], target: [ 1, 0, 0], up: [0, -1, 0] }, 6 | { eye: [0, 0, 0], target: [-1, 0, 0], up: [0, -1, 0] }, 7 | { eye: [0, 0, 0], target: [0, 1, 0], up: [0, 0, 1] }, 8 | { eye: [0, 0, 0], target: [0, -1, 0], up: [0, 0,-1] }, 9 | { eye: [0, 0, 0], target: [0, 0, 1], up: [0, -1, 0] }, 10 | { eye: [0, 0, 0], target: [0, 0, -1], up: [0, -1, 0] }, 11 | ]; 12 | 13 | var fbo = null; 14 | var projectionMatrix = null; 15 | var viewMatrix = null; 16 | 17 | function renderToCubemap(ctx, cubemap, drawScene, level) { 18 | level = level || 0; 19 | if (!fbo) { 20 | fbo = ctx.createFramebuffer(); 21 | projectionMatrix = Mat4.perspective(Mat4.create(), 90, 1, 0.001, 50.0); 22 | viewMatrix = Mat4.create(); 23 | } 24 | 25 | var levelScale = 1.0 / Math.pow(2.0, level); 26 | 27 | ctx.pushState(ctx.VIEWPORT_BIT | ctx.FRAMEBUFFER_BIT | ctx.MATRIX_PROJECTION_BIT | ctx.MATRIX_VIEW_BIT | ctx.COLOR_BIT); 28 | ctx.setViewport(0, 0, cubemap.getWidth()*levelScale, cubemap.getHeight()*levelScale); 29 | ctx.bindFramebuffer(fbo); 30 | ctx.setProjectionMatrix(projectionMatrix); 31 | sides.forEach(function(side, sideIndex) { 32 | fbo.setColorAttachment(0, ctx.TEXTURE_CUBE_MAP_POSITIVE_X + sideIndex, cubemap.getHandle(), level); 33 | ctx.setClearColor(0, 0, 0, 0); 34 | ctx.clear(ctx.COLOR_BIT | ctx.DEPTH_BIT); 35 | Mat4.lookAt(viewMatrix, side.eye, side.target, side.up); 36 | ctx.setViewMatrix(viewMatrix); 37 | drawScene(); 38 | }) 39 | ctx.popState(ctx.VIEWPORT_BIT | ctx.FRAMEBUFFER_BIT | ctx.MATRIX_PROJECTION_BIT | ctx.MATRIX_VIEW_BIT | ctx.COLOR_BIT); 40 | } 41 | 42 | module.exports = renderToCubemap; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pragmatic-pbr", 3 | "version": "0.0.0", 4 | "description": "Implementing Physically Based Rendering from scratch in pex", 5 | "main": "index.js", 6 | "scripts": {}, 7 | "keywords": [ 8 | "pbr", 9 | "webgl", 10 | "pex" 11 | ], 12 | "author": { 13 | "name": "Marcin Ignac", 14 | "email": "marcin.ignac@gmail.com", 15 | "url": "http://marcinignac.com" 16 | }, 17 | "license": "MIT", 18 | "dependencies": { 19 | "clone": "^1.0.2", 20 | "glsl-diffuse-lambert": "^1.0.0", 21 | "glsl-gamma": "^2.0.0", 22 | "glsl-inverse": "^1.0.0", 23 | "glsl-perturb-normal": "^1.0.2", 24 | "glsl-random": "^0.0.5", 25 | "glsl-specular-cook-torrance": "^2.0.1", 26 | "glsl-specular-phong": "^1.0.0", 27 | "glsl-transpose": "^1.0.0", 28 | "glslify-import": "^1.0.0", 29 | "glslify-promise": "^1.0.1", 30 | "glslify-sync": "^1.1.1", 31 | "hammersley": "^1.0.0", 32 | "is-browser": "^2.0.1", 33 | "is-mobile": "^0.2.2", 34 | "parse-dds": "^1.2.1", 35 | "pex-cam": "^1.0.0-beta.2", 36 | "pex-context": "^1.1.0", 37 | "pex-draw": "^1.0.0-beta.2", 38 | "pex-geom": "^1.0.0-beta.1", 39 | "pex-gui": "^1.2.0", 40 | "pex-io": "^1.1.0", 41 | "pex-math": "^1.0.0", 42 | "pex-random": "^1.0.0", 43 | "pex-sys": "^1.1.1", 44 | "primitive-box": "^1.0.0", 45 | "primitive-capsule": "^2.0.2", 46 | "primitive-cube": "^2.0.0", 47 | "primitive-sphere": "^2.0.0", 48 | "ray-aabb-intersection": "^1.0.1", 49 | "ray-sphere-intersection": "^1.0.0", 50 | "re-map": "^0.1.1", 51 | "watchify": "^3.7.0" 52 | }, 53 | "devDependencies": { 54 | "browserify": "^11.0.1", 55 | "beefy": "^2.1.5" 56 | }, 57 | "repository": { 58 | "type": "git", 59 | "url": "https://github.com/vorg/pragmatic-pbr.git" 60 | }, 61 | "bugs": { 62 | "url": "https://github.com/vorg/pragmatic-pbr/issues" 63 | }, 64 | "homepage": "https://github.com/vorg/pragmatic-pbr" 65 | } 66 | --------------------------------------------------------------------------------