├── README.md ├── examples ├── images │ ├── broken.jpg │ ├── bw.png │ ├── couch.png │ ├── floral.jpg │ ├── grass.png │ ├── rough.jpg │ ├── rust.jpg │ └── scene.jpg └── index.html └── main.js /README.md: -------------------------------------------------------------------------------- 1 | ## aframe-GLSL-component 2 | 3 | Aframe component to inject custom GLSL into the THREE.js MeshStandardMaterial Shader. 4 | 5 | ![](https://i.imgur.com/U2zbXIJ.gif) 6 | 7 | Have a look at the [example](https://pbayer8.github.io/aframe-glsl-component/examples/index.html) 8 | 9 | ### API 10 | 11 | | Property | Description | Default Value | 12 | | ---------- | ----------- | ------------- | 13 | |fragUniformsGLSL | selectorAll - selects the script tag to inject in the beggining of the fragment shader|#fragUniformsGLSL| 14 | |fragModsGLSL | selectorAll - selects the script tag to inject in main() of the fragment shader|#fragModsGLSL| 15 | |vertUniformsGLSL | selectorAll - selects the script tag to inject in the beggining of the vertex shader|#vertUniformsGLSL| 16 | |vertModsGLSL | selectorAll - selects the script tag to inject in main() of the fragment shader|#vertModsGLSL| 17 | Note: you can also set almost every property accessible in the [materials component](https://github.com/aframevr/aframe/blob/a46c1b133634de39e5f40c35bf28823a0960c7b5/docs/components/material.md) 18 | 19 | ### Installation 20 | Include as a ` 23 | ``` 24 | 25 | ### Usage 26 | Add the `glsl-standard` component to an entity with geometry. Note that it works better with more segments: 27 | ``` 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | ``` 46 | 47 | Then, write GLSL. This component gives you access to two vec3 type variables you can modify: 48 | `finalPosition` in the vertex shader, and `finalColor` in the fragment shader. 49 | The component creates and updates two floats variables `time` (mS) and `seconds` that you can use, 50 | and a vec3 `objectNormal` that you can read and use when modifying the `finalPosition` variable. 51 | I've also included a small collection of noise and shaping functions. 52 | You can specify alternate script tags, otherwise it defaults to what is listed in the API section above: 53 | ``` 54 | 59 | 66 | 71 | 76 | ``` 77 | 78 | The result will look like: 79 | 80 | ![](https://i.imgur.com/ruOJwIZ.gif) -------------------------------------------------------------------------------- /examples/images/broken.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/broken.jpg -------------------------------------------------------------------------------- /examples/images/bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/bw.png -------------------------------------------------------------------------------- /examples/images/couch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/couch.png -------------------------------------------------------------------------------- /examples/images/floral.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/floral.jpg -------------------------------------------------------------------------------- /examples/images/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/grass.png -------------------------------------------------------------------------------- /examples/images/rough.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/rough.jpg -------------------------------------------------------------------------------- /examples/images/rust.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/rust.jpg -------------------------------------------------------------------------------- /examples/images/scene.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbayer8/aframe-glsl-component/2bac573e0c79e873f7b294c21f98e92f58026628/examples/images/scene.jpg -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yippee Skippee 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 31 | 43 | 44 | 55 | 56 | 57 | 62 | 69 | 74 | 79 | 84 | 87 | 121 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | let start = Date.now() 2 | AFRAME.registerComponent("glsl-standard", { 3 | schema: { 4 | //TODO mipmap/minfilter bug envmap wont blur with roughness) 5 | map: { type: "selector", default: null }, 6 | normalMap: { type: "selector", default: null }, 7 | envMap: { type: "selector", default: null }, 8 | alphaMap: { type: "selector", default: null }, 9 | aoMap: { type: "selector", default: null }, 10 | lightMap: { type: "selector", default: null }, 11 | emissiveMap: { type: "selector", default: null }, 12 | bumpMap: { type: "selector", default: null }, 13 | displacementMap: { type: "selector", default: null }, 14 | roughnessMap: { type: "selector", default: null }, 15 | metalnessMap: { type: "selector", default: null }, 16 | diffuse: { type: "color", default: null }, 17 | emissive: { type: "color", default: null }, 18 | opacity: { type: "number", default: null }, 19 | roughness: { type: "number", default: null }, 20 | metalness: { type: "number", default: null }, 21 | envMapIntensity: { type: "number", default: null }, 22 | reflectivity: { type: "number", default: null }, 23 | refractionRatio: { type: "number", default: null }, 24 | aoMapIntensity: { type: "number", default: null }, 25 | lightMapIntensity: { type: "number", default: null }, 26 | bumpScale: { type: "number", default: null }, 27 | normalScale: { type: "number", default: null }, 28 | displacementScale: { type: "number", default: null }, 29 | displacementBias: { type: "number", default: null }, 30 | fragUniformsGLSL: { type: "selectorAll", default: "#fragUniformsGLSL" }, 31 | fragModsGLSL: { type: "selectorAll", default: "#fragModsGLSL" }, 32 | vertUniformsGLSL: { type: "selectorAll", default: "#vertUniformsGLSL" }, 33 | vertModsGLSL: { type: "selectorAll", default: "#vertModsGLSL" } 34 | }, 35 | 36 | init: function() { 37 | var standardShader = THREE.ShaderLib["standard"] 38 | this.uniforms = THREE.UniformsUtils.clone(THREE.UniformsUtils.merge([ 39 | standardShader.uniforms, 40 | { 41 | time: { type: "f", value: 0.0 } 42 | //add new uniforms here 43 | } 44 | ])) 45 | let fragUniforms = [] 46 | this.data.fragUniformsGLSL.forEach((el) => { 47 | fragUniforms.push(el.textContent) 48 | }) 49 | let fragMods = [] 50 | this.data.fragModsGLSL.forEach((el) => { 51 | fragMods.push(el.textContent) 52 | }) 53 | let vertUniforms = [] 54 | this.data.vertUniformsGLSL.forEach((el) => { 55 | vertUniforms.push(el.textContent) 56 | }) 57 | let vertMods = [] 58 | this.data.vertModsGLSL.forEach((el) => { 59 | vertMods.push(el.textContent) 60 | }) 61 | this.material = this.el.getOrCreateObject3D("mesh").material = new THREE.ShaderMaterial({ 62 | uniforms: this.uniforms, 63 | vertexShader: this.shaderFunctions + vertUniforms.join("\n") + this.vert1 + vertMods.join("\n") + this.vert2, 64 | fragmentShader: this.shaderFunctions + fragUniforms.join("\n") + this.frag1 + fragMods.join("\n") + this.frag2, 65 | lights: true, 66 | fog: true 67 | }) 68 | for (var property in this.data) { 69 | if (this.data.hasOwnProperty(property) && this.data[property]) { 70 | if (property === "envMap") { 71 | let texture = new THREE.Texture(this.data[property]) 72 | texture.mapping = THREE.EquirectangularReflectionMapping //TODO think of clean way to allow specifying maptype 73 | // texture.mipmaps[0] = texture.image //TODO figure out how to make this work 74 | // texture.generateMipmaps = true 75 | // texture.minFilter = THREE.LinearMipMapLinearFilter 76 | // texture.magFilter = THREE.LinearFilter 77 | texture.needsUpdate = true 78 | this.uniforms[property].value = texture 79 | this.material[property] = texture 80 | } else if (property.toLowerCase().endsWith("map")) { 81 | let texture = new THREE.Texture(this.data[property]) 82 | texture.needsUpdate = true 83 | this.uniforms[property].value = texture 84 | this.material[property] = texture 85 | } else if (["emissive", "diffuse"].includes(property.toLowerCase())) { 86 | console.log(this.data[property]) 87 | this.uniforms[property].value = new THREE.Color(this.data[property]) 88 | } else if (!property.toLowerCase().endsWith("glsl")) { 89 | try { 90 | this.uniforms[property].value = this.data[property] 91 | } catch (er) { 92 | console.log(er) 93 | } 94 | 95 | } 96 | } 97 | } 98 | }, 99 | tick: function() { 100 | this.uniforms.time.value = Date.now() - start // Updates this new value 101 | }, 102 | vert1: ` 103 | uniform float time; 104 | #define PHYSICAL 105 | varying vec3 vViewPosition; 106 | #ifndef FLAT_SHADED 107 | varying vec3 vNormal; 108 | #endif 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | void main() { 121 | float seconds = time/1000.; 122 | #include 123 | #include 124 | #include 125 | #include 126 | #include 127 | #include 128 | #include 129 | #include 130 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED 131 | vNormal = normalize( transformedNormal ); 132 | #endif 133 | #include 134 | #include 135 | #include 136 | #include 137 | vec3 finalPosition = transformed;`, 138 | vert2: ` 139 | transformed = finalPosition; 140 | #include 141 | #include 142 | #include 143 | vViewPosition = - mvPosition.xyz; 144 | #include 145 | #include 146 | #include 147 | }`, 148 | frag1: ` 149 | #define PHYSICAL 150 | uniform vec3 diffuse; 151 | uniform vec3 emissive; 152 | uniform float roughness; 153 | uniform float metalness; 154 | uniform float opacity; 155 | #ifndef STANDARD 156 | uniform float clearCoat; 157 | uniform float clearCoatRoughness; 158 | #endif 159 | varying vec3 vViewPosition; 160 | #ifndef FLAT_SHADED 161 | varying vec3 vNormal; 162 | #endif 163 | #include 164 | #include 165 | #include 166 | #include 167 | #include 168 | #include 169 | #include 170 | #include 171 | #include 172 | #include 173 | #include 174 | //#include 175 | #if defined( USE_ENVMAP ) || defined( PHYSICAL ) 176 | uniform float reflectivity; 177 | uniform float envMapIntensity; 178 | #endif 179 | #ifdef USE_ENVMAP 180 | #if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) ) 181 | varying vec3 vWorldPosition; 182 | #endif 183 | #ifdef ENVMAP_TYPE_CUBE 184 | uniform samplerCube envMap; 185 | #else 186 | uniform sampler2D envMap; 187 | #endif 188 | uniform float flipEnvMap; 189 | uniform int maxMipLevel; 190 | 191 | #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL ) 192 | uniform float refractionRatio; 193 | #else 194 | varying vec3 vReflect; 195 | #endif 196 | #endif 197 | #include 198 | #include 199 | #include 200 | //#include 201 | //#include 202 | uniform vec3 ambientLightColor; 203 | vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { 204 | vec3 irradiance = ambientLightColor; 205 | #ifndef PHYSICALLY_CORRECT_LIGHTS 206 | irradiance *= PI; 207 | #endif 208 | return irradiance; 209 | } 210 | #if NUM_DIR_LIGHTS > 0 211 | struct DirectionalLight { 212 | vec3 direction; 213 | vec3 color; 214 | int shadow; 215 | float shadowBias; 216 | float shadowRadius; 217 | vec2 shadowMapSize; 218 | }; 219 | uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; 220 | void getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) { 221 | directLight.color = directionalLight.color; 222 | directLight.direction = directionalLight.direction; 223 | directLight.visible = true; 224 | } 225 | #endif 226 | #if NUM_POINT_LIGHTS > 0 227 | struct PointLight { 228 | vec3 position; 229 | vec3 color; 230 | float distance; 231 | float decay; 232 | int shadow; 233 | float shadowBias; 234 | float shadowRadius; 235 | vec2 shadowMapSize; 236 | float shadowCameraNear; 237 | float shadowCameraFar; 238 | }; 239 | uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; 240 | // directLight is an out parameter as having it as a return value caused compiler errors on some devices 241 | void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) { 242 | vec3 lVector = pointLight.position - geometry.position; 243 | directLight.direction = normalize( lVector ); 244 | float lightDistance = length( lVector ); 245 | directLight.color = pointLight.color; 246 | directLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay ); 247 | directLight.visible = ( directLight.color != vec3( 0.0 ) ); 248 | } 249 | #endif 250 | #if NUM_SPOT_LIGHTS > 0 251 | struct SpotLight { 252 | vec3 position; 253 | vec3 direction; 254 | vec3 color; 255 | float distance; 256 | float decay; 257 | float coneCos; 258 | float penumbraCos; 259 | int shadow; 260 | float shadowBias; 261 | float shadowRadius; 262 | vec2 shadowMapSize; 263 | }; 264 | uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; 265 | // directLight is an out parameter as having it as a return value caused compiler errors on some devices 266 | void getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) { 267 | vec3 lVector = spotLight.position - geometry.position; 268 | directLight.direction = normalize( lVector ); 269 | float lightDistance = length( lVector ); 270 | float angleCos = dot( directLight.direction, spotLight.direction ); 271 | if ( angleCos > spotLight.coneCos ) { 272 | float spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos ); 273 | directLight.color = spotLight.color; 274 | directLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay ); 275 | directLight.visible = true; 276 | } else { 277 | directLight.color = vec3( 0.0 ); 278 | directLight.visible = false; 279 | } 280 | } 281 | #endif 282 | #if NUM_RECT_AREA_LIGHTS > 0 283 | struct RectAreaLight { 284 | vec3 color; 285 | vec3 position; 286 | vec3 halfWidth; 287 | vec3 halfHeight; 288 | }; 289 | // Pre-computed values of LinearTransformedCosine approximation of BRDF 290 | // BRDF approximation Texture is 64x64 291 | uniform sampler2D ltc_1; // RGBA Float 292 | uniform sampler2D ltc_2; // RGBA Float 293 | uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; 294 | #endif 295 | #if NUM_HEMI_LIGHTS > 0 296 | struct HemisphereLight { 297 | vec3 direction; 298 | vec3 skyColor; 299 | vec3 groundColor; 300 | }; 301 | uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; 302 | vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) { 303 | float dotNL = dot( geometry.normal, hemiLight.direction ); 304 | float hemiDiffuseWeight = 0.5 * dotNL + 0.5; 305 | vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); 306 | #ifndef PHYSICALLY_CORRECT_LIGHTS 307 | irradiance *= PI; 308 | #endif 309 | return irradiance; 310 | } 311 | #endif 312 | #if defined( USE_ENVMAP ) && defined( PHYSICAL ) 313 | vec3 getLightProbeIndirectIrradiance( /*const in SpecularLightProbe specularLightProbe,*/ const in GeometricContext geometry, const in int maxMIPLevel ) { 314 | vec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix ); 315 | #ifdef ENVMAP_TYPE_CUBE 316 | vec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz ); 317 | // TODO: replace with properly filtered cubemaps and access the irradiance LOD level, be it the last LOD level 318 | // of a specular cubemap, or just the default level of a specially created irradiance cubemap. 319 | #ifdef TEXTURE_LOD_EXT 320 | vec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) ); 321 | #else 322 | // force the bias high to get the last LOD level as it is the most blurred. 323 | vec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) ); 324 | #endif 325 | envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb; 326 | #elif defined( ENVMAP_TYPE_CUBE_UV ) 327 | vec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz ); 328 | vec4 envMapColor = textureCubeUV( queryVec, 1.0 ); 329 | #else 330 | vec4 envMapColor = vec4( 0.0 ); 331 | #endif 332 | return PI * envMapColor.rgb * envMapIntensity; 333 | } 334 | // taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html 335 | float getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) { 336 | //float envMapWidth = pow( 2.0, maxMIPLevelScalar ); 337 | //float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 ); 338 | float maxMIPLevelScalar = float( maxMIPLevel ); 339 | float desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 ); 340 | // clamp to allowable LOD ranges. 341 | return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar ); 342 | } 343 | vec3 getLightProbeIndirectRadiance( /*const in SpecularLightProbe specularLightProbe,*/ const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) { 344 | #ifdef ENVMAP_MODE_REFLECTION 345 | vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal ); 346 | #else 347 | vec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio ); 348 | #endif 349 | reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); 350 | float specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel ); 351 | #ifdef ENVMAP_TYPE_CUBE 352 | vec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz ); 353 | #ifdef TEXTURE_LOD_EXT 354 | vec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel ); 355 | #else 356 | vec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel ); 357 | #endif 358 | envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb; 359 | #elif defined( ENVMAP_TYPE_CUBE_UV ) 360 | vec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz ); 361 | vec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent)); 362 | #elif defined( ENVMAP_TYPE_EQUIREC ) 363 | vec2 sampleUV; 364 | sampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; 365 | sampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5; 366 | #ifdef TEXTURE_LOD_EXT 367 | vec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel ); 368 | #else 369 | vec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel ); 370 | #endif 371 | envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb; 372 | #elif defined( ENVMAP_TYPE_SPHERE ) 373 | vec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) ); 374 | #ifdef TEXTURE_LOD_EXT 375 | vec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel ); 376 | #else 377 | vec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel ); 378 | #endif 379 | envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb; 380 | #endif 381 | return envMapColor.rgb * envMapIntensity; 382 | } 383 | #endif 384 | #include 385 | #include 386 | #include 387 | #include 388 | #include 389 | #include 390 | #include 391 | #include 392 | void main() { 393 | #include 394 | vec4 diffuseColor = vec4( diffuse, opacity ); 395 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 396 | vec3 totalEmissiveRadiance = emissive; 397 | #include 398 | #include 399 | #include 400 | #include 401 | #include 402 | #include 403 | #include 404 | // #include 405 | // #include 406 | #ifdef FLAT_SHADED 407 | // Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ... 408 | vec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) ); 409 | vec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) ); 410 | vec3 normal = normalize( cross( fdx, fdy ) ); 411 | #else 412 | vec3 normal = normalize( vNormal ); 413 | #ifdef DOUBLE_SIDED 414 | normal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 ); 415 | #endif 416 | #endif 417 | #ifdef USE_NORMALMAP 418 | normal = perturbNormal2Arb( -vViewPosition, normal ); 419 | #elif defined( USE_BUMPMAP ) 420 | normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() ); 421 | #endif 422 | #include 423 | // accumulation 424 | #include 425 | // #include 426 | // #include 427 | // #include 428 | GeometricContext geometry; 429 | geometry.position = - vViewPosition; 430 | geometry.normal = normal; 431 | geometry.viewDir = normalize( vViewPosition ); 432 | IncidentLight directLight; 433 | #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) 434 | PointLight pointLight; 435 | #pragma unroll_loop 436 | for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { 437 | pointLight = pointLights[ i ]; 438 | getPointDirectLightIrradiance( pointLight, geometry, directLight ); 439 | #ifdef USE_SHADOWMAP 440 | directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; 441 | #endif 442 | RE_Direct( directLight, geometry, material, reflectedLight ); 443 | } 444 | #endif 445 | #if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) 446 | SpotLight spotLight; 447 | #pragma unroll_loop 448 | for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { 449 | spotLight = spotLights[ i ]; 450 | getSpotDirectLightIrradiance( spotLight, geometry, directLight ); 451 | #ifdef USE_SHADOWMAP 452 | directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0; 453 | #endif 454 | RE_Direct( directLight, geometry, material, reflectedLight ); 455 | } 456 | #endif 457 | #if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) 458 | DirectionalLight directionalLight; 459 | #pragma unroll_loop 460 | for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { 461 | directionalLight = directionalLights[ i ]; 462 | getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight ); 463 | #ifdef USE_SHADOWMAP 464 | directLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; 465 | #endif 466 | RE_Direct( directLight, geometry, material, reflectedLight ); 467 | } 468 | #endif 469 | #if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) 470 | RectAreaLight rectAreaLight; 471 | #pragma unroll_loop 472 | for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { 473 | rectAreaLight = rectAreaLights[ i ]; 474 | RE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight ); 475 | } 476 | #endif 477 | #if defined( RE_IndirectDiffuse ) 478 | vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); 479 | #if ( NUM_HEMI_LIGHTS > 0 ) 480 | #pragma unroll_loop 481 | for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { 482 | irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry ); 483 | } 484 | #endif 485 | #endif 486 | #if defined( RE_IndirectSpecular ) 487 | vec3 radiance = vec3( 0.0 ); 488 | vec3 clearCoatRadiance = vec3( 0.0 ); 489 | #endif 490 | #if defined( RE_IndirectDiffuse ) 491 | #ifdef USE_LIGHTMAP 492 | vec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity; 493 | #ifndef PHYSICALLY_CORRECT_LIGHTS 494 | lightMapIrradiance *= PI; // factor of PI should not be present; included here to prevent breakage 495 | #endif 496 | irradiance += lightMapIrradiance; 497 | #endif 498 | #if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV ) 499 | irradiance += getLightProbeIndirectIrradiance( /*lightProbe,*/ geometry, maxMipLevel ); 500 | #endif 501 | #endif 502 | #if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) 503 | radiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry, Material_BlinnShininessExponent( material ), maxMipLevel ); 504 | #ifndef STANDARD 505 | clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel ); 506 | #endif 507 | #endif 508 | #if defined( RE_IndirectDiffuse ) 509 | RE_IndirectDiffuse( irradiance, geometry, material, reflectedLight ); 510 | #endif 511 | #if defined( RE_IndirectSpecular ) 512 | RE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight ); 513 | #endif 514 | // modulation 515 | #include 516 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 517 | vec3 finalColor = outgoingLight; 518 | `, 519 | frag2: ` 520 | gl_FragColor = vec4( finalColor, diffuseColor.a ); 521 | #include 522 | #include 523 | #include 524 | #include 525 | #include 526 | } 527 | `, 528 | shaderFunctions: ` 529 | // Copyright (c) 2011 Stefan Gustavson. All rights reserved. 530 | // Distributed under the MIT license. See LICENSE file. 531 | // https://github.com/stegu/webgl-noise 532 | // 533 | 534 | vec3 mod289(vec3 x) 535 | { 536 | return x - floor(x * (1.0 / 289.0)) * 289.0; 537 | } 538 | 539 | vec4 mod289(vec4 x) 540 | { 541 | return x - floor(x * (1.0 / 289.0)) * 289.0; 542 | } 543 | 544 | vec4 permute(vec4 x) 545 | { 546 | return mod289(((x*34.0)+1.0)*x); 547 | } 548 | 549 | vec4 taylorInvSqrt(vec4 r) 550 | { 551 | return 1.79284291400159 - 0.85373472095314 * r; 552 | } 553 | 554 | vec3 fade(vec3 t) { 555 | return t*t*t*(t*(t*6.0-15.0)+10.0); 556 | } 557 | 558 | // Classic Perlin noise 559 | float cnoise(vec3 P) 560 | { 561 | vec3 Pi0 = floor(P); // Integer part for indexing 562 | vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 563 | Pi0 = mod289(Pi0); 564 | Pi1 = mod289(Pi1); 565 | vec3 Pf0 = fract(P); // Fractional part for interpolation 566 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 567 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); 568 | vec4 iy = vec4(Pi0.yy, Pi1.yy); 569 | vec4 iz0 = Pi0.zzzz; 570 | vec4 iz1 = Pi1.zzzz; 571 | 572 | vec4 ixy = permute(permute(ix) + iy); 573 | vec4 ixy0 = permute(ixy + iz0); 574 | vec4 ixy1 = permute(ixy + iz1); 575 | 576 | vec4 gx0 = ixy0 * (1.0 / 7.0); 577 | vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; 578 | gx0 = fract(gx0); 579 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); 580 | vec4 sz0 = step(gz0, vec4(0.0)); 581 | gx0 -= sz0 * (step(0.0, gx0) - 0.5); 582 | gy0 -= sz0 * (step(0.0, gy0) - 0.5); 583 | 584 | vec4 gx1 = ixy1 * (1.0 / 7.0); 585 | vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; 586 | gx1 = fract(gx1); 587 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); 588 | vec4 sz1 = step(gz1, vec4(0.0)); 589 | gx1 -= sz1 * (step(0.0, gx1) - 0.5); 590 | gy1 -= sz1 * (step(0.0, gy1) - 0.5); 591 | 592 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); 593 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); 594 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); 595 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); 596 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); 597 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); 598 | vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); 599 | vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); 600 | 601 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); 602 | g000 *= norm0.x; 603 | g010 *= norm0.y; 604 | g100 *= norm0.z; 605 | g110 *= norm0.w; 606 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); 607 | g001 *= norm1.x; 608 | g011 *= norm1.y; 609 | g101 *= norm1.z; 610 | g111 *= norm1.w; 611 | 612 | float n000 = dot(g000, Pf0); 613 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); 614 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); 615 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); 616 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); 617 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); 618 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); 619 | float n111 = dot(g111, Pf1); 620 | 621 | vec3 fade_xyz = fade(Pf0); 622 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); 623 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); 624 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 625 | return 2.2 * n_xyz; 626 | } 627 | 628 | // Classic Perlin noise, periodic variant 629 | float pnoise(vec3 P, vec3 rep) 630 | { 631 | vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period 632 | vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period 633 | Pi0 = mod289(Pi0); 634 | Pi1 = mod289(Pi1); 635 | vec3 Pf0 = fract(P); // Fractional part for interpolation 636 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 637 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); 638 | vec4 iy = vec4(Pi0.yy, Pi1.yy); 639 | vec4 iz0 = Pi0.zzzz; 640 | vec4 iz1 = Pi1.zzzz; 641 | 642 | vec4 ixy = permute(permute(ix) + iy); 643 | vec4 ixy0 = permute(ixy + iz0); 644 | vec4 ixy1 = permute(ixy + iz1); 645 | 646 | vec4 gx0 = ixy0 * (1.0 / 7.0); 647 | vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; 648 | gx0 = fract(gx0); 649 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); 650 | vec4 sz0 = step(gz0, vec4(0.0)); 651 | gx0 -= sz0 * (step(0.0, gx0) - 0.5); 652 | gy0 -= sz0 * (step(0.0, gy0) - 0.5); 653 | 654 | vec4 gx1 = ixy1 * (1.0 / 7.0); 655 | vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; 656 | gx1 = fract(gx1); 657 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); 658 | vec4 sz1 = step(gz1, vec4(0.0)); 659 | gx1 -= sz1 * (step(0.0, gx1) - 0.5); 660 | gy1 -= sz1 * (step(0.0, gy1) - 0.5); 661 | 662 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); 663 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); 664 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); 665 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); 666 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); 667 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); 668 | vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); 669 | vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); 670 | 671 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); 672 | g000 *= norm0.x; 673 | g010 *= norm0.y; 674 | g100 *= norm0.z; 675 | g110 *= norm0.w; 676 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); 677 | g001 *= norm1.x; 678 | g011 *= norm1.y; 679 | g101 *= norm1.z; 680 | g111 *= norm1.w; 681 | 682 | float n000 = dot(g000, Pf0); 683 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); 684 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); 685 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); 686 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); 687 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); 688 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); 689 | float n111 = dot(g111, Pf1); 690 | 691 | vec3 fade_xyz = fade(Pf0); 692 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); 693 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); 694 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 695 | return 2.2 * n_xyz; 696 | } 697 | 698 | // Function from Iñigo Quiles 699 | // www.iquilezles.org/www/articles/functions/functions.htm 700 | float cubicPulse( float c, float w, float x ){ 701 | x = abs(x - c); 702 | if( x>w ) return 0.0; 703 | x /= w; 704 | return 1.0 - x*x*(3.0-2.0*x); 705 | } 706 | 707 | //MEEEEE 708 | //cosine simlarity of vectors 709 | float cosSim(vec3 v1, vec3 v2){ 710 | float d = dot(v1,v2); 711 | float m = length(v1)*length(v2); 712 | return abs(d/m); 713 | } 714 | // get perpendicular component 715 | vec3 perpComp(vec3 v1, vec3 v2){ 716 | float d = dot(v1,v2); 717 | float m = d/pow(length(v1),2.); 718 | vec3 v = m*v1; 719 | return v2 - v; 720 | 721 | } 722 | 723 | vec3 rgb2hsb( in vec3 c ){ 724 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 725 | vec4 p = mix(vec4(c.bg, K.wz), 726 | vec4(c.gb, K.xy), 727 | step(c.b, c.g)); 728 | vec4 q = mix(vec4(p.xyw, c.r), 729 | vec4(c.r, p.yzx), 730 | step(p.x, c.r)); 731 | float d = q.x - min(q.w, q.y); 732 | float e = 1.0e-10; 733 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), 734 | d / (q.x + e), 735 | q.x); 736 | } 737 | 738 | // Function from Iñigo Quiles 739 | // https://www.shadertoy.com/view/MsS3Wc 740 | vec3 hsb2rgb( in vec3 c ){ 741 | vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 742 | 6.0)-3.0)-1.0, 743 | 0.0, 744 | 1.0 ); 745 | rgb = rgb*rgb*(3.0-2.0*rgb); 746 | return c.z * mix(vec3(1.0), rgb, c.y); 747 | } 748 | mat3 xProduct(vec3 v){ 749 | return mat3(0.,v.z,-v.y,-v.z,0.,v.x,v.y,-v.x,0); 750 | } 751 | mat3 outerProduct(vec3 u, vec3 v) { 752 | return mat3(u.x*v.x,u.y*v.x,u.z*v.x, 753 | u.x*v.y,u.y*v.y,u.z*v.y, 754 | u.x*v.z,u.y*v.z,u.z*v.z); 755 | } 756 | mat3 rotMatrix(float theta, vec3 v){ 757 | v = normalize(v); 758 | mat3 vprod = xProduct(v); 759 | return mat3(cos(theta)) + sin(theta)*vprod + (1.-cos(theta)) * outerProduct(v,v); 760 | } 761 | 762 | 763 | vec2 random2( vec2 p ) { 764 | return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); 765 | } 766 | 767 | float doubleExponentialSeat (float x, float a){ 768 | 769 | float epsilon = 0.00001; 770 | float min_param_a = 0.0 + epsilon; 771 | float max_param_a = 1.0 - epsilon; 772 | a = min(max_param_a, max(min_param_a, a)); 773 | 774 | float y = 0.; 775 | if (x<=0.5){ 776 | y = (pow(2.0*x, 1.-a))/2.0; 777 | } else { 778 | y = 1.0 - (pow(2.0*(1.0-x), 1.-a))/2.0; 779 | } 780 | return y; 781 | } 782 | 783 | float logisticSigmoid (float x, float a){ 784 | // n.b.: this Logistic Sigmoid has been normalized. 785 | 786 | float epsilon = 0.0001; 787 | float min_param_a = 0.0 + epsilon; 788 | float max_param_a = 1.0 - epsilon; 789 | a = max(min_param_a, min(max_param_a, a)); 790 | a = (1./(1.-a) - 1.); 791 | 792 | float A = 1.0 / (1.0 + exp(0. -((x-0.5)*a*2.0))); 793 | float B = 1.0 / (1.0 + exp(a)); 794 | float C = 1.0 / (1.0 + exp(0.-a)); 795 | float y = (A-B)/(C-B); 796 | return y; 797 | } 798 | ` 799 | }) 800 | --------------------------------------------------------------------------------