From 22f203ad1fe35bc5d0155152769087d26bb34b1b Mon Sep 17 00:00:00 2001 From: Jonas Wagner Date: Sun, 13 Mar 2016 16:01:52 +0100 Subject: [PATCH] v0.0.0 --- dist/jquery.normalmap.js | 62 ++++ dist/normalmap.js | 731 +++++++++++++++++++++++++++++++++++++++ dist/normalmap.min.js | 1 + 3 files changed, 794 insertions(+) create mode 100644 dist/jquery.normalmap.js create mode 100644 dist/normalmap.js create mode 100644 dist/normalmap.min.js diff --git a/dist/jquery.normalmap.js b/dist/jquery.normalmap.js new file mode 100644 index 0000000..5603f5e --- /dev/null +++ b/dist/jquery.normalmap.js @@ -0,0 +1,62 @@ +/* globals jQuery, normalmap */ +(function() { + +var $ = jQuery; + +$.fn.normalmap = function(options){ + if(this.length === 0) return; + if(this[0].tagName !== 'CANVAS') { + throw new Error('$.fn.normalmap only works on a single element'); + } + return loadImages(this[0], options); +}; + +function loadImages(canvas, options){ + var maps = ['normalMap', 'baseColorMap', 'materialMap', 'ambientMap']; + return $.when.apply($, $.map(maps, function(o){ return loadImage(options[o]); })) + .then(function(){ + for(var i = 0; i < arguments.length; i++){ + options[maps[i]] = arguments[i]; + } + if(!options.repeat) { + canvas.width = options.normalMap.naturalWidth; + canvas.height = options.normalMap.naturalHeight; + } + options.canvas = canvas; + var lights = normalmap(options); + $(window).on('resize', lights.resize); + return lights; + }); +} + +function loadImage(src){ + var deferred = $.Deferred(); + function trackImage(img){ + img.onload = function(){ deferred.resolve(img); }; + img.onerror = function(){ deferred.reject(new Error('image failed to load')); }; + } + if(src){ + if(jQuery.type(src) === 'string'){ + var img = new Image(); + trackImage(img); + img.crossorigin = 'anonymous'; + img.src = src; + } + // assume image + else { + if(src.tagName === 'IMG' && src.complete === false) { + trackImage(src); + } + else { + deferred.resolve(src); + } + } + } + else { + deferred.resolve(); + } + return deferred.promise(); +} +$.fn.normalmap._loadImage = loadImage; + +}()); diff --git a/dist/normalmap.js b/dist/normalmap.js new file mode 100644 index 0000000..3d7fa55 --- /dev/null +++ b/dist/normalmap.js @@ -0,0 +1,731 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.normalmap = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ot;t++){var i=e.getActiveUniform(n,t);r[i.name]={type:i.type,size:i.size,location:e.getUniformLocation(n,i.name)}}return r}function s(e,n,r){var a=e.createShader(n);if(e.shaderSource(a,r),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw Error('Shader compiler error: "'+e.getShaderInfoLog(a)+'"');return a}function l(e,n,r){var a=s(e,e.FRAGMENT_SHADER,r),t=s(e,e.VERTEX_SHADER,n),i=e.createProgram();if(e.attachShader(i,t),e.attachShader(i,a),e.bindAttribLocation(i,0,"aPosition"),e.linkProgram(i),!e.getProgramParameter(i,e.LINK_STATUS))throw Error("Shader linker error: "+e.getProgramInfoLog(i));return i}function u(e,n){for(var r=!0,a=0;an&&console.warn("shader missing uniform",e),this.uniformLocations[e]=n}return this.uniformLocations[e]},getAttribLocation:function(e){if(!(e in this.attributeLocations)){var n=this.gl.getAttribLocation(this.program,e);0>n&&console.warn("shader missing attribute",e),this.attributeLocations[e]=n}return this.attributeLocations[e]}}},{}],5:[function(e,n,r){n.exports="#ifdef USE_AMBIENT_MAP\nuniform sampler2D uAmbientSampler;\nuniform float uAmbient;\n\nvoid addAmbient(inout vec4 fragColor){\n vec4 ambient = texture2D(uAmbientSampler, vUv);\n ambient.rgb *= uAmbient * ambient.a;\n fragColor.rgb = fragColor.rgb*fragColor.a + ambient.rgb;\n // this is a bit of a hack but it allows for a separate alpha in both\n // while not messing up when they are blended\n fragColor.a = max(fragColor.a, ambient.a);\n}\n#endif\n"},{}],6:[function(e,n,r){n.exports='#include "common.glsl"\n\n// Epic approximation of schlicks\n// F0 is the specular reflectance at normal incidence.\n// via: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nvec3 F_schlick( vec3 F0, float dotLH ) {\n float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n return ( 1.0 - F0 ) * fresnel + F0;\n}\n\n// normal distribution\n// alpha = roughness^2\n// via: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nfloat D_ggx(const in float dotNH, const in float alpha) {\n float alphaSquared = alpha * alpha;\n float denominator = dotNH*dotNH * (alphaSquared - 1.0) + 1.0;\n return (alphaSquared) / (PI * denominator*denominator);\n}\n\n// geometric attenuation\n// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf\nfloat G_ggx(const in float dotNL, const in float dotNV, const in float roughness) {\n float k = (roughness + 1.0);\n k = k*k / 8.0;\n float l = dotNL / ( dotNL * (1.0-k) + k);\n float v = dotNV / ( dotNV * (1.0-k) + k);\n return l * v;\n}\n\n// n = normal\n// l = light direction\n// v = view direction\n// F0 specular color\n// h = half angle between l and v\nvec3 brdf_ggx(vec3 n, vec3 l, vec3 v, vec3 F0, float roughness) {\n float alpha = roughness * roughness;\n vec3 h = normalize(l + v);\n\n float dotNL = saturate(dot(n, l));\n float dotNV = saturate(dot(n, v));\n float dotNH = saturate(dot(n, h));\n float dotLH = saturate(dot(l, h));\n\n vec3 F = F_schlick(F0, dotLH);\n float D = D_ggx(dotNH, alpha);\n float G = G_ggx(dotNL, dotNV, roughness);\n\n return F * ( G * D );\n}\n'},{}],7:[function(e,n,r){n.exports="#define saturate(x) clamp(x, 0.0, 1.0)\nconst float PI = 3.14159265359;\nconst float RECIPROCAL_PI = 1.0 / PI;\nconst float EPSILON = 1e-30;\n\nfloat gammaEncode(const in float linear){\n return pow(linear, 1.0/2.2);\n}\nvec3 gammaEncode(const in vec3 linear) {\n return pow(linear, vec3(1.0/2.2));\n}\nvec4 gammaEncode(const in vec4 linear) {\n return vec4(pow(linear.rgb, vec3(1.0/2.2)), linear.a);\n}\n\nvec3 gammaDecode(const in vec3 linear) {\n return pow(linear, vec3(2.2));\n}\n"},{}],8:[function(e,n,r){n.exports="// based on nvidia fxaa 3.11 console https://gist.github.com/bkaradzic/6011431\n// https://github.com/mitsuhiko/webgl-meincraft/blob/master/assets/shaders/fxaa.glsl\n// it has been modified with little testing and is quite possibly broken now.\n\n// 0.125 leaves less aliasing, but is softer (default!!!)\n// 0.25 leaves more aliasing, and is sharper\nconst float fxaaEdgeThreshold = 0.125;\n// 0.06 - faster but more aliasing in darks\n// 0.05 - default\n// 0.04 - slower and less aliasing in darks\nconst float fxaaConsoleEdgeThresholdMin = 0.00;\n\n// 8.0 is sharper (default!!!)\n// 4.0 is softer\n// 2.0 is really soft (good only for vector graphics inputs)\nconst float fxaaConsoleEdgeSharpness = 8.0;\n\n// for some reason fxaa wants gamma encoded values\n// so I gamma encode on the fly\nfloat fxaaLuma(vec4 color){\n const vec4 luma = vec4(0.299, 0.587, 0.114, 0.0);\n return gammaEncode(dot(saturate(color), luma));\n}\n\nvec4 fxaa(vec2 uv, const vec2 resolution, sampler2D sampler) {\n // N = 0.50 (default)\n // N = 0.33 (sharper)\n vec4 fxaaConsoleRcpFrameOpt = vec4(0.33) / vec4(-resolution.x, -resolution.y, resolution.x, resolution.y);\n vec4 fxaaConsoleRcpFrameOpt2 = vec4(2.0) / vec4(-resolution.x, -resolution.y, resolution.x, resolution.y);\n\n // vec2 inverseVP = vec2(1.0 / uViewportSize.x, 1.0 / uViewportSize.y);\n vec2 pixelOffset = vec2(1.0)/resolution;\n\n vec4 rgbNw = texture2D(sampler, (uv + vec2(-1.0, -1.0)) * pixelOffset);\n vec4 rgbNe = texture2D(sampler, (uv + vec2(1.0, -1.0)) * pixelOffset);\n vec4 rgbSw = texture2D(sampler, (uv + vec2(-1.0, 1.0)) * pixelOffset);\n vec4 rgbSe = texture2D(sampler, (uv + vec2(1.0, 1.0)) * pixelOffset);\n vec4 rgbM = texture2D(sampler, uv);\n\n // ffxaa wants luma to be\n float lumaNw = fxaaLuma(rgbNw);\n float lumaNe = fxaaLuma(rgbNe);\n float lumaSw = fxaaLuma(rgbSw);\n float lumaSe = fxaaLuma(rgbSe);\n float lumaM = fxaaLuma(rgbM);\n\n float lumaMaxNwSw = max(lumaNw, lumaSw);\n lumaNe += 1.0/384.0;\n float lumaMinNwSw = min(lumaNw, lumaSw);\n\n float lumaMaxNeSe = max(lumaNe, lumaSe);\n float lumaMinNeSe = min(lumaNe, lumaSe);\n\n float lumaMax = max(lumaMaxNeSe, lumaMaxNwSw);\n float lumaMin = min(lumaMinNeSe, lumaMinNwSw);\n\n float lumaMaxScaled = lumaMax * fxaaEdgeThreshold;\n\n float lumaMinM = min(lumaMin, lumaM);\n float lumaMaxScaledClamped = max(fxaaConsoleEdgeThresholdMin, lumaMaxScaled);\n float lumaMaxM = max(lumaMax, lumaM);\n float dirSwMinusNe = lumaSw - lumaNe;\n float lumaMaxSubMinM = lumaMaxM - lumaMinM;\n float dirSeMinusNw = lumaSe - lumaNw;\n // early out\n // if(lumaMaxSubMinM < lumaMaxScaledClamped) return vec4(1.0, 0.0, 0.0, 1.0);\n if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbM;\n\n vec2 dir = dirSwMinusNe + vec2(dirSeMinusNw, -dirSeMinusNw);\n\n vec2 dir1 = normalize(dir.xy);\n // this is suboptimal. It would probably be more efficient to do this in another stage.\n vec4 rgbyN1 = gammaEncode(saturate(texture2D(sampler, uv - dir1 * fxaaConsoleRcpFrameOpt.zw)));\n vec4 rgbyP1 = gammaEncode(saturate(texture2D(sampler, uv + dir1 * fxaaConsoleRcpFrameOpt.zw)));\n\n float dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * fxaaConsoleEdgeSharpness;\n vec2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0);\n\n vec4 rgbyN2 = gammaEncode(saturate(texture2D(sampler, uv - dir2 * fxaaConsoleRcpFrameOpt2.zw)));\n vec4 rgbyP2 = gammaEncode(saturate(texture2D(sampler, uv + dir2 * fxaaConsoleRcpFrameOpt2.zw)));\n\n vec4 rgbyA = rgbyN1 + rgbyP1;\n vec4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25);\n\n bool twoTap = (rgbyB.y < lumaMin) || (rgbyB.y > lumaMax);\n\n if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5;\n\n return rgbyB;\n}\n"},{}],9:[function(e,n,r){n.exports='precision highp float;\n#include "common.glsl"\n#include "brdf.glsl"\n\nuniform sampler2D uNormalSampler;\n\n#ifdef USE_BASE_COLOR_MAP\nuniform sampler2D uBaseColorSampler;\n#endif\n\n#ifdef USE_MATERIAL_MAP\nuniform sampler2D uMaterialSampler;\n#endif\n\nuniform vec3 uBaseColor;\nuniform float uMetalness;\nuniform float uRoughness;\n\n#ifdef IS_POINT_LIGHT\nuniform vec3 uLightPosition;\n#endif\n\n#ifdef USE_SSS\nuniform float uSubSurfaceScattering;\n#endif\n\n#ifdef IS_DIRECTIONAL_LIGHT\nuniform vec3 uLightDirection;\n#endif\n\nuniform vec3 uLightColor;\nuniform float uViewportAspect;\nuniform float uScale;\n\nvarying vec2 vUv;\nvarying vec3 vPosition;\n\n#ifdef USE_SINGLE_PASS\n#include "ambient.glsl"\n#endif\n\nconst vec3 eye = vec3(0.5, 0.5, 100.0);\n\nfloat attenuation(float distance){\n return 1.0/(distance*distance);\n}\n\nvec3 rgbToNormal(vec3 rgb){\n return normalize(rgb - vec3(0.5));\n}\n\nvoid main(){\n vec4 normalSample = texture2D(uNormalSampler, vUv);\n float alpha = normalSample.a;\n vec3 normal = rgbToNormal(normalSample.rgb);\n#ifdef USE_SSS\n vec4 diffuseNormalSample = texture2D(uNormalSampler, vUv, uSubSurfaceScattering);\n vec3 diffuseNormal = rgbToNormal(diffuseNormalSample.rgb);\n#else\n#define diffuseNormal normal\n#endif\n\n float metalness = uMetalness;\n float roughness = uRoughness;\n\n#ifdef USE_MATERIAL_MAP\n vec4 materialSample = texture2D(uMaterialSampler, vUv);\n metalness *= materialSample.r;\n roughness *= materialSample.g;\n float occlusion = materialSample.b;\n#endif\n\n metalness = saturate(metalness);\n roughness = clamp(roughness, EPSILON, 1.0);\n\n vec3 baseColor = uBaseColor;\n\n#ifdef USE_BASE_COLOR_MAP\n vec4 baseColorSample = texture2D(uBaseColorSampler, vUv);\n baseColor *= gammaDecode(baseColorSample.rgb);\n#endif\n\n vec3 diffuseColor = mix(baseColor, vec3(0.0), metalness);\n // ?\n vec3 specularColor = mix(vec3(0.04), baseColor.rgb, metalness)*0.5;\n\n#ifdef IS_POINT_LIGHT\n vec3 lightOffset = vPosition - uLightPosition;\n lightOffset.y /= uViewportAspect;\n float lightDistance = length(lightOffset);\n float falloff = attenuation(lightDistance);\n vec3 lightDirection = lightOffset/lightDistance;\n#endif\n\n#ifdef IS_DIRECTIONAL_LIGHT\n float falloff = 1.0;\n vec3 lightDirection = uLightDirection;\n#endif\n\n vec3 eyeDirection = normalize(eye - vPosition);\n vec3 diffuse = max(0.0, -dot(diffuseNormal, lightDirection))*diffuseColor;\n // linear = vec3(roughness);\n vec3 specular = brdf_ggx(normal, -lightDirection, eyeDirection, specularColor, roughness);\n vec3 intensity = (diffuse+specular)*falloff;\n\n#ifdef USE_MATERIAL_MAP\n intensity *= occlusion;\n#endif\n\n vec3 linear = uLightColor*intensity;\n // linear = specularColor;\n // linear.r = metalness;\n // linear = vec3(uRoughness*materialSample.g == materialSample.g ? 1.0 : 0.0);\n // linear.b = occlusion;\n\n gl_FragColor = vec4(linear, alpha);\n\n#ifdef USE_SINGLE_PASS\n gl_FragColor = gammaEncode(gl_FragColor);\n#ifdef USE_AMBIENT_MAP\n addAmbient(gl_FragColor);\n#endif\n#endif\n\n}\n'},{}],10:[function(e,n,r){n.exports='precision highp float;\n#include "common.glsl"\n#include "fxaa.glsl"\n\nuniform sampler2D uFrameBufferSampler;\nuniform vec2 uFrameBufferResolution;\n\nvarying vec3 vPosition;\n\n#ifdef USE_AMBIENT_MAP\nvarying vec2 vUv;\n#endif\n\n#include "ambient.glsl"\n\nvoid main(){\n#ifdef USE_FXAA\n // fxaa does gammaEncode .. for now\n vec4 frameBuffer = fxaa(vec2(vPosition.x, 1.0 - vPosition.y), uFrameBufferResolution, uFrameBufferSampler);\n#endif\n#ifndef USE_FXAA\n vec4 frameBuffer = gammaEncode(texture2D(uFrameBufferSampler, vec2(vPosition.x, 1.0 - vPosition.y)));\n#endif\n gl_FragColor = frameBuffer;\n// assume SRGB\n#ifdef USE_AMBIENT_MAP\n addAmbient(gl_FragColor);\n#endif\n}\n'},{}],11:[function(e,n,r){n.exports="attribute vec3 aPosition;\n#ifdef USE_AMBIENT_MAP\nvarying vec2 vUv;\n#endif\n\nvoid main(){\n vUv = vec2(0.5)-(aPosition.xy)*vec2(-0.5, 0.5);\n gl_Position = vec4(aPosition, 1.0);\n}\n"},{}],12:[function(e,n,r){n.exports="attribute vec3 aPosition;\n\nuniform float uScale;\nuniform float uTextureAspect;\n\nvarying vec2 vUv;\nvarying vec3 vPosition;\n\nvoid main(){\n vPosition = vec3(vec2(0.5)-(aPosition.xy)*vec2(-0.5, 0.5), 0);\n vUv = vPosition.xy * uScale * vec2(1.0, 1.0/uTextureAspect);\n gl_Position = vec4(aPosition, 1.0);\n}\n"},{}]},{},[2])(2)}); \ No newline at end of file