troika-three-utils
Advanced tools
Comparing version 0.38.1 to 0.39.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [0.39.0](https://github.com/protectwise/troika/compare/v0.38.1...v0.39.0) (2021-02-15) | ||
### Bug Fixes | ||
* restore compatibility with three versions <0.113.0 by copying MathUtils.generateUUID ([35856b5](https://github.com/protectwise/troika/commit/35856b555919278b1addad0d2625faaaeb379757)) | ||
## [0.38.1](https://github.com/protectwise/troika/compare/v0.38.0...v0.38.1) (2021-02-03) | ||
@@ -8,0 +19,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { ShaderChunk, MathUtils, UniformsUtils, MeshDepthMaterial, RGBADepthPacking, MeshDistanceMaterial, ShaderLib, Matrix4, Vector3, Mesh, CylinderBufferGeometry, Vector2, MeshStandardMaterial, DoubleSide } from 'three'; | ||
import { ShaderChunk, UniformsUtils, MeshDepthMaterial, RGBADepthPacking, MeshDistanceMaterial, ShaderLib, Matrix4, Vector3, Mesh, CylinderBufferGeometry, Vector2, MeshStandardMaterial, DoubleSide } from 'three'; | ||
@@ -25,2 +25,32 @@ /** | ||
/* | ||
* This is a direct copy of MathUtils.generateUUID from Three.js, to preserve compatibility with three | ||
* versions before 0.113.0 as it was changed from Math to MathUtils in that version. | ||
* https://github.com/mrdoob/three.js/blob/dd8b5aa3b270c17096b90945cd2d6d1b13aaec53/src/math/MathUtils.js#L16 | ||
*/ | ||
const _lut = []; | ||
for (let i = 0; i < 256; i++) { | ||
_lut[i] = (i < 16 ? '0' : '') + (i).toString(16); | ||
} | ||
function generateUUID() { | ||
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 | ||
const d0 = Math.random() * 0xffffffff | 0; | ||
const d1 = Math.random() * 0xffffffff | 0; | ||
const d2 = Math.random() * 0xffffffff | 0; | ||
const d3 = Math.random() * 0xffffffff | 0; | ||
const uuid = _lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff] + '-' + | ||
_lut[d1 & 0xff] + _lut[d1 >> 8 & 0xff] + '-' + _lut[d1 >> 16 & 0x0f | 0x40] + _lut[d1 >> 24 & 0xff] + '-' + | ||
_lut[d2 & 0x3f | 0x80] + _lut[d2 >> 8 & 0xff] + '-' + _lut[d2 >> 16 & 0xff] + _lut[d2 >> 24 & 0xff] + | ||
_lut[d3 & 0xff] + _lut[d3 >> 8 & 0xff] + _lut[d3 >> 16 & 0xff] + _lut[d3 >> 24 & 0xff]; | ||
// .toUpperCase() here flattens concatenated strings to save heap memory space. | ||
return uuid.toUpperCase() | ||
} | ||
// Local assign polyfill to avoid importing troika-core | ||
@@ -174,3 +204,3 @@ const assign = Object.assign || function(/*target, ...sources*/) { | ||
Object.defineProperty(derived, 'id', { value: materialInstanceId++ }); | ||
derived.uuid = MathUtils.generateUUID(); | ||
derived.uuid = generateUUID(); | ||
@@ -177,0 +207,0 @@ // Merge uniforms, defines, and extensions |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'three'], factory) : | ||
(global = global || self, factory(global.troika_three_utils = {}, global.THREE)); | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.troika_three_utils = {}, global.THREE)); | ||
}(this, (function (exports, three) { 'use strict'; | ||
@@ -29,2 +29,32 @@ | ||
/* | ||
* This is a direct copy of MathUtils.generateUUID from Three.js, to preserve compatibility with three | ||
* versions before 0.113.0 as it was changed from Math to MathUtils in that version. | ||
* https://github.com/mrdoob/three.js/blob/dd8b5aa3b270c17096b90945cd2d6d1b13aaec53/src/math/MathUtils.js#L16 | ||
*/ | ||
var _lut = []; | ||
for (var i = 0; i < 256; i++) { | ||
_lut[i] = (i < 16 ? '0' : '') + (i).toString(16); | ||
} | ||
function generateUUID() { | ||
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 | ||
var d0 = Math.random() * 0xffffffff | 0; | ||
var d1 = Math.random() * 0xffffffff | 0; | ||
var d2 = Math.random() * 0xffffffff | 0; | ||
var d3 = Math.random() * 0xffffffff | 0; | ||
var uuid = _lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff] + '-' + | ||
_lut[d1 & 0xff] + _lut[d1 >> 8 & 0xff] + '-' + _lut[d1 >> 16 & 0x0f | 0x40] + _lut[d1 >> 24 & 0xff] + '-' + | ||
_lut[d2 & 0x3f | 0x80] + _lut[d2 >> 8 & 0xff] + '-' + _lut[d2 >> 16 & 0xff] + _lut[d2 >> 24 & 0xff] + | ||
_lut[d3 & 0xff] + _lut[d3 >> 8 & 0xff] + _lut[d3 >> 16 & 0xff] + _lut[d3 >> 24 & 0xff]; | ||
// .toUpperCase() here flattens concatenated strings to save heap memory space. | ||
return uuid.toUpperCase() | ||
} | ||
// Local assign polyfill to avoid importing troika-core | ||
@@ -180,3 +210,3 @@ var assign = Object.assign || function(/*target, ...sources*/) { | ||
Object.defineProperty(derived, 'id', { value: materialInstanceId++ }); | ||
derived.uuid = three.MathUtils.generateUUID(); | ||
derived.uuid = generateUUID(); | ||
@@ -183,0 +213,0 @@ // Merge uniforms, defines, and extensions |
@@ -1,16 +0,17 @@ | ||
'use strict';(function(f,c){"object"===typeof exports&&"undefined"!==typeof module?c(exports,require("three")):"function"===typeof define&&define.amd?define(["exports","three"],c):(f=f||self,c(f.troika_three_utils={},f.THREE))})(this,function(f,c){function t(b){return b.replace(/^[ \t]*#include +<([\w\d./]+)>/gm,function(a,b){return(b=c.ShaderChunk[b])?t(b):a})}function l(b,a){var e=A(a),d=q.get(b);d||q.set(b,d=Object.create(null));if(d[e])return new d[e];var g="_onBeforeCompile"+e,f=function(h){b.onBeforeCompile.call(this, | ||
h);var d=e+"|||"+h.vertexShader+"|||"+h.fragmentShader,c=u[d];c||(c=B(h,a,e),c=u[d]=c);h.vertexShader=c.vertexShader;h.fragmentShader=c.fragmentShader;k(h.uniforms,this.uniforms);a.timeUniform&&(h.uniforms[a.timeUniform]={get value(){return Date.now()-C}});if(this[g])this[g](h)},r=function(){return p(a.chained?b:b.clone())},p=function(d){var h=Object.create(d,m);Object.defineProperty(h,"baseMaterial",{value:b});Object.defineProperty(h,"id",{value:D++});h.uuid=c.MathUtils.generateUUID();h.uniforms= | ||
k({},d.uniforms,a.uniforms);h.defines=k({},d.defines,a.defines);h.defines["TROIKA_DERIVED_MATERIAL_"+e]="";h.extensions=k({},d.extensions,a.extensions);h._listeners=void 0;return h},m={constructor:{value:r},isDerivedMaterial:{value:!0},customProgramCacheKey:{writable:!0,configurable:!0,value:function(){return e}},onBeforeCompile:{get:function(){return f},set:function(a){this[g]=a}},copy:{writable:!0,configurable:!0,value:function(a){b.copy.call(this,a);b.isShaderMaterial||b.isDerivedMaterial||(k(this.extensions, | ||
a.extensions),k(this.defines,a.defines),k(this.uniforms,c.UniformsUtils.clone(a.uniforms)));return this}},clone:{writable:!0,configurable:!0,value:function(){var a=new b.constructor;return p(a).copy(this)}},getDepthMaterial:{writable:!0,configurable:!0,value:function(){var d=this._depthMaterial;d||(d=this._depthMaterial=l(b.isDerivedMaterial?b.getDepthMaterial():new c.MeshDepthMaterial({depthPacking:c.RGBADepthPacking}),a),d.defines.IS_DEPTH_MATERIAL="",d.uniforms=this.uniforms);return d}},getDistanceMaterial:{writable:!0, | ||
configurable:!0,value:function(){var d=this._distanceMaterial;d||(d=this._distanceMaterial=l(b.isDerivedMaterial?b.getDistanceMaterial():new c.MeshDistanceMaterial,a),d.defines.IS_DISTANCE_MATERIAL="",d.uniforms=this.uniforms);return d}},dispose:{writable:!0,configurable:!0,value:function(){var a=this._depthMaterial,d=this._distanceMaterial;a&&a.dispose();d&&d.dispose();b.dispose.call(this)}}};d[e]=r;return new r}function B(b,a,e){var d=b.vertexShader,g=b.fragmentShader;b=a.vertexDefs;var c=a.vertexMainIntro, | ||
f=a.vertexMainOutro,p=a.vertexTransform,m=a.fragmentDefs,h=a.fragmentMainIntro,k=a.fragmentMainOutro,n=a.fragmentColorTransform,l=a.customRewriter;a=a.timeUniform;b=b||"";c=c||"";f=f||"";m=m||"";h=h||"";k=k||"";if(p||l)d=t(d);if(n||l)g=g.replace(/^[ \t]*#include <((?:tonemapping|encodings|fog|premultiplied_alpha|dithering)_fragment)>/gm,"\n//!BEGIN_POST_CHUNK $1\n$&\n//!END_POST_CHUNK\n"),g=t(g);l&&(g=l({vertexShader:d,fragmentShader:g}),d=g.vertexShader,g=g.fragmentShader);if(n){var q=[];g=g.replace(/^\/\/!BEGIN_POST_CHUNK[^]+?^\/\/!END_POST_CHUNK/gm, | ||
function(a){q.push(a);return""});k=n+"\n"+q.join("\n")+"\n"+k}a&&(n="\nuniform float "+a+";\n",b=n+b,m=n+m);p&&(b=b+"\nvoid troikaVertexTransform"+e+"(inout vec3 position, inout vec3 normal, inout vec2 uv) {\n "+p+"\n}\n",c="\ntroika_position_"+e+" = vec3(position);\ntroika_normal_"+e+" = vec3(normal);\ntroika_uv_"+e+" = vec2(uv);\ntroikaVertexTransform"+e+"(troika_position_"+e+", troika_normal_"+e+", troika_uv_"+e+");\n"+c+"\n",d=("vec3 troika_position_"+e+";\nvec3 troika_normal_"+e+";\nvec2 troika_uv_"+ | ||
e+";\n"+d+"\n").replace(/\b(position|normal|uv)\b/g,function(a,d,b,c){return/\battribute\s+vec[23]\s+$/.test(c.substr(0,b))?d:"troika_"+d+"_"+e}));d=v(d,e,b,c,f);g=v(g,e,m,h,k);return{vertexShader:d,fragmentShader:g}}function v(b,a,c,d,g){if(d||g||c)b=b.replace(w,"\n"+c+"\nvoid troikaOrigMain"+a+"() {"),b+="\nvoid main() {\n "+d+"\n troikaOrigMain"+a+"();\n "+g+"\n}";return b}function E(b,a){return"uniforms"===b?void 0:"function"===typeof a?a.toString():a}function A(b){b=JSON.stringify(b,E);var a= | ||
x.get(b);null==a&&x.set(b,a=++F);return a}var w=/\bvoid\s+main\s*\(\s*\)\s*{/g,k=Object.assign||function(){for(var b=arguments,a=arguments[0],c=1,d=arguments.length;c<d;c++){var g=b[c];if(g)for(var f in g)g.hasOwnProperty(f)&&(a[f]=g[f])}return a},C=Date.now(),q=new WeakMap,u=new Map,D=1E10,F=0,x=new Map,G={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon", | ||
MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"},y=null,z=new c.MeshStandardMaterial({color:16777215,side:c.DoubleSide}),H=function(b){function a(){b.call(this,a.getGeometry(),z);this.pointA=new c.Vector3;this.controlA=new c.Vector3;this.controlB=new c.Vector3;this.pointB=new c.Vector3;this.radius=.01;this.dashArray=new c.Vector2; | ||
this.dashOffset=0;this.frustumCulled=!1}b&&(a.__proto__=b);a.prototype=Object.create(b&&b.prototype);a.prototype.constructor=a;var e={material:{configurable:!0},customDepthMaterial:{configurable:!0},customDistanceMaterial:{configurable:!0}};a.getGeometry=function(){return y||(y=(new c.CylinderBufferGeometry(1,1,1,6,64)).translate(0,.5,0))};e.material.get=function(){var a=this._derivedMaterial,b=this._baseMaterial||this._defaultMaterial||(this._defaultMaterial=z.clone());a&&a.baseMaterial===b||(a= | ||
this._derivedMaterial=l(b,{chained:!0,uniforms:{pointA:{value:new c.Vector3},controlA:{value:new c.Vector3},controlB:{value:new c.Vector3},pointB:{value:new c.Vector3},radius:{value:.01},dashing:{value:new c.Vector3}},vertexDefs:"\nuniform vec3 pointA;\nuniform vec3 controlA;\nuniform vec3 controlB;\nuniform vec3 pointB;\nuniform float radius;\nvarying float bezierT;\n\nvec3 cubicBezier(vec3 p1, vec3 c1, vec3 c2, vec3 p2, float t) {\n float t2 = 1.0 - t;\n float b0 = t2 * t2 * t2;\n float b1 = 3.0 * t * t2 * t2;\n float b2 = 3.0 * t * t * t2;\n float b3 = t * t * t;\n return b0 * p1 + b1 * c1 + b2 * c2 + b3 * p2;\n}\n\nvec3 cubicBezierDerivative(vec3 p1, vec3 c1, vec3 c2, vec3 p2, float t) {\n float t2 = 1.0 - t;\n return -3.0 * p1 * t2 * t2 +\n c1 * (3.0 * t2 * t2 - 6.0 * t2 * t) +\n c2 * (6.0 * t2 * t - 3.0 * t * t) +\n 3.0 * p2 * t * t;\n}\n", | ||
'use strict';(function(f,c){"object"===typeof exports&&"undefined"!==typeof module?c(exports,require("three")):"function"===typeof define&&define.amd?define(["exports","three"],c):(f="undefined"!==typeof globalThis?globalThis:f||self,c(f.troika_three_utils={},f.THREE))})(this,function(f,c){function t(b){return b.replace(/^[ \t]*#include +<([\w\d./]+)>/gm,function(a,b){return(b=c.ShaderChunk[b])?t(b):a})}function n(b,a){var g=C(a),d=q.get(b);d||q.set(b,d=Object.create(null));if(d[g])return new d[g]; | ||
var e="_onBeforeCompile"+g,f=function(h){b.onBeforeCompile.call(this,h);var d=g+"|||"+h.vertexShader+"|||"+h.fragmentShader,c=v[d];c||(c=D(h,a,g),c=v[d]=c);h.vertexShader=c.vertexShader;h.fragmentShader=c.fragmentShader;m(h.uniforms,this.uniforms);a.timeUniform&&(h.uniforms[a.timeUniform]={get value(){return Date.now()-E}});if(this[e])this[e](h)},r=function(){return w(a.chained?b:b.clone())},w=function(d){var h=Object.create(d,p);Object.defineProperty(h,"baseMaterial",{value:b});Object.defineProperty(h, | ||
"id",{value:F++});var e=4294967295*Math.random()|0;var c=4294967295*Math.random()|0,f=4294967295*Math.random()|0,u=4294967295*Math.random()|0;e=(k[e&255]+k[e>>8&255]+k[e>>16&255]+k[e>>24&255]+"-"+k[c&255]+k[c>>8&255]+"-"+k[c>>16&15|64]+k[c>>24&255]+"-"+k[f&63|128]+k[f>>8&255]+"-"+k[f>>16&255]+k[f>>24&255]+k[u&255]+k[u>>8&255]+k[u>>16&255]+k[u>>24&255]).toUpperCase();h.uuid=e;h.uniforms=m({},d.uniforms,a.uniforms);h.defines=m({},d.defines,a.defines);h.defines["TROIKA_DERIVED_MATERIAL_"+g]="";h.extensions= | ||
m({},d.extensions,a.extensions);h._listeners=void 0;return h},p={constructor:{value:r},isDerivedMaterial:{value:!0},customProgramCacheKey:{writable:!0,configurable:!0,value:function(){return g}},onBeforeCompile:{get:function(){return f},set:function(a){this[e]=a}},copy:{writable:!0,configurable:!0,value:function(a){b.copy.call(this,a);b.isShaderMaterial||b.isDerivedMaterial||(m(this.extensions,a.extensions),m(this.defines,a.defines),m(this.uniforms,c.UniformsUtils.clone(a.uniforms)));return this}}, | ||
clone:{writable:!0,configurable:!0,value:function(){var a=new b.constructor;return w(a).copy(this)}},getDepthMaterial:{writable:!0,configurable:!0,value:function(){var d=this._depthMaterial;d||(d=this._depthMaterial=n(b.isDerivedMaterial?b.getDepthMaterial():new c.MeshDepthMaterial({depthPacking:c.RGBADepthPacking}),a),d.defines.IS_DEPTH_MATERIAL="",d.uniforms=this.uniforms);return d}},getDistanceMaterial:{writable:!0,configurable:!0,value:function(){var d=this._distanceMaterial;d||(d=this._distanceMaterial= | ||
n(b.isDerivedMaterial?b.getDistanceMaterial():new c.MeshDistanceMaterial,a),d.defines.IS_DISTANCE_MATERIAL="",d.uniforms=this.uniforms);return d}},dispose:{writable:!0,configurable:!0,value:function(){var a=this._depthMaterial,d=this._distanceMaterial;a&&a.dispose();d&&d.dispose();b.dispose.call(this)}}};d[g]=r;return new r}function D(b,a,g){var d=b.vertexShader,e=b.fragmentShader;b=a.vertexDefs;var c=a.vertexMainIntro,f=a.vertexMainOutro,k=a.vertexTransform,p=a.fragmentDefs,h=a.fragmentMainIntro, | ||
m=a.fragmentMainOutro,l=a.fragmentColorTransform,n=a.customRewriter;a=a.timeUniform;b=b||"";c=c||"";f=f||"";p=p||"";h=h||"";m=m||"";if(k||n)d=t(d);if(l||n)e=e.replace(/^[ \t]*#include <((?:tonemapping|encodings|fog|premultiplied_alpha|dithering)_fragment)>/gm,"\n//!BEGIN_POST_CHUNK $1\n$&\n//!END_POST_CHUNK\n"),e=t(e);n&&(e=n({vertexShader:d,fragmentShader:e}),d=e.vertexShader,e=e.fragmentShader);if(l){var q=[];e=e.replace(/^\/\/!BEGIN_POST_CHUNK[^]+?^\/\/!END_POST_CHUNK/gm,function(a){q.push(a); | ||
return""});m=l+"\n"+q.join("\n")+"\n"+m}a&&(l="\nuniform float "+a+";\n",b=l+b,p=l+p);k&&(b=b+"\nvoid troikaVertexTransform"+g+"(inout vec3 position, inout vec3 normal, inout vec2 uv) {\n "+k+"\n}\n",c="\ntroika_position_"+g+" = vec3(position);\ntroika_normal_"+g+" = vec3(normal);\ntroika_uv_"+g+" = vec2(uv);\ntroikaVertexTransform"+g+"(troika_position_"+g+", troika_normal_"+g+", troika_uv_"+g+");\n"+c+"\n",d=("vec3 troika_position_"+g+";\nvec3 troika_normal_"+g+";\nvec2 troika_uv_"+g+";\n"+d+"\n").replace(/\b(position|normal|uv)\b/g, | ||
function(a,d,b,c){return/\battribute\s+vec[23]\s+$/.test(c.substr(0,b))?d:"troika_"+d+"_"+g}));d=x(d,g,b,c,f);e=x(e,g,p,h,m);return{vertexShader:d,fragmentShader:e}}function x(b,a,c,d,e){if(d||e||c)b=b.replace(y,"\n"+c+"\nvoid troikaOrigMain"+a+"() {"),b+="\nvoid main() {\n "+d+"\n troikaOrigMain"+a+"();\n "+e+"\n}";return b}function G(b,a){return"uniforms"===b?void 0:"function"===typeof a?a.toString():a}function C(b){b=JSON.stringify(b,G);var a=z.get(b);null==a&&z.set(b,a=++H);return a}for(var y= | ||
/\bvoid\s+main\s*\(\s*\)\s*{/g,k=[],l=0;256>l;l++)k[l]=(16>l?"0":"")+l.toString(16);var m=Object.assign||function(){for(var b=arguments,a=arguments[0],c=1,d=arguments.length;c<d;c++){var e=b[c];if(e)for(var f in e)e.hasOwnProperty(f)&&(a[f]=e[f])}return a},E=Date.now(),q=new WeakMap,v=new Map,F=1E10,H=0,z=new Map,I={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon", | ||
MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"},A=null,B=new c.MeshStandardMaterial({color:16777215,side:c.DoubleSide});l=function(b){function a(){b.call(this,a.getGeometry(),B);this.pointA=new c.Vector3;this.controlA=new c.Vector3;this.controlB=new c.Vector3;this.pointB=new c.Vector3;this.radius=.01;this.dashArray=new c.Vector2; | ||
this.dashOffset=0;this.frustumCulled=!1}b&&(a.__proto__=b);a.prototype=Object.create(b&&b.prototype);a.prototype.constructor=a;var g={material:{configurable:!0},customDepthMaterial:{configurable:!0},customDistanceMaterial:{configurable:!0}};a.getGeometry=function(){return A||(A=(new c.CylinderBufferGeometry(1,1,1,6,64)).translate(0,.5,0))};g.material.get=function(){var a=this._derivedMaterial,b=this._baseMaterial||this._defaultMaterial||(this._defaultMaterial=B.clone());a&&a.baseMaterial===b||(a= | ||
this._derivedMaterial=n(b,{chained:!0,uniforms:{pointA:{value:new c.Vector3},controlA:{value:new c.Vector3},controlB:{value:new c.Vector3},pointB:{value:new c.Vector3},radius:{value:.01},dashing:{value:new c.Vector3}},vertexDefs:"\nuniform vec3 pointA;\nuniform vec3 controlA;\nuniform vec3 controlB;\nuniform vec3 pointB;\nuniform float radius;\nvarying float bezierT;\n\nvec3 cubicBezier(vec3 p1, vec3 c1, vec3 c2, vec3 p2, float t) {\n float t2 = 1.0 - t;\n float b0 = t2 * t2 * t2;\n float b1 = 3.0 * t * t2 * t2;\n float b2 = 3.0 * t * t * t2;\n float b3 = t * t * t;\n return b0 * p1 + b1 * c1 + b2 * c2 + b3 * p2;\n}\n\nvec3 cubicBezierDerivative(vec3 p1, vec3 c1, vec3 c2, vec3 p2, float t) {\n float t2 = 1.0 - t;\n return -3.0 * p1 * t2 * t2 +\n c1 * (3.0 * t2 * t2 - 6.0 * t2 * t) +\n c2 * (6.0 * t2 * t - 3.0 * t * t) +\n 3.0 * p2 * t * t;\n}\n", | ||
vertexTransform:'\nfloat t = position.y;\nbezierT = t;\nvec3 bezierCenterPos = cubicBezier(pointA, controlA, controlB, pointB, t);\nvec3 bezierDir = normalize(cubicBezierDerivative(pointA, controlA, controlB, pointB, t));\n\n// Make "sideways" always perpendicular to the camera ray; this ensures that any twists\n// in the cylinder occur where you won\'t see them: \nvec3 viewDirection = normalMatrix * vec3(0.0, 0.0, 1.0);\nif (bezierDir == viewDirection) {\n bezierDir = normalize(cubicBezierDerivative(pointA, controlA, controlB, pointB, t == 1.0 ? t - 0.0001 : t + 0.0001));\n}\nvec3 sideways = normalize(cross(bezierDir, viewDirection));\nvec3 upish = normalize(cross(sideways, bezierDir));\n\n// Build a matrix for transforming this disc in the cylinder:\nmat4 discTx;\ndiscTx[0].xyz = sideways * radius;\ndiscTx[1].xyz = bezierDir * radius;\ndiscTx[2].xyz = upish * radius;\ndiscTx[3].xyz = bezierCenterPos;\ndiscTx[3][3] = 1.0;\n\n// Apply transform, ignoring original y\nposition = (discTx * vec4(position.x, 0.0, position.z, 1.0)).xyz;\nnormal = normalize(mat3(discTx) * normal);\n', | ||
fragmentDefs:"\nuniform vec3 dashing;\nvarying float bezierT;\n",fragmentMainIntro:"\nif (dashing.x + dashing.y > 0.0) {\n float dashFrac = mod(bezierT - dashing.z, dashing.x + dashing.y);\n if (dashFrac > dashing.x) {\n discard;\n }\n}\n"}),b.addEventListener("dispose",function r(){b.removeEventListener("dispose",r);a.dispose()}));return a};e.material.set=function(a){this._baseMaterial=a};e.customDepthMaterial.get=function(){return this.material.getDepthMaterial()};e.customDistanceMaterial.get= | ||
function(){return this.material.getDistanceMaterial()};a.prototype.onBeforeRender=function(a){a=this.material.uniforms;var b=this.controlA,d=this.controlB,c=this.pointB,e=this.radius,f=this.dashArray,h=this.dashOffset;a.pointA.value.copy(this.pointA);a.controlA.value.copy(b);a.controlB.value.copy(d);a.pointB.value.copy(c);a.radius.value=e;a.dashing.value.set(f.x,f.y,h||0)};a.prototype.raycast=function(a,b){};Object.defineProperties(a.prototype,e);return a}(c.Mesh);f.BezierMesh=H;f.createDerivedMaterial= | ||
l;f.expandShaderIncludes=t;f.getShaderUniformTypes=function(b){for(var a=/\buniform\s+(int|float|vec[234])\s+([A-Za-z_][\w]*)/g,c=Object.create(null),d;null!==(d=a.exec(b));)c[d[2]]=d[1];return c};f.getShadersForMaterial=function(b){var a=G[b.type];return a?c.ShaderLib[a]:b};f.invertMatrix4=function(b,a){void 0===a&&(a=new c.Matrix4);"function"===typeof a.invert?a.copy(b).invert():a.getInverse(b);return a};f.voidMainRegExp=w;Object.defineProperty(f,"__esModule",{value:!0})}) | ||
fragmentDefs:"\nuniform vec3 dashing;\nvarying float bezierT;\n",fragmentMainIntro:"\nif (dashing.x + dashing.y > 0.0) {\n float dashFrac = mod(bezierT - dashing.z, dashing.x + dashing.y);\n if (dashFrac > dashing.x) {\n discard;\n }\n}\n"}),b.addEventListener("dispose",function r(){b.removeEventListener("dispose",r);a.dispose()}));return a};g.material.set=function(a){this._baseMaterial=a};g.customDepthMaterial.get=function(){return this.material.getDepthMaterial()};g.customDistanceMaterial.get= | ||
function(){return this.material.getDistanceMaterial()};a.prototype.onBeforeRender=function(a){a=this.material.uniforms;var b=this.controlA,c=this.controlB,d=this.pointB,g=this.radius,f=this.dashArray,h=this.dashOffset;a.pointA.value.copy(this.pointA);a.controlA.value.copy(b);a.controlB.value.copy(c);a.pointB.value.copy(d);a.radius.value=g;a.dashing.value.set(f.x,f.y,h||0)};a.prototype.raycast=function(a,b){};Object.defineProperties(a.prototype,g);return a}(c.Mesh);f.BezierMesh=l;f.createDerivedMaterial= | ||
n;f.expandShaderIncludes=t;f.getShaderUniformTypes=function(b){for(var a=/\buniform\s+(int|float|vec[234])\s+([A-Za-z_][\w]*)/g,c=Object.create(null),d;null!==(d=a.exec(b));)c[d[2]]=d[1];return c};f.getShadersForMaterial=function(b){var a=I[b.type];return a?c.ShaderLib[a]:b};f.invertMatrix4=function(b,a){void 0===a&&(a=new c.Matrix4);"function"===typeof a.invert?a.copy(b).invert():a.getInverse(b);return a};f.voidMainRegExp=y;Object.defineProperty(f,"__esModule",{value:!0})}) |
{ | ||
"name": "troika-three-utils", | ||
"version": "0.38.1", | ||
"version": "0.39.0", | ||
"description": "Various utilities related to Three.js", | ||
@@ -19,3 +19,3 @@ "author": "Jason Johnston <jason.johnston@protectwise.com>", | ||
}, | ||
"gitHead": "b54fd6f27b4d95190747ff94cf4e101239447fea" | ||
"gitHead": "8c276e7cf6580ebd57d3fee8b2575dac27667491" | ||
} |
@@ -14,5 +14,11 @@ # Troika Three.js Utilities | ||
You will also need to install a compatible version of [Three.js](https://threejs.org); see the notes in the [Troika 3D Readme](../troika-3d/README.md#installation) for details. | ||
You will also need to install a compatible version of [Three.js](https://threejs.org), which is declared with a wide version range in `peerDependencies` rather than a direct dependency on a specific version, to give you flexibility in choosing a specific version for your application. | ||
```sh | ||
npm install three | ||
``` | ||
You can look in the [package.json](./package.json) under `"peerDependencies"` for a range of Three.js versions that has been verified to work with this and all other Troika packages. Other versions that have not been specifically tested may also work depending on the features you use, they just haven't been explicitly tested. | ||
## Provided Utilities | ||
@@ -24,67 +30,19 @@ | ||
### createDerivedMaterial() | ||
_[Source code with JSDoc](./src/DerivedMaterial.js)_ | ||
This utility allows you to easily _extend_ existing Three.js materials with your own custom shader code. This is an incredibly powerful tool, and is the secret behind most of Troika's shader-driven tools like `troika-three-text`, `three-instanced-uniforms-mesh`, and `BezierMesh`. | ||
One of the most powerful things about Three.js is its excellent set of built-in materials. They provide many features like physically-based reflectivity, shadows, texture maps, fog, and so on, building the very complex shaders behind the scenes. | ||
See the [createDerivedMaterial documentation page](./docs/createDerivedMaterial.md) and its [source code with JSDoc](./src/DerivedMaterial.js) for details. | ||
But sometimes you need to do something custom in the shaders, such as move around the vertices, or change the colors or transparency of certain pixels. You could use a [ShaderMaterial](https://threejs.org/docs/#api/en/materials/ShaderMaterial) but then you lose all the built-in features. The experimental [NodeMaterial](https://www.donmccurdy.com/2019/03/17/three-nodematerial-introduction/) seems promising but doesn't appear to be ready as a full replacement. | ||
The [onBeforeCompile](https://threejs.org/docs/#api/en/materials/Material.onBeforeCompile) hook lets you intercept the shader code and modify it, but in practice there are quirks to this that make it difficult to work with, not to mention the complexity of forming regular expressions to inject your custom shader code in the right places. | ||
Troika's `createDerivedMaterial(baseMaterial, options)` utility handles all that complexity, letting you "extend" a built-in Material's shaders via a declarative interface. The resulting material is prototype-chained to the base material so it picks up changes to its properties. It has methods for generating depth and distance materials so your shader modifications can be reflected in shadow maps. Derived materials may themselves be derived from recursively for composability. | ||
Here's a simple example that injects an auto-incrementing `elapsed` uniform holding the current time, and uses that to transform the vertices in a wave pattern. | ||
```js | ||
import { createDerivedMaterial} from 'troika-three-utils' | ||
import { Mesh, MeshStandardMaterial, PlaneBufferGeometry } from 'three' | ||
const baseMaterial = new MeshStandardMaterial({color: 0xffcc00}) | ||
const customMaterial = createDerivedMaterial( | ||
baseMaterial, | ||
{ | ||
timeUniform: 'elapsed', | ||
vertexTransform: ` | ||
float waveAmplitude = 0.1 | ||
float waveX = uv.x * PI * 4.0 - mod(elapsed / 300.0, PI2); | ||
float waveZ = sin(waveX) * waveAmplitude; | ||
normal.xyz = normalize(vec3(-cos(waveX) * waveAmplitude, 0.0, 1.0)); | ||
position.z += waveZ; | ||
` | ||
} | ||
) | ||
const mesh = new Mesh( | ||
new PlaneBufferGeometry(1, 1, 64, 1), | ||
customMaterial | ||
) | ||
mesh.customDepthMaterial = customMaterial.getDepthMaterial() //for shadows | ||
``` | ||
You can also declare custom `uniforms` and `defines`, inject fragment shader code to modify the output color, etc. See the JSDoc in [DerivedMaterial.js](./src/DerivedMaterial.js) for full details. | ||
### BezierMesh | ||
_[Source code with JSDoc](./src/BezierMesh.js)_ | ||
_[Online example](https://troika-examples.netlify.com/#bezier3d)_ | ||
_[Online example using InstancedUniformsMesh](https://ibyou.csb.app/)_ | ||
This creates a cylindrical mesh and bends it along a 3D cubic bezier path between two points, in a custom derived vertex shader. This is useful for visually connecting objects in 3D space with a line that has thickness to it. | ||
```js | ||
import { BezierMesh } from 'troika-three-utils' | ||
See the [BezierMesh documentation page](./docs/BezierMesh.md) and its [source code with JSDoc](./src/BezierMesh.js) for details. | ||
const bezier = new BezierMesh() | ||
bezier.pointA.set(-0.3, 0.4, -0.3) | ||
bezier.controlA.set(0.7, 0.6, 0.4) | ||
bezier.controlB.set(-0.6, -0.6, -0.6) | ||
bezier.pointB.set(0.7, 0, -0.7) | ||
bezier.radius = 0.01 | ||
scene.add(bezier) | ||
``` | ||
### InstancedUniformsMesh | ||
> NOTE: InstancedUniformsMesh has been moved to [its own `three-instanced-uniforms-mesh` package](https://github.com/protectwise/troika/tree/master/packages/three-instanced-uniforms-mesh). |
import { voidMainRegExp } from './voidMainRegExp.js' | ||
import { expandShaderIncludes } from './expandShaderIncludes.js' | ||
import { MathUtils, MeshDepthMaterial, MeshDistanceMaterial, RGBADepthPacking, UniformsUtils } from 'three' | ||
import { MeshDepthMaterial, MeshDistanceMaterial, RGBADepthPacking, UniformsUtils } from 'three' | ||
import { generateUUID } from './generateUUID.js' | ||
@@ -153,3 +154,3 @@ // Local assign polyfill to avoid importing troika-core | ||
Object.defineProperty(derived, 'id', { value: materialInstanceId++ }) | ||
derived.uuid = MathUtils.generateUUID() | ||
derived.uuid = generateUUID() | ||
@@ -156,0 +157,0 @@ // Merge uniforms, defines, and extensions |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
123184
21
2275
47