mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2026-01-25 15:08:11 +00:00
1596 lines
85 KiB
JavaScript
1596 lines
85 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('three')) :
|
|
typeof define === 'function' && define.amd ? define(['exports', 'three'], factory) :
|
|
(factory((global.BAS = {}),global.THREE));
|
|
}(this, (function (exports,three) { 'use strict';
|
|
|
|
function BaseAnimationMaterial(parameters, uniforms) {
|
|
three.ShaderMaterial.call(this);
|
|
|
|
var uniformValues = parameters.uniformValues;
|
|
delete parameters.uniformValues;
|
|
|
|
this.setValues(parameters);
|
|
|
|
this.uniforms = three.UniformsUtils.merge([uniforms, this.uniforms]);
|
|
|
|
this.setUniformValues(uniformValues);
|
|
|
|
if (uniformValues) {
|
|
uniformValues.map && (this.defines['USE_MAP'] = '');
|
|
uniformValues.normalMap && (this.defines['USE_NORMALMAP'] = '');
|
|
uniformValues.envMap && (this.defines['USE_ENVMAP'] = '');
|
|
uniformValues.aoMap && (this.defines['USE_AOMAP'] = '');
|
|
uniformValues.specularMap && (this.defines['USE_SPECULARMAP'] = '');
|
|
uniformValues.alphaMap && (this.defines['USE_ALPHAMAP'] = '');
|
|
uniformValues.lightMap && (this.defines['USE_LIGHTMAP'] = '');
|
|
uniformValues.emissiveMap && (this.defines['USE_EMISSIVEMAP'] = '');
|
|
uniformValues.bumpMap && (this.defines['USE_BUMPMAP'] = '');
|
|
uniformValues.displacementMap && (this.defines['USE_DISPLACEMENTMAP'] = '');
|
|
uniformValues.roughnessMap && (this.defines['USE_DISPLACEMENTMAP'] = '');
|
|
uniformValues.roughnessMap && (this.defines['USE_ROUGHNESSMAP'] = '');
|
|
uniformValues.metalnessMap && (this.defines['USE_METALNESSMAP'] = '');
|
|
|
|
if (uniformValues.envMap) {
|
|
this.defines['USE_ENVMAP'] = '';
|
|
|
|
var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
|
|
var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
|
|
var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
|
|
|
|
switch (uniformValues.envMap.mapping) {
|
|
case three.CubeReflectionMapping:
|
|
case three.CubeRefractionMapping:
|
|
envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
|
|
break;
|
|
case three.CubeUVReflectionMapping:
|
|
case three.CubeUVRefractionMapping:
|
|
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
|
|
break;
|
|
case three.EquirectangularReflectionMapping:
|
|
case three.EquirectangularRefractionMapping:
|
|
envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
|
|
break;
|
|
case three.SphericalReflectionMapping:
|
|
envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
|
|
break;
|
|
}
|
|
|
|
switch (uniformValues.envMap.mapping) {
|
|
case three.CubeRefractionMapping:
|
|
case three.EquirectangularRefractionMapping:
|
|
envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
|
|
break;
|
|
}
|
|
|
|
switch (uniformValues.combine) {
|
|
case three.MixOperation:
|
|
envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
|
|
break;
|
|
case three.AddOperation:
|
|
envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
|
|
break;
|
|
case three.MultiplyOperation:
|
|
default:
|
|
envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
|
|
break;
|
|
}
|
|
|
|
this.defines[envMapTypeDefine] = '';
|
|
this.defines[envMapBlendingDefine] = '';
|
|
this.defines[envMapModeDefine] = '';
|
|
}
|
|
}
|
|
}
|
|
|
|
BaseAnimationMaterial.prototype = Object.assign(Object.create(three.ShaderMaterial.prototype), {
|
|
constructor: BaseAnimationMaterial,
|
|
|
|
setUniformValues: function setUniformValues(values) {
|
|
var _this = this;
|
|
|
|
if (!values) return;
|
|
|
|
var keys = Object.keys(values);
|
|
|
|
keys.forEach(function (key) {
|
|
key in _this.uniforms && (_this.uniforms[key].value = values[key]);
|
|
});
|
|
},
|
|
stringifyChunk: function stringifyChunk(name) {
|
|
var value = void 0;
|
|
|
|
if (!this[name]) {
|
|
value = '';
|
|
} else if (typeof this[name] === 'string') {
|
|
value = this[name];
|
|
} else {
|
|
value = this[name].join('\n');
|
|
}
|
|
|
|
return value;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Extends THREE.MeshBasicMaterial with custom shader chunks.
|
|
*
|
|
* @see http://three-bas-examples.surge.sh/examples/materials_basic/
|
|
*
|
|
* @param {Object} parameters Object containing material properties and custom shader chunks.
|
|
* @constructor
|
|
*/
|
|
function BasicAnimationMaterial(parameters) {
|
|
this.varyingParameters = [];
|
|
|
|
this.vertexParameters = [];
|
|
this.vertexFunctions = [];
|
|
this.vertexInit = [];
|
|
this.vertexNormal = [];
|
|
this.vertexPosition = [];
|
|
this.vertexColor = [];
|
|
this.vertexPostMorph = [];
|
|
this.vertexPostSkinning = [];
|
|
|
|
this.fragmentFunctions = [];
|
|
this.fragmentParameters = [];
|
|
this.fragmentInit = [];
|
|
this.fragmentMap = [];
|
|
this.fragmentDiffuse = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters, three.ShaderLib['basic'].uniforms);
|
|
|
|
this.lights = false;
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = this.concatFragmentShader();
|
|
}
|
|
BasicAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
BasicAnimationMaterial.prototype.constructor = BasicAnimationMaterial;
|
|
|
|
BasicAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n #include <common>\n #include <uv_pars_vertex>\n #include <uv2_pars_vertex>\n #include <envmap_pars_vertex>\n #include <color_pars_vertex>\n #include <fog_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n\n ' + this.stringifyChunk('vertexInit') + '\n \n #include <uv_vertex>\n #include <uv2_vertex>\n #include <color_vertex>\n #include <skinbase_vertex>\n \n #ifdef USE_ENVMAP\n \n #include <beginnormal_vertex>\n \n ' + this.stringifyChunk('vertexNormal') + '\n \n #include <morphnormal_vertex>\n #include <skinnormal_vertex>\n #include <defaultnormal_vertex>\n \n #endif\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n ' + this.stringifyChunk('vertexColor') + '\n \n #include <morphtarget_vertex>\n \n ' + this.stringifyChunk('vertexPostMorph') + '\n \n #include <skinning_vertex>\n\n ' + this.stringifyChunk('vertexPostSkinning') + '\n\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n \n #include <worldpos_vertex>\n #include <clipping_planes_vertex>\n #include <envmap_vertex>\n #include <fog_vertex>\n }';
|
|
};
|
|
|
|
BasicAnimationMaterial.prototype.concatFragmentShader = function () {
|
|
return '\n uniform vec3 diffuse;\n uniform float opacity;\n \n ' + this.stringifyChunk('fragmentParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('fragmentFunctions') + '\n \n #ifndef FLAT_SHADED\n \n varying vec3 vNormal;\n \n #endif\n \n #include <common>\n #include <color_pars_fragment>\n #include <uv_pars_fragment>\n #include <uv2_pars_fragment>\n #include <map_pars_fragment>\n #include <alphamap_pars_fragment>\n #include <aomap_pars_fragment>\n #include <lightmap_pars_fragment>\n #include <envmap_pars_fragment>\n #include <fog_pars_fragment>\n #include <specularmap_pars_fragment>\n #include <logdepthbuf_pars_fragment>\n #include <clipping_planes_pars_fragment>\n \n void main() {\n \n ' + this.stringifyChunk('fragmentInit') + '\n \n #include <clipping_planes_fragment>\n\n vec4 diffuseColor = vec4( diffuse, opacity );\n\n ' + this.stringifyChunk('fragmentDiffuse') + '\n \n #include <logdepthbuf_fragment>\n \n ' + (this.stringifyChunk('fragmentMap') || '#include <map_fragment>') + '\n \n #include <color_fragment>\n #include <alphamap_fragment>\n #include <alphatest_fragment>\n #include <specularmap_fragment>\n \n ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n \n // accumulation (baked indirect lighting only)\n #ifdef USE_LIGHTMAP\n \n reflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n \n #else\n \n reflectedLight.indirectDiffuse += vec3( 1.0 );\n \n #endif\n \n // modulation\n #include <aomap_fragment>\n \n reflectedLight.indirectDiffuse *= diffuseColor.rgb;\n \n vec3 outgoingLight = reflectedLight.indirectDiffuse;\n \n #include <envmap_fragment>\n \n gl_FragColor = vec4( outgoingLight, diffuseColor.a );\n \n #include <premultiplied_alpha_fragment>\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n #include <fog_fragment>\n }';
|
|
};
|
|
|
|
/**
|
|
* Extends THREE.MeshLambertMaterial with custom shader chunks.
|
|
*
|
|
* @see http://three-bas-examples.surge.sh/examples/materials_lambert/
|
|
*
|
|
* @param {Object} parameters Object containing material properties and custom shader chunks.
|
|
* @constructor
|
|
*/
|
|
function LambertAnimationMaterial(parameters) {
|
|
this.varyingParameters = [];
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexNormal = [];
|
|
this.vertexPosition = [];
|
|
this.vertexColor = [];
|
|
this.vertexPostMorph = [];
|
|
this.vertexPostSkinning = [];
|
|
|
|
this.fragmentFunctions = [];
|
|
this.fragmentParameters = [];
|
|
this.fragmentInit = [];
|
|
this.fragmentMap = [];
|
|
this.fragmentDiffuse = [];
|
|
this.fragmentEmissive = [];
|
|
this.fragmentSpecular = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters, three.ShaderLib['lambert'].uniforms);
|
|
|
|
this.lights = true;
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = this.concatFragmentShader();
|
|
}
|
|
LambertAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
LambertAnimationMaterial.prototype.constructor = LambertAnimationMaterial;
|
|
|
|
LambertAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n #define LAMBERT\n\n varying vec3 vLightFront;\n \n #ifdef DOUBLE_SIDED\n \n varying vec3 vLightBack;\n \n #endif\n \n #include <common>\n #include <uv_pars_vertex>\n #include <uv2_pars_vertex>\n #include <envmap_pars_vertex>\n #include <bsdfs>\n #include <lights_pars_begin>\n #include <lights_pars_maps>\n #include <color_pars_vertex>\n #include <fog_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <shadowmap_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('vertexInit') + '\n \n #include <uv_vertex>\n #include <uv2_vertex>\n #include <color_vertex>\n \n #include <beginnormal_vertex>\n \n ' + this.stringifyChunk('vertexNormal') + '\n \n #include <morphnormal_vertex>\n #include <skinbase_vertex>\n #include <skinnormal_vertex>\n #include <defaultnormal_vertex>\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n ' + this.stringifyChunk('vertexColor') + '\n \n #include <morphtarget_vertex>\n \n ' + this.stringifyChunk('vertexPostMorph') + '\n \n #include <skinning_vertex>\n\n ' + this.stringifyChunk('vertexPostSkinning') + '\n \n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n \n #include <worldpos_vertex>\n #include <envmap_vertex>\n #include <lights_lambert_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n }';
|
|
};
|
|
|
|
LambertAnimationMaterial.prototype.concatFragmentShader = function () {
|
|
return '\n uniform vec3 diffuse;\n uniform vec3 emissive;\n uniform float opacity;\n \n varying vec3 vLightFront;\n \n #ifdef DOUBLE_SIDED\n \n varying vec3 vLightBack;\n \n #endif\n \n #include <common>\n #include <packing>\n #include <dithering_pars_fragment>\n #include <color_pars_fragment>\n #include <uv_pars_fragment>\n #include <uv2_pars_fragment>\n #include <map_pars_fragment>\n #include <alphamap_pars_fragment>\n #include <aomap_pars_fragment>\n #include <lightmap_pars_fragment>\n #include <emissivemap_pars_fragment>\n #include <envmap_pars_fragment>\n #include <bsdfs>\n #include <lights_pars_begin>\n #include <lights_pars_maps>\n #include <fog_pars_fragment>\n #include <shadowmap_pars_fragment>\n #include <shadowmask_pars_fragment>\n #include <specularmap_pars_fragment>\n #include <logdepthbuf_pars_fragment>\n #include <clipping_planes_pars_fragment>\n \n ' + this.stringifyChunk('fragmentParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('fragmentFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('fragmentInit') + '\n \n #include <clipping_planes_fragment>\n\n vec4 diffuseColor = vec4( diffuse, opacity );\n ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n vec3 totalEmissiveRadiance = emissive;\n\t\n ' + this.stringifyChunk('fragmentDiffuse') + '\n \n #include <logdepthbuf_fragment>\n\n ' + (this.stringifyChunk('fragmentMap') || '#include <map_fragment>') + '\n\n #include <color_fragment>\n #include <alphamap_fragment>\n #include <alphatest_fragment>\n #include <specularmap_fragment>\n\n ' + this.stringifyChunk('fragmentEmissive') + '\n\n #include <emissivemap_fragment>\n \n // accumulation\n reflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n \n #include <lightmap_fragment>\n \n reflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n \n #ifdef DOUBLE_SIDED\n \n reflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n \n #else\n \n reflectedLight.directDiffuse = vLightFront;\n \n #endif\n \n reflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n \n // modulation\n #include <aomap_fragment>\n \n vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n \n #include <envmap_fragment>\n \n gl_FragColor = vec4( outgoingLight, diffuseColor.a );\n \n #include <tonemapping_fragment>\n #include <encodings_fragment>\n #include <fog_fragment>\n #include <premultiplied_alpha_fragment>\n #include <dithering_fragment>\n }';
|
|
};
|
|
|
|
/**
|
|
* Extends THREE.MeshPhongMaterial with custom shader chunks.
|
|
*
|
|
* @see http://three-bas-examples.surge.sh/examples/materials_phong/
|
|
*
|
|
* @param {Object} parameters Object containing material properties and custom shader chunks.
|
|
* @constructor
|
|
*/
|
|
function PhongAnimationMaterial(parameters) {
|
|
this.varyingParameters = [];
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexNormal = [];
|
|
this.vertexPosition = [];
|
|
this.vertexColor = [];
|
|
|
|
this.fragmentFunctions = [];
|
|
this.fragmentParameters = [];
|
|
this.fragmentInit = [];
|
|
this.fragmentMap = [];
|
|
this.fragmentDiffuse = [];
|
|
this.fragmentEmissive = [];
|
|
this.fragmentSpecular = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters, three.ShaderLib['phong'].uniforms);
|
|
|
|
this.lights = true;
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = this.concatFragmentShader();
|
|
}
|
|
PhongAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
PhongAnimationMaterial.prototype.constructor = PhongAnimationMaterial;
|
|
|
|
PhongAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n #define PHONG\n\n varying vec3 vViewPosition;\n \n #ifndef FLAT_SHADED\n \n varying vec3 vNormal;\n \n #endif\n \n #include <common>\n #include <uv_pars_vertex>\n #include <uv2_pars_vertex>\n #include <displacementmap_pars_vertex>\n #include <envmap_pars_vertex>\n #include <color_pars_vertex>\n #include <fog_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <shadowmap_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('vertexInit') + '\n \n #include <uv_vertex>\n #include <uv2_vertex>\n #include <color_vertex>\n \n #include <beginnormal_vertex>\n \n ' + this.stringifyChunk('vertexNormal') + '\n \n #include <morphnormal_vertex>\n #include <skinbase_vertex>\n #include <skinnormal_vertex>\n #include <defaultnormal_vertex>\n \n #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\n \n vNormal = normalize( transformedNormal );\n \n #endif\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n ' + this.stringifyChunk('vertexColor') + '\n \n #include <morphtarget_vertex>\n #include <skinning_vertex>\n #include <displacementmap_vertex>\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n \n vViewPosition = - mvPosition.xyz;\n \n #include <worldpos_vertex>\n #include <envmap_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n }';
|
|
};
|
|
|
|
PhongAnimationMaterial.prototype.concatFragmentShader = function () {
|
|
return '\n #define PHONG\n\n uniform vec3 diffuse;\n uniform vec3 emissive;\n uniform vec3 specular;\n uniform float shininess;\n uniform float opacity;\n \n #include <common>\n #include <packing>\n #include <dithering_pars_fragment>\n #include <color_pars_fragment>\n #include <uv_pars_fragment>\n #include <uv2_pars_fragment>\n #include <map_pars_fragment>\n #include <alphamap_pars_fragment>\n #include <aomap_pars_fragment>\n #include <lightmap_pars_fragment>\n #include <emissivemap_pars_fragment>\n #include <envmap_pars_fragment>\n #include <gradientmap_pars_fragment>\n #include <fog_pars_fragment>\n #include <bsdfs>\n #include <lights_pars_begin>\n #include <lights_pars_maps>\n #include <lights_phong_pars_fragment>\n #include <shadowmap_pars_fragment>\n #include <bumpmap_pars_fragment>\n #include <normalmap_pars_fragment>\n #include <specularmap_pars_fragment>\n #include <logdepthbuf_pars_fragment>\n #include <clipping_planes_pars_fragment>\n \n ' + this.stringifyChunk('fragmentParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('fragmentFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('fragmentInit') + '\n \n #include <clipping_planes_fragment>\n \n vec4 diffuseColor = vec4( diffuse, opacity );\n ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n vec3 totalEmissiveRadiance = emissive;\n \n ' + this.stringifyChunk('fragmentDiffuse') + '\n \n #include <logdepthbuf_fragment>\n\n ' + (this.stringifyChunk('fragmentMap') || '#include <map_fragment>') + '\n\n #include <color_fragment>\n #include <alphamap_fragment>\n #include <alphatest_fragment>\n #include <specularmap_fragment>\n #include <normal_fragment_begin>\n #include <normal_fragment_maps>\n \n ' + this.stringifyChunk('fragmentEmissive') + '\n \n #include <emissivemap_fragment>\n \n // accumulation\n #include <lights_phong_fragment>\n #include <lights_fragment_begin>\n #include <lights_fragment_maps>\n #include <lights_fragment_end>\n \n ' + this.stringifyChunk('fragmentSpecular') + '\n \n // modulation\n #include <aomap_fragment>\n \n vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n \n #include <envmap_fragment>\n \n gl_FragColor = vec4( outgoingLight, diffuseColor.a );\n \n #include <tonemapping_fragment>\n #include <encodings_fragment>\n #include <fog_fragment>\n #include <premultiplied_alpha_fragment>\n #include <dithering_fragment>\n \n }';
|
|
};
|
|
|
|
/**
|
|
* Extends THREE.MeshStandardMaterial with custom shader chunks.
|
|
*
|
|
* @see http://three-bas-examples.surge.sh/examples/materials_standard/
|
|
*
|
|
* @param {Object} parameters Object containing material properties and custom shader chunks.
|
|
* @constructor
|
|
*/
|
|
function StandardAnimationMaterial(parameters) {
|
|
this.varyingParameters = [];
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexNormal = [];
|
|
this.vertexPosition = [];
|
|
this.vertexColor = [];
|
|
this.vertexPostMorph = [];
|
|
this.vertexPostSkinning = [];
|
|
|
|
this.fragmentFunctions = [];
|
|
this.fragmentParameters = [];
|
|
this.fragmentInit = [];
|
|
this.fragmentMap = [];
|
|
this.fragmentDiffuse = [];
|
|
this.fragmentRoughness = [];
|
|
this.fragmentMetalness = [];
|
|
this.fragmentEmissive = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters, three.ShaderLib['standard'].uniforms);
|
|
|
|
this.lights = true;
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = this.concatFragmentShader();
|
|
}
|
|
StandardAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
StandardAnimationMaterial.prototype.constructor = StandardAnimationMaterial;
|
|
|
|
StandardAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n #define PHYSICAL\n\n varying vec3 vViewPosition;\n \n #ifndef FLAT_SHADED\n \n varying vec3 vNormal;\n \n #endif\n \n #include <common>\n #include <uv_pars_vertex>\n #include <uv2_pars_vertex>\n #include <displacementmap_pars_vertex>\n #include <color_pars_vertex>\n #include <fog_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <shadowmap_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n\n ' + this.stringifyChunk('vertexInit') + '\n\n #include <uv_vertex>\n #include <uv2_vertex>\n #include <color_vertex>\n \n #include <beginnormal_vertex>\n \n ' + this.stringifyChunk('vertexNormal') + '\n \n #include <morphnormal_vertex>\n #include <skinbase_vertex>\n #include <skinnormal_vertex>\n #include <defaultnormal_vertex>\n \n #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\n \n vNormal = normalize( transformedNormal );\n \n #endif\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n ' + this.stringifyChunk('vertexColor') + '\n \n #include <morphtarget_vertex>\n \n ' + this.stringifyChunk('vertexPostMorph') + '\n \n #include <skinning_vertex>\n\n ' + this.stringifyChunk('vertexPostSkinning') + '\n \n #include <displacementmap_vertex>\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n \n vViewPosition = - mvPosition.xyz;\n \n #include <worldpos_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n }';
|
|
};
|
|
|
|
StandardAnimationMaterial.prototype.concatFragmentShader = function () {
|
|
return '\n #define PHYSICAL\n \n uniform vec3 diffuse;\n uniform vec3 emissive;\n uniform float roughness;\n uniform float metalness;\n uniform float opacity;\n \n #ifndef STANDARD\n uniform float clearCoat;\n uniform float clearCoatRoughness;\n #endif\n \n varying vec3 vViewPosition;\n \n #ifndef FLAT_SHADED\n \n varying vec3 vNormal;\n \n #endif\n \n #include <common>\n #include <packing>\n #include <dithering_pars_fragment>\n #include <color_pars_fragment>\n #include <uv_pars_fragment>\n #include <uv2_pars_fragment>\n #include <map_pars_fragment>\n #include <alphamap_pars_fragment>\n #include <aomap_pars_fragment>\n #include <lightmap_pars_fragment>\n #include <emissivemap_pars_fragment>\n #include <envmap_pars_fragment>\n #include <fog_pars_fragment>\n #include <bsdfs>\n #include <cube_uv_reflection_fragment>\n #include <lights_pars_begin>\n #include <lights_pars_maps>\n #include <lights_physical_pars_fragment>\n #include <shadowmap_pars_fragment>\n #include <bumpmap_pars_fragment>\n #include <normalmap_pars_fragment>\n #include <roughnessmap_pars_fragment>\n #include <metalnessmap_pars_fragment>\n #include <logdepthbuf_pars_fragment>\n #include <clipping_planes_pars_fragment>\n \n ' + this.stringifyChunk('fragmentParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('fragmentFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('fragmentInit') + '\n \n #include <clipping_planes_fragment>\n \n vec4 diffuseColor = vec4( diffuse, opacity );\n ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n vec3 totalEmissiveRadiance = emissive;\n \n ' + this.stringifyChunk('fragmentDiffuse') + '\n \n #include <logdepthbuf_fragment>\n\n ' + (this.stringifyChunk('fragmentMap') || '#include <map_fragment>') + '\n\n #include <color_fragment>\n #include <alphamap_fragment>\n #include <alphatest_fragment>\n \n float roughnessFactor = roughness;\n ' + this.stringifyChunk('fragmentRoughness') + '\n #ifdef USE_ROUGHNESSMAP\n \n vec4 texelRoughness = texture2D( roughnessMap, vUv );\n \n // reads channel G, compatible with a combined OcclusionRoughnessMetallic (RGB) texture\n roughnessFactor *= texelRoughness.g;\n \n #endif\n \n float metalnessFactor = metalness;\n ' + this.stringifyChunk('fragmentMetalness') + '\n #ifdef USE_METALNESSMAP\n \n vec4 texelMetalness = texture2D( metalnessMap, vUv );\n metalnessFactor *= texelMetalness.b;\n \n #endif\n \n #include <normal_fragment_begin>\n #include <normal_fragment_maps>\n \n ' + this.stringifyChunk('fragmentEmissive') + '\n \n #include <emissivemap_fragment>\n \n // accumulation\n #include <lights_physical_fragment>\n #include <lights_fragment_begin>\n #include <lights_fragment_maps>\n #include <lights_fragment_end>\n \n // modulation\n #include <aomap_fragment>\n \n vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n \n gl_FragColor = vec4( outgoingLight, diffuseColor.a );\n \n #include <tonemapping_fragment>\n #include <encodings_fragment>\n #include <fog_fragment>\n #include <premultiplied_alpha_fragment>\n #include <dithering_fragment>\n \n }';
|
|
};
|
|
|
|
/**
|
|
* Extends THREE.PointsMaterial with custom shader chunks.
|
|
*
|
|
* @param {Object} parameters Object containing material properties and custom shader chunks.
|
|
* @constructor
|
|
*/
|
|
function PointsAnimationMaterial(parameters) {
|
|
this.varyingParameters = [];
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexPosition = [];
|
|
this.vertexColor = [];
|
|
|
|
this.fragmentFunctions = [];
|
|
this.fragmentParameters = [];
|
|
this.fragmentInit = [];
|
|
this.fragmentMap = [];
|
|
this.fragmentDiffuse = [];
|
|
// use fragment shader to shape to point, reference: https://thebookofshaders.com/07/
|
|
this.fragmentShape = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters, three.ShaderLib['points'].uniforms);
|
|
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = this.concatFragmentShader();
|
|
}
|
|
|
|
PointsAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
PointsAnimationMaterial.prototype.constructor = PointsAnimationMaterial;
|
|
|
|
PointsAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n uniform float size;\n uniform float scale;\n \n #include <common>\n #include <color_pars_vertex>\n #include <fog_pars_vertex>\n #include <shadowmap_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('vertexInit') + '\n \n #include <color_vertex>\n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n ' + this.stringifyChunk('vertexColor') + '\n \n #include <project_vertex>\n \n #ifdef USE_SIZEATTENUATION\n gl_PointSize = size * ( scale / - mvPosition.z );\n #else\n gl_PointSize = size;\n #endif\n \n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n #include <worldpos_vertex>\n #include <shadowmap_vertex>\n #include <fog_vertex>\n }';
|
|
};
|
|
|
|
PointsAnimationMaterial.prototype.concatFragmentShader = function () {
|
|
return '\n uniform vec3 diffuse;\n uniform float opacity;\n \n #include <common>\n #include <packing>\n #include <color_pars_fragment>\n #include <map_particle_pars_fragment>\n #include <fog_pars_fragment>\n #include <shadowmap_pars_fragment>\n #include <logdepthbuf_pars_fragment>\n #include <clipping_planes_pars_fragment>\n \n ' + this.stringifyChunk('fragmentParameters') + '\n ' + this.stringifyChunk('varyingParameters') + '\n ' + this.stringifyChunk('fragmentFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('fragmentInit') + '\n \n #include <clipping_planes_fragment>\n \n vec3 outgoingLight = vec3( 0.0 );\n vec4 diffuseColor = vec4( diffuse, opacity );\n \n ' + this.stringifyChunk('fragmentDiffuse') + '\n \n #include <logdepthbuf_fragment>\n\n ' + (this.stringifyChunk('fragmentMap') || '#include <map_particle_fragment>') + '\n\n #include <color_fragment>\n #include <alphatest_fragment>\n \n outgoingLight = diffuseColor.rgb;\n \n gl_FragColor = vec4( outgoingLight, diffuseColor.a );\n \n ' + this.stringifyChunk('fragmentShape') + '\n \n #include <premultiplied_alpha_fragment>\n #include <tonemapping_fragment>\n #include <encodings_fragment>\n #include <fog_fragment>\n }';
|
|
};
|
|
|
|
function DepthAnimationMaterial(parameters) {
|
|
this.depthPacking = three.RGBADepthPacking;
|
|
this.clipping = true;
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexPosition = [];
|
|
this.vertexPostMorph = [];
|
|
this.vertexPostSkinning = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters);
|
|
|
|
this.uniforms = three.UniformsUtils.merge([three.ShaderLib['depth'].uniforms, this.uniforms]);
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = three.ShaderLib['depth'].fragmentShader;
|
|
}
|
|
DepthAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
DepthAnimationMaterial.prototype.constructor = DepthAnimationMaterial;
|
|
|
|
DepthAnimationMaterial.prototype.concatVertexShader = function () {
|
|
|
|
return '\n #include <common>\n #include <uv_pars_vertex>\n #include <displacementmap_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <logdepthbuf_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n \n ' + this.stringifyChunk('vertexInit') + '\n \n #include <uv_vertex>\n \n #include <skinbase_vertex>\n \n #ifdef USE_DISPLACEMENTMAP\n \n #include <beginnormal_vertex>\n #include <morphnormal_vertex>\n #include <skinnormal_vertex>\n \n #endif\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n\n #include <morphtarget_vertex>\n \n ' + this.stringifyChunk('vertexPostMorph') + '\n \n #include <skinning_vertex>\n\n ' + this.stringifyChunk('vertexPostSkinning') + '\n \n #include <displacementmap_vertex>\n #include <project_vertex>\n #include <logdepthbuf_vertex>\n #include <clipping_planes_vertex>\n }';
|
|
};
|
|
|
|
function DistanceAnimationMaterial(parameters) {
|
|
this.depthPacking = three.RGBADepthPacking;
|
|
this.clipping = true;
|
|
|
|
this.vertexFunctions = [];
|
|
this.vertexParameters = [];
|
|
this.vertexInit = [];
|
|
this.vertexPosition = [];
|
|
this.vertexPostMorph = [];
|
|
this.vertexPostSkinning = [];
|
|
|
|
BaseAnimationMaterial.call(this, parameters);
|
|
|
|
this.uniforms = three.UniformsUtils.merge([three.ShaderLib['distanceRGBA'].uniforms, this.uniforms]);
|
|
this.vertexShader = this.concatVertexShader();
|
|
this.fragmentShader = three.ShaderLib['distanceRGBA'].fragmentShader;
|
|
}
|
|
DistanceAnimationMaterial.prototype = Object.create(BaseAnimationMaterial.prototype);
|
|
DistanceAnimationMaterial.prototype.constructor = DistanceAnimationMaterial;
|
|
|
|
DistanceAnimationMaterial.prototype.concatVertexShader = function () {
|
|
return '\n #define DISTANCE\n\n varying vec3 vWorldPosition;\n \n #include <common>\n #include <uv_pars_vertex>\n #include <displacementmap_pars_vertex>\n #include <morphtarget_pars_vertex>\n #include <skinning_pars_vertex>\n #include <clipping_planes_pars_vertex>\n \n ' + this.stringifyChunk('vertexParameters') + '\n ' + this.stringifyChunk('vertexFunctions') + '\n \n void main() {\n\n ' + this.stringifyChunk('vertexInit') + '\n \n #include <uv_vertex>\n \n #include <skinbase_vertex>\n \n #ifdef USE_DISPLACEMENTMAP\n \n #include <beginnormal_vertex>\n #include <morphnormal_vertex>\n #include <skinnormal_vertex>\n \n #endif\n \n #include <begin_vertex>\n \n ' + this.stringifyChunk('vertexPosition') + '\n\n #include <morphtarget_vertex>\n \n ' + this.stringifyChunk('vertexPostMorph') + '\n \n #include <skinning_vertex>\n\n ' + this.stringifyChunk('vertexPostSkinning') + '\n \n #include <displacementmap_vertex>\n #include <project_vertex>\n #include <worldpos_vertex>\n #include <clipping_planes_vertex>\n \n vWorldPosition = worldPosition.xyz;\n \n }';
|
|
};
|
|
|
|
/**
|
|
* A BufferGeometry where a 'prefab' geometry is repeated a number of times.
|
|
*
|
|
* @param {Geometry|BufferGeometry} prefab The Geometry instance to repeat.
|
|
* @param {Number} count The number of times to repeat the geometry.
|
|
* @constructor
|
|
*/
|
|
function PrefabBufferGeometry(prefab, count) {
|
|
three.BufferGeometry.call(this);
|
|
|
|
/**
|
|
* A reference to the prefab geometry used to create this instance.
|
|
* @type {Geometry|BufferGeometry}
|
|
*/
|
|
this.prefabGeometry = prefab;
|
|
this.isPrefabBufferGeometry = prefab.isBufferGeometry;
|
|
|
|
/**
|
|
* Number of prefabs.
|
|
* @type {Number}
|
|
*/
|
|
this.prefabCount = count;
|
|
|
|
/**
|
|
* Number of vertices of the prefab.
|
|
* @type {Number}
|
|
*/
|
|
if (this.isPrefabBufferGeometry) {
|
|
this.prefabVertexCount = prefab.attributes.position.count;
|
|
} else {
|
|
this.prefabVertexCount = prefab.vertices.length;
|
|
}
|
|
|
|
this.bufferIndices();
|
|
this.bufferPositions();
|
|
}
|
|
PrefabBufferGeometry.prototype = Object.create(three.BufferGeometry.prototype);
|
|
PrefabBufferGeometry.prototype.constructor = PrefabBufferGeometry;
|
|
|
|
PrefabBufferGeometry.prototype.bufferIndices = function () {
|
|
var prefabIndices = [];
|
|
var prefabIndexCount = void 0;
|
|
|
|
if (this.isPrefabBufferGeometry) {
|
|
if (this.prefabGeometry.index) {
|
|
prefabIndexCount = this.prefabGeometry.index.count;
|
|
prefabIndices = this.prefabGeometry.index.array;
|
|
} else {
|
|
prefabIndexCount = this.prefabVertexCount;
|
|
|
|
for (var i = 0; i < prefabIndexCount; i++) {
|
|
prefabIndices.push(i);
|
|
}
|
|
}
|
|
} else {
|
|
var prefabFaceCount = this.prefabGeometry.faces.length;
|
|
prefabIndexCount = prefabFaceCount * 3;
|
|
|
|
for (var _i = 0; _i < prefabFaceCount; _i++) {
|
|
var face = this.prefabGeometry.faces[_i];
|
|
prefabIndices.push(face.a, face.b, face.c);
|
|
}
|
|
}
|
|
|
|
var indexBuffer = new Uint32Array(this.prefabCount * prefabIndexCount);
|
|
|
|
this.setIndex(new three.BufferAttribute(indexBuffer, 1));
|
|
|
|
for (var _i2 = 0; _i2 < this.prefabCount; _i2++) {
|
|
for (var k = 0; k < prefabIndexCount; k++) {
|
|
indexBuffer[_i2 * prefabIndexCount + k] = prefabIndices[k] + _i2 * this.prefabVertexCount;
|
|
}
|
|
}
|
|
};
|
|
|
|
PrefabBufferGeometry.prototype.bufferPositions = function () {
|
|
var positionBuffer = this.createAttribute('position', 3).array;
|
|
|
|
if (this.isPrefabBufferGeometry) {
|
|
var positions = this.prefabGeometry.attributes.position.array;
|
|
|
|
for (var i = 0, offset = 0; i < this.prefabCount; i++) {
|
|
for (var j = 0; j < this.prefabVertexCount; j++, offset += 3) {
|
|
positionBuffer[offset] = positions[j * 3];
|
|
positionBuffer[offset + 1] = positions[j * 3 + 1];
|
|
positionBuffer[offset + 2] = positions[j * 3 + 2];
|
|
}
|
|
}
|
|
} else {
|
|
for (var _i3 = 0, _offset = 0; _i3 < this.prefabCount; _i3++) {
|
|
for (var _j = 0; _j < this.prefabVertexCount; _j++, _offset += 3) {
|
|
var prefabVertex = this.prefabGeometry.vertices[_j];
|
|
|
|
positionBuffer[_offset] = prefabVertex.x;
|
|
positionBuffer[_offset + 1] = prefabVertex.y;
|
|
positionBuffer[_offset + 2] = prefabVertex.z;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a BufferAttribute with UV coordinates.
|
|
*/
|
|
PrefabBufferGeometry.prototype.bufferUvs = function () {
|
|
var prefabUvs = [];
|
|
|
|
if (this.isPrefabBufferGeometry) {
|
|
var uv = this.prefabGeometry.attributes.uv.array;
|
|
|
|
for (var i = 0; i < this.prefabVertexCount; i++) {
|
|
prefabUvs.push(new three.Vector2(uv[i * 2], uv[i * 2 + 1]));
|
|
}
|
|
} else {
|
|
var prefabFaceCount = this.prefabGeometry.faces.length;
|
|
|
|
for (var _i4 = 0; _i4 < prefabFaceCount; _i4++) {
|
|
var face = this.prefabGeometry.faces[_i4];
|
|
var _uv = this.prefabGeometry.faceVertexUvs[0][_i4];
|
|
|
|
prefabUvs[face.a] = _uv[0];
|
|
prefabUvs[face.b] = _uv[1];
|
|
prefabUvs[face.c] = _uv[2];
|
|
}
|
|
}
|
|
|
|
var uvBuffer = this.createAttribute('uv', 2);
|
|
|
|
for (var _i5 = 0, offset = 0; _i5 < this.prefabCount; _i5++) {
|
|
for (var j = 0; j < this.prefabVertexCount; j++, offset += 2) {
|
|
var prefabUv = prefabUvs[j];
|
|
|
|
uvBuffer.array[offset] = prefabUv.x;
|
|
uvBuffer.array[offset + 1] = prefabUv.y;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a BufferAttribute on this geometry instance.
|
|
*
|
|
* @param {String} name Name of the attribute.
|
|
* @param {Number} itemSize Number of floats per vertex (typically 1, 2, 3 or 4).
|
|
* @param {function=} factory Function that will be called for each prefab upon creation. Accepts 3 arguments: data[], index and prefabCount. Calls setPrefabData.
|
|
*
|
|
* @returns {BufferAttribute}
|
|
*/
|
|
PrefabBufferGeometry.prototype.createAttribute = function (name, itemSize, factory) {
|
|
var buffer = new Float32Array(this.prefabCount * this.prefabVertexCount * itemSize);
|
|
var attribute = new three.BufferAttribute(buffer, itemSize);
|
|
|
|
this.addAttribute(name, attribute);
|
|
|
|
if (factory) {
|
|
var data = [];
|
|
|
|
for (var i = 0; i < this.prefabCount; i++) {
|
|
factory(data, i, this.prefabCount);
|
|
this.setPrefabData(attribute, i, data);
|
|
}
|
|
}
|
|
|
|
return attribute;
|
|
};
|
|
|
|
/**
|
|
* Sets data for all vertices of a prefab at a given index.
|
|
* Usually called in a loop.
|
|
*
|
|
* @param {String|BufferAttribute} attribute The attribute or attribute name where the data is to be stored.
|
|
* @param {Number} prefabIndex Index of the prefab in the buffer geometry.
|
|
* @param {Array} data Array of data. Length should be equal to item size of the attribute.
|
|
*/
|
|
PrefabBufferGeometry.prototype.setPrefabData = function (attribute, prefabIndex, data) {
|
|
attribute = typeof attribute === 'string' ? this.attributes[attribute] : attribute;
|
|
|
|
var offset = prefabIndex * this.prefabVertexCount * attribute.itemSize;
|
|
|
|
for (var i = 0; i < this.prefabVertexCount; i++) {
|
|
for (var j = 0; j < attribute.itemSize; j++) {
|
|
attribute.array[offset++] = data[j];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A BufferGeometry where a 'prefab' geometry array is repeated a number of times.
|
|
*
|
|
* @param {Array} prefabs An array with Geometry instances to repeat.
|
|
* @param {Number} repeatCount The number of times to repeat the array of Geometries.
|
|
* @constructor
|
|
*/
|
|
function MultiPrefabBufferGeometry(prefabs, repeatCount) {
|
|
three.BufferGeometry.call(this);
|
|
|
|
if (Array.isArray(prefabs)) {
|
|
this.prefabGeometries = prefabs;
|
|
} else {
|
|
this.prefabGeometries = [prefabs];
|
|
}
|
|
|
|
this.prefabGeometriesCount = this.prefabGeometries.length;
|
|
|
|
/**
|
|
* Number of prefabs.
|
|
* @type {Number}
|
|
*/
|
|
this.prefabCount = repeatCount * this.prefabGeometriesCount;
|
|
/**
|
|
* How often the prefab array is repeated.
|
|
* @type {Number}
|
|
*/
|
|
this.repeatCount = repeatCount;
|
|
|
|
/**
|
|
* Array of vertex counts per prefab.
|
|
* @type {Array}
|
|
*/
|
|
this.prefabVertexCounts = this.prefabGeometries.map(function (p) {
|
|
return p.isBufferGeometry ? p.attributes.position.count : p.vertices.length;
|
|
});
|
|
/**
|
|
* Total number of vertices for one repetition of the prefabs
|
|
* @type {number}
|
|
*/
|
|
this.repeatVertexCount = this.prefabVertexCounts.reduce(function (r, v) {
|
|
return r + v;
|
|
}, 0);
|
|
|
|
this.bufferIndices();
|
|
this.bufferPositions();
|
|
}
|
|
MultiPrefabBufferGeometry.prototype = Object.create(three.BufferGeometry.prototype);
|
|
MultiPrefabBufferGeometry.prototype.constructor = MultiPrefabBufferGeometry;
|
|
|
|
MultiPrefabBufferGeometry.prototype.bufferIndices = function () {
|
|
var repeatIndexCount = 0;
|
|
|
|
this.prefabIndices = this.prefabGeometries.map(function (geometry) {
|
|
var indices = [];
|
|
|
|
if (geometry.isBufferGeometry) {
|
|
if (geometry.index) {
|
|
indices = geometry.index.array;
|
|
} else {
|
|
for (var i = 0; i < geometry.attributes.position.count; i++) {
|
|
indices.push(i);
|
|
}
|
|
}
|
|
} else {
|
|
for (var _i = 0; _i < geometry.faces.length; _i++) {
|
|
var face = geometry.faces[_i];
|
|
indices.push(face.a, face.b, face.c);
|
|
}
|
|
}
|
|
|
|
repeatIndexCount += indices.length;
|
|
|
|
return indices;
|
|
});
|
|
|
|
var indexBuffer = new Uint32Array(repeatIndexCount * this.repeatCount);
|
|
var indexOffset = 0;
|
|
var prefabOffset = 0;
|
|
|
|
for (var i = 0; i < this.prefabCount; i++) {
|
|
var index = i % this.prefabGeometriesCount;
|
|
var indices = this.prefabIndices[index];
|
|
var vertexCount = this.prefabVertexCounts[index];
|
|
|
|
for (var j = 0; j < indices.length; j++) {
|
|
indexBuffer[indexOffset++] = indices[j] + prefabOffset;
|
|
}
|
|
|
|
prefabOffset += vertexCount;
|
|
}
|
|
|
|
this.setIndex(new three.BufferAttribute(indexBuffer, 1));
|
|
};
|
|
|
|
MultiPrefabBufferGeometry.prototype.bufferPositions = function () {
|
|
var _this = this;
|
|
|
|
var positionBuffer = this.createAttribute('position', 3).array;
|
|
|
|
var prefabPositions = this.prefabGeometries.map(function (geometry, i) {
|
|
var positions = void 0;
|
|
|
|
if (geometry.isBufferGeometry) {
|
|
positions = geometry.attributes.position.array;
|
|
} else {
|
|
|
|
var vertexCount = _this.prefabVertexCounts[i];
|
|
|
|
positions = [];
|
|
|
|
for (var j = 0, offset = 0; j < vertexCount; j++) {
|
|
var prefabVertex = geometry.vertices[j];
|
|
|
|
positions[offset++] = prefabVertex.x;
|
|
positions[offset++] = prefabVertex.y;
|
|
positions[offset++] = prefabVertex.z;
|
|
}
|
|
}
|
|
|
|
return positions;
|
|
});
|
|
|
|
for (var i = 0, offset = 0; i < this.prefabCount; i++) {
|
|
var index = i % this.prefabGeometries.length;
|
|
var vertexCount = this.prefabVertexCounts[index];
|
|
var positions = prefabPositions[index];
|
|
|
|
for (var j = 0; j < vertexCount; j++) {
|
|
positionBuffer[offset++] = positions[j * 3];
|
|
positionBuffer[offset++] = positions[j * 3 + 1];
|
|
positionBuffer[offset++] = positions[j * 3 + 2];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a BufferAttribute with UV coordinates.
|
|
*/
|
|
MultiPrefabBufferGeometry.prototype.bufferUvs = function () {
|
|
var _this2 = this;
|
|
|
|
var uvBuffer = this.createAttribute('uv', 2).array;
|
|
|
|
var prefabUvs = this.prefabGeometries.map(function (geometry, i) {
|
|
var uvs = void 0;
|
|
|
|
if (geometry.isBufferGeometry) {
|
|
if (!geometry.attributes.uv) {
|
|
console.error('No UV found in prefab geometry', geometry);
|
|
}
|
|
|
|
uvs = geometry.attributes.uv.array;
|
|
} else {
|
|
var prefabFaceCount = _this2.prefabIndices[i].length / 3;
|
|
var uvObjects = [];
|
|
|
|
for (var j = 0; j < prefabFaceCount; j++) {
|
|
var face = geometry.faces[j];
|
|
var uv = geometry.faceVertexUvs[0][j];
|
|
|
|
uvObjects[face.a] = uv[0];
|
|
uvObjects[face.b] = uv[1];
|
|
uvObjects[face.c] = uv[2];
|
|
}
|
|
|
|
uvs = [];
|
|
|
|
for (var k = 0; k < uvObjects.length; k++) {
|
|
uvs[k * 2] = uvObjects[k].x;
|
|
uvs[k * 2 + 1] = uvObjects[k].y;
|
|
}
|
|
}
|
|
|
|
return uvs;
|
|
});
|
|
|
|
for (var i = 0, offset = 0; i < this.prefabCount; i++) {
|
|
|
|
var index = i % this.prefabGeometries.length;
|
|
var vertexCount = this.prefabVertexCounts[index];
|
|
var uvs = prefabUvs[index];
|
|
|
|
for (var j = 0; j < vertexCount; j++) {
|
|
uvBuffer[offset++] = uvs[j * 2];
|
|
uvBuffer[offset++] = uvs[j * 2 + 1];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a BufferAttribute on this geometry instance.
|
|
*
|
|
* @param {String} name Name of the attribute.
|
|
* @param {Number} itemSize Number of floats per vertex (typically 1, 2, 3 or 4).
|
|
* @param {function=} factory Function that will be called for each prefab upon creation. Accepts 3 arguments: data[], index and prefabCount. Calls setPrefabData.
|
|
*
|
|
* @returns {BufferAttribute}
|
|
*/
|
|
MultiPrefabBufferGeometry.prototype.createAttribute = function (name, itemSize, factory) {
|
|
var buffer = new Float32Array(this.repeatCount * this.repeatVertexCount * itemSize);
|
|
var attribute = new three.BufferAttribute(buffer, itemSize);
|
|
|
|
this.addAttribute(name, attribute);
|
|
|
|
if (factory) {
|
|
var data = [];
|
|
|
|
for (var i = 0; i < this.prefabCount; i++) {
|
|
factory(data, i, this.prefabCount);
|
|
this.setPrefabData(attribute, i, data);
|
|
}
|
|
}
|
|
|
|
return attribute;
|
|
};
|
|
|
|
/**
|
|
* Sets data for all vertices of a prefab at a given index.
|
|
* Usually called in a loop.
|
|
*
|
|
* @param {String|BufferAttribute} attribute The attribute or attribute name where the data is to be stored.
|
|
* @param {Number} prefabIndex Index of the prefab in the buffer geometry.
|
|
* @param {Array} data Array of data. Length should be equal to item size of the attribute.
|
|
*/
|
|
MultiPrefabBufferGeometry.prototype.setPrefabData = function (attribute, prefabIndex, data) {
|
|
attribute = typeof attribute === 'string' ? this.attributes[attribute] : attribute;
|
|
|
|
var prefabGeometryIndex = prefabIndex % this.prefabGeometriesCount;
|
|
var prefabGeometryVertexCount = this.prefabVertexCounts[prefabGeometryIndex];
|
|
var whole = (prefabIndex / this.prefabGeometriesCount | 0) * this.prefabGeometriesCount;
|
|
var wholeOffset = whole * this.repeatVertexCount;
|
|
var part = prefabIndex - whole;
|
|
var partOffset = 0;
|
|
var i = 0;
|
|
|
|
while (i < part) {
|
|
partOffset += this.prefabVertexCounts[i++];
|
|
}
|
|
|
|
var offset = (wholeOffset + partOffset) * attribute.itemSize;
|
|
|
|
for (var _i2 = 0; _i2 < prefabGeometryVertexCount; _i2++) {
|
|
for (var j = 0; j < attribute.itemSize; j++) {
|
|
attribute.array[offset++] = data[j];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Collection of utility functions.
|
|
* @namespace
|
|
*/
|
|
var Utils = {
|
|
/**
|
|
* Duplicates vertices so each face becomes separate.
|
|
* Same as THREE.ExplodeModifier.
|
|
*
|
|
* @param {THREE.Geometry} geometry Geometry instance to modify.
|
|
*/
|
|
separateFaces: function separateFaces(geometry) {
|
|
var vertices = [];
|
|
|
|
for (var i = 0, il = geometry.faces.length; i < il; i++) {
|
|
var n = vertices.length;
|
|
var face = geometry.faces[i];
|
|
|
|
var a = face.a;
|
|
var b = face.b;
|
|
var c = face.c;
|
|
|
|
var va = geometry.vertices[a];
|
|
var vb = geometry.vertices[b];
|
|
var vc = geometry.vertices[c];
|
|
|
|
vertices.push(va.clone());
|
|
vertices.push(vb.clone());
|
|
vertices.push(vc.clone());
|
|
|
|
face.a = n;
|
|
face.b = n + 1;
|
|
face.c = n + 2;
|
|
}
|
|
|
|
geometry.vertices = vertices;
|
|
},
|
|
|
|
/**
|
|
* Compute the centroid (center) of a THREE.Face3.
|
|
*
|
|
* @param {THREE.Geometry} geometry Geometry instance the face is in.
|
|
* @param {THREE.Face3} face Face object from the THREE.Geometry.faces array
|
|
* @param {THREE.Vector3=} v Optional vector to store result in.
|
|
* @returns {THREE.Vector3}
|
|
*/
|
|
computeCentroid: function computeCentroid(geometry, face, v) {
|
|
var a = geometry.vertices[face.a];
|
|
var b = geometry.vertices[face.b];
|
|
var c = geometry.vertices[face.c];
|
|
|
|
v = v || new three.Vector3();
|
|
|
|
v.x = (a.x + b.x + c.x) / 3;
|
|
v.y = (a.y + b.y + c.y) / 3;
|
|
v.z = (a.z + b.z + c.z) / 3;
|
|
|
|
return v;
|
|
},
|
|
|
|
/**
|
|
* Get a random vector between box.min and box.max.
|
|
*
|
|
* @param {THREE.Box3} box THREE.Box3 instance.
|
|
* @param {THREE.Vector3=} v Optional vector to store result in.
|
|
* @returns {THREE.Vector3}
|
|
*/
|
|
randomInBox: function randomInBox(box, v) {
|
|
v = v || new three.Vector3();
|
|
|
|
v.x = three.Math.randFloat(box.min.x, box.max.x);
|
|
v.y = three.Math.randFloat(box.min.y, box.max.y);
|
|
v.z = three.Math.randFloat(box.min.z, box.max.z);
|
|
|
|
return v;
|
|
},
|
|
|
|
/**
|
|
* Get a random axis for quaternion rotation.
|
|
*
|
|
* @param {THREE.Vector3=} v Option vector to store result in.
|
|
* @returns {THREE.Vector3}
|
|
*/
|
|
randomAxis: function randomAxis(v) {
|
|
v = v || new three.Vector3();
|
|
|
|
v.x = three.Math.randFloatSpread(2.0);
|
|
v.y = three.Math.randFloatSpread(2.0);
|
|
v.z = three.Math.randFloatSpread(2.0);
|
|
v.normalize();
|
|
|
|
return v;
|
|
},
|
|
|
|
/**
|
|
* Create a THREE.BAS.DepthAnimationMaterial for shadows from a THREE.SpotLight or THREE.DirectionalLight by copying relevant shader chunks.
|
|
* Uniform values must be manually synced between the source material and the depth material.
|
|
*
|
|
* @see {@link http://three-bas-examples.surge.sh/examples/shadows/}
|
|
*
|
|
* @param {THREE.BAS.BaseAnimationMaterial} sourceMaterial Instance to get the shader chunks from.
|
|
* @returns {THREE.BAS.DepthAnimationMaterial}
|
|
*/
|
|
createDepthAnimationMaterial: function createDepthAnimationMaterial(sourceMaterial) {
|
|
return new DepthAnimationMaterial({
|
|
uniforms: sourceMaterial.uniforms,
|
|
defines: sourceMaterial.defines,
|
|
vertexFunctions: sourceMaterial.vertexFunctions,
|
|
vertexParameters: sourceMaterial.vertexParameters,
|
|
vertexInit: sourceMaterial.vertexInit,
|
|
vertexPosition: sourceMaterial.vertexPosition
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Create a THREE.BAS.DistanceAnimationMaterial for shadows from a THREE.PointLight by copying relevant shader chunks.
|
|
* Uniform values must be manually synced between the source material and the distance material.
|
|
*
|
|
* @see {@link http://three-bas-examples.surge.sh/examples/shadows/}
|
|
*
|
|
* @param {THREE.BAS.BaseAnimationMaterial} sourceMaterial Instance to get the shader chunks from.
|
|
* @returns {THREE.BAS.DistanceAnimationMaterial}
|
|
*/
|
|
createDistanceAnimationMaterial: function createDistanceAnimationMaterial(sourceMaterial) {
|
|
return new DistanceAnimationMaterial({
|
|
uniforms: sourceMaterial.uniforms,
|
|
defines: sourceMaterial.defines,
|
|
vertexFunctions: sourceMaterial.vertexFunctions,
|
|
vertexParameters: sourceMaterial.vertexParameters,
|
|
vertexInit: sourceMaterial.vertexInit,
|
|
vertexPosition: sourceMaterial.vertexPosition
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A THREE.BufferGeometry for animating individual faces of a THREE.Geometry.
|
|
*
|
|
* @param {THREE.Geometry} model The THREE.Geometry to base this geometry on.
|
|
* @param {Object=} options
|
|
* @param {Boolean=} options.computeCentroids If true, a centroids will be computed for each face and stored in THREE.BAS.ModelBufferGeometry.centroids.
|
|
* @param {Boolean=} options.localizeFaces If true, the positions for each face will be stored relative to the centroid. This is useful if you want to rotate or scale faces around their center.
|
|
* @constructor
|
|
*/
|
|
function ModelBufferGeometry(model, options) {
|
|
three.BufferGeometry.call(this);
|
|
|
|
/**
|
|
* A reference to the geometry used to create this instance.
|
|
* @type {THREE.Geometry}
|
|
*/
|
|
this.modelGeometry = model;
|
|
|
|
/**
|
|
* Number of faces of the model.
|
|
* @type {Number}
|
|
*/
|
|
this.faceCount = this.modelGeometry.faces.length;
|
|
|
|
/**
|
|
* Number of vertices of the model.
|
|
* @type {Number}
|
|
*/
|
|
this.vertexCount = this.modelGeometry.vertices.length;
|
|
|
|
options = options || {};
|
|
options.computeCentroids && this.computeCentroids();
|
|
|
|
this.bufferIndices();
|
|
this.bufferPositions(options.localizeFaces);
|
|
}
|
|
ModelBufferGeometry.prototype = Object.create(three.BufferGeometry.prototype);
|
|
ModelBufferGeometry.prototype.constructor = ModelBufferGeometry;
|
|
|
|
/**
|
|
* Computes a centroid for each face and stores it in THREE.BAS.ModelBufferGeometry.centroids.
|
|
*/
|
|
ModelBufferGeometry.prototype.computeCentroids = function () {
|
|
/**
|
|
* An array of centroids corresponding to the faces of the model.
|
|
*
|
|
* @type {Array}
|
|
*/
|
|
this.centroids = [];
|
|
|
|
for (var i = 0; i < this.faceCount; i++) {
|
|
this.centroids[i] = Utils.computeCentroid(this.modelGeometry, this.modelGeometry.faces[i]);
|
|
}
|
|
};
|
|
|
|
ModelBufferGeometry.prototype.bufferIndices = function () {
|
|
var indexBuffer = new Uint32Array(this.faceCount * 3);
|
|
|
|
this.setIndex(new three.BufferAttribute(indexBuffer, 1));
|
|
|
|
for (var i = 0, offset = 0; i < this.faceCount; i++, offset += 3) {
|
|
var face = this.modelGeometry.faces[i];
|
|
|
|
indexBuffer[offset] = face.a;
|
|
indexBuffer[offset + 1] = face.b;
|
|
indexBuffer[offset + 2] = face.c;
|
|
}
|
|
};
|
|
|
|
ModelBufferGeometry.prototype.bufferPositions = function (localizeFaces) {
|
|
var positionBuffer = this.createAttribute('position', 3).array;
|
|
var i = void 0,
|
|
offset = void 0;
|
|
|
|
if (localizeFaces === true) {
|
|
for (i = 0; i < this.faceCount; i++) {
|
|
var face = this.modelGeometry.faces[i];
|
|
var centroid = this.centroids ? this.centroids[i] : Utils.computeCentroid(this.modelGeometry, face);
|
|
|
|
var a = this.modelGeometry.vertices[face.a];
|
|
var b = this.modelGeometry.vertices[face.b];
|
|
var c = this.modelGeometry.vertices[face.c];
|
|
|
|
positionBuffer[face.a * 3] = a.x - centroid.x;
|
|
positionBuffer[face.a * 3 + 1] = a.y - centroid.y;
|
|
positionBuffer[face.a * 3 + 2] = a.z - centroid.z;
|
|
|
|
positionBuffer[face.b * 3] = b.x - centroid.x;
|
|
positionBuffer[face.b * 3 + 1] = b.y - centroid.y;
|
|
positionBuffer[face.b * 3 + 2] = b.z - centroid.z;
|
|
|
|
positionBuffer[face.c * 3] = c.x - centroid.x;
|
|
positionBuffer[face.c * 3 + 1] = c.y - centroid.y;
|
|
positionBuffer[face.c * 3 + 2] = c.z - centroid.z;
|
|
}
|
|
} else {
|
|
for (i = 0, offset = 0; i < this.vertexCount; i++, offset += 3) {
|
|
var vertex = this.modelGeometry.vertices[i];
|
|
|
|
positionBuffer[offset] = vertex.x;
|
|
positionBuffer[offset + 1] = vertex.y;
|
|
positionBuffer[offset + 2] = vertex.z;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a THREE.BufferAttribute with UV coordinates.
|
|
*/
|
|
ModelBufferGeometry.prototype.bufferUVs = function () {
|
|
var uvBuffer = this.createAttribute('uv', 2).array;
|
|
|
|
for (var i = 0; i < this.faceCount; i++) {
|
|
|
|
var face = this.modelGeometry.faces[i];
|
|
var uv = void 0;
|
|
|
|
uv = this.modelGeometry.faceVertexUvs[0][i][0];
|
|
uvBuffer[face.a * 2] = uv.x;
|
|
uvBuffer[face.a * 2 + 1] = uv.y;
|
|
|
|
uv = this.modelGeometry.faceVertexUvs[0][i][1];
|
|
uvBuffer[face.b * 2] = uv.x;
|
|
uvBuffer[face.b * 2 + 1] = uv.y;
|
|
|
|
uv = this.modelGeometry.faceVertexUvs[0][i][2];
|
|
uvBuffer[face.c * 2] = uv.x;
|
|
uvBuffer[face.c * 2 + 1] = uv.y;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates two THREE.BufferAttributes: skinIndex and skinWeight. Both are required for skinning.
|
|
*/
|
|
ModelBufferGeometry.prototype.bufferSkinning = function () {
|
|
var skinIndexBuffer = this.createAttribute('skinIndex', 4).array;
|
|
var skinWeightBuffer = this.createAttribute('skinWeight', 4).array;
|
|
|
|
for (var i = 0; i < this.vertexCount; i++) {
|
|
var skinIndex = this.modelGeometry.skinIndices[i];
|
|
var skinWeight = this.modelGeometry.skinWeights[i];
|
|
|
|
skinIndexBuffer[i * 4] = skinIndex.x;
|
|
skinIndexBuffer[i * 4 + 1] = skinIndex.y;
|
|
skinIndexBuffer[i * 4 + 2] = skinIndex.z;
|
|
skinIndexBuffer[i * 4 + 3] = skinIndex.w;
|
|
|
|
skinWeightBuffer[i * 4] = skinWeight.x;
|
|
skinWeightBuffer[i * 4 + 1] = skinWeight.y;
|
|
skinWeightBuffer[i * 4 + 2] = skinWeight.z;
|
|
skinWeightBuffer[i * 4 + 3] = skinWeight.w;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a THREE.BufferAttribute on this geometry instance.
|
|
*
|
|
* @param {String} name Name of the attribute.
|
|
* @param {int} itemSize Number of floats per vertex (typically 1, 2, 3 or 4).
|
|
* @param {function=} factory Function that will be called for each face upon creation. Accepts 3 arguments: data[], index and faceCount. Calls setFaceData.
|
|
*
|
|
* @returns {BufferAttribute}
|
|
*/
|
|
ModelBufferGeometry.prototype.createAttribute = function (name, itemSize, factory) {
|
|
var buffer = new Float32Array(this.vertexCount * itemSize);
|
|
var attribute = new three.BufferAttribute(buffer, itemSize);
|
|
|
|
this.addAttribute(name, attribute);
|
|
|
|
if (factory) {
|
|
var data = [];
|
|
|
|
for (var i = 0; i < this.faceCount; i++) {
|
|
factory(data, i, this.faceCount);
|
|
this.setFaceData(attribute, i, data);
|
|
}
|
|
}
|
|
|
|
return attribute;
|
|
};
|
|
|
|
/**
|
|
* Sets data for all vertices of a face at a given index.
|
|
* Usually called in a loop.
|
|
*
|
|
* @param {String|THREE.BufferAttribute} attribute The attribute or attribute name where the data is to be stored.
|
|
* @param {int} faceIndex Index of the face in the buffer geometry.
|
|
* @param {Array} data Array of data. Length should be equal to item size of the attribute.
|
|
*/
|
|
ModelBufferGeometry.prototype.setFaceData = function (attribute, faceIndex, data) {
|
|
attribute = typeof attribute === 'string' ? this.attributes[attribute] : attribute;
|
|
|
|
var offset = faceIndex * 3 * attribute.itemSize;
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
for (var j = 0; j < attribute.itemSize; j++) {
|
|
attribute.array[offset++] = data[j];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A THREE.BufferGeometry consists of points.
|
|
* @param {Number} count The number of points.
|
|
* @constructor
|
|
*/
|
|
function PointBufferGeometry(count) {
|
|
three.BufferGeometry.call(this);
|
|
|
|
/**
|
|
* Number of points.
|
|
* @type {Number}
|
|
*/
|
|
this.pointCount = count;
|
|
|
|
this.bufferPositions();
|
|
}
|
|
PointBufferGeometry.prototype = Object.create(three.BufferGeometry.prototype);
|
|
PointBufferGeometry.prototype.constructor = PointBufferGeometry;
|
|
|
|
PointBufferGeometry.prototype.bufferPositions = function () {
|
|
this.createAttribute('position', 3);
|
|
};
|
|
|
|
/**
|
|
* Creates a THREE.BufferAttribute on this geometry instance.
|
|
*
|
|
* @param {String} name Name of the attribute.
|
|
* @param {Number} itemSize Number of floats per vertex (typically 1, 2, 3 or 4).
|
|
* @param {function=} factory Function that will be called for each point upon creation. Accepts 3 arguments: data[], index and prefabCount. Calls setPointData.
|
|
*
|
|
* @returns {THREE.BufferAttribute}
|
|
*/
|
|
PointBufferGeometry.prototype.createAttribute = function (name, itemSize, factory) {
|
|
var buffer = new Float32Array(this.pointCount * itemSize);
|
|
var attribute = new three.BufferAttribute(buffer, itemSize);
|
|
|
|
this.addAttribute(name, attribute);
|
|
|
|
if (factory) {
|
|
var data = [];
|
|
for (var i = 0; i < this.pointCount; i++) {
|
|
factory(data, i, this.pointCount);
|
|
this.setPointData(attribute, i, data);
|
|
}
|
|
}
|
|
|
|
return attribute;
|
|
};
|
|
|
|
PointBufferGeometry.prototype.setPointData = function (attribute, pointIndex, data) {
|
|
attribute = typeof attribute === 'string' ? this.attributes[attribute] : attribute;
|
|
|
|
var offset = pointIndex * attribute.itemSize;
|
|
|
|
for (var j = 0; j < attribute.itemSize; j++) {
|
|
attribute.array[offset++] = data[j];
|
|
}
|
|
};
|
|
|
|
var catmull_rom_spline = "vec4 catmullRomSpline(vec4 p0, vec4 p1, vec4 p2, vec4 p3, float t, vec2 c) {\r\n vec4 v0 = (p2 - p0) * c.x;\r\n vec4 v1 = (p3 - p1) * c.y;\r\n float t2 = t * t;\r\n float t3 = t * t * t;\r\n\r\n return vec4((2.0 * p1 - 2.0 * p2 + v0 + v1) * t3 + (-3.0 * p1 + 3.0 * p2 - 2.0 * v0 - v1) * t2 + v0 * t + p1);\r\n}\r\nvec4 catmullRomSpline(vec4 p0, vec4 p1, vec4 p2, vec4 p3, float t) {\r\n return catmullRomSpline(p0, p1, p2, p3, t, vec2(0.5, 0.5));\r\n}\r\n\r\nvec3 catmullRomSpline(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t, vec2 c) {\r\n vec3 v0 = (p2 - p0) * c.x;\r\n vec3 v1 = (p3 - p1) * c.y;\r\n float t2 = t * t;\r\n float t3 = t * t * t;\r\n\r\n return vec3((2.0 * p1 - 2.0 * p2 + v0 + v1) * t3 + (-3.0 * p1 + 3.0 * p2 - 2.0 * v0 - v1) * t2 + v0 * t + p1);\r\n}\r\nvec3 catmullRomSpline(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t) {\r\n return catmullRomSpline(p0, p1, p2, p3, t, vec2(0.5, 0.5));\r\n}\r\n\r\nvec2 catmullRomSpline(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t, vec2 c) {\r\n vec2 v0 = (p2 - p0) * c.x;\r\n vec2 v1 = (p3 - p1) * c.y;\r\n float t2 = t * t;\r\n float t3 = t * t * t;\r\n\r\n return vec2((2.0 * p1 - 2.0 * p2 + v0 + v1) * t3 + (-3.0 * p1 + 3.0 * p2 - 2.0 * v0 - v1) * t2 + v0 * t + p1);\r\n}\r\nvec2 catmullRomSpline(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t) {\r\n return catmullRomSpline(p0, p1, p2, p3, t, vec2(0.5, 0.5));\r\n}\r\n\r\nfloat catmullRomSpline(float p0, float p1, float p2, float p3, float t, vec2 c) {\r\n float v0 = (p2 - p0) * c.x;\r\n float v1 = (p3 - p1) * c.y;\r\n float t2 = t * t;\r\n float t3 = t * t * t;\r\n\r\n return float((2.0 * p1 - 2.0 * p2 + v0 + v1) * t3 + (-3.0 * p1 + 3.0 * p2 - 2.0 * v0 - v1) * t2 + v0 * t + p1);\r\n}\r\nfloat catmullRomSpline(float p0, float p1, float p2, float p3, float t) {\r\n return catmullRomSpline(p0, p1, p2, p3, t, vec2(0.5, 0.5));\r\n}\r\n\r\nivec4 getCatmullRomSplineIndices(float l, float p) {\r\n float index = floor(p);\r\n int i0 = int(max(0.0, index - 1.0));\r\n int i1 = int(index);\r\n int i2 = int(min(index + 1.0, l));\r\n int i3 = int(min(index + 2.0, l));\r\n\r\n return ivec4(i0, i1, i2, i3);\r\n}\r\n\r\nivec4 getCatmullRomSplineIndicesClosed(float l, float p) {\r\n float index = floor(p);\r\n int i0 = int(index == 0.0 ? l : index - 1.0);\r\n int i1 = int(index);\r\n int i2 = int(mod(index + 1.0, l));\r\n int i3 = int(mod(index + 2.0, l));\r\n\r\n return ivec4(i0, i1, i2, i3);\r\n}\r\n";
|
|
|
|
var cubic_bezier = "vec3 cubicBezier(vec3 p0, vec3 c0, vec3 c1, vec3 p1, float t) {\r\n float tn = 1.0 - t;\r\n\r\n return tn * tn * tn * p0 + 3.0 * tn * tn * t * c0 + 3.0 * tn * t * t * c1 + t * t * t * p1;\r\n}\r\n\r\nvec2 cubicBezier(vec2 p0, vec2 c0, vec2 c1, vec2 p1, float t) {\r\n float tn = 1.0 - t;\r\n\r\n return tn * tn * tn * p0 + 3.0 * tn * tn * t * c0 + 3.0 * tn * t * t * c1 + t * t * t * p1;\r\n}\r\n";
|
|
|
|
var ease_back_in = "float easeBackIn(float p, float amplitude) {\r\n return p * p * ((amplitude + 1.0) * p - amplitude);\r\n}\r\n\r\nfloat easeBackIn(float p) {\r\n return easeBackIn(p, 1.70158);\r\n}\r\n\r\nfloat easeBackIn(float t, float b, float c, float d, float amplitude) {\r\n return b + easeBackIn(t / d, amplitude) * c;\r\n}\r\n\r\nfloat easeBackIn(float t, float b, float c, float d) {\r\n return b + easeBackIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_back_in_out = "float easeBackInOut(float p, float amplitude) {\r\n amplitude *= 1.525;\r\n\r\n return ((p *= 2.0) < 1.0) ? 0.5 * p * p * ((amplitude + 1.0) * p - amplitude) : 0.5 * ((p -= 2.0) * p * ((amplitude + 1.0) * p + amplitude) + 2.0);\r\n}\r\n\r\nfloat easeBackInOut(float p) {\r\n return easeBackInOut(p, 1.70158);\r\n}\r\n\r\nfloat easeBackInOut(float t, float b, float c, float d, float amplitude) {\r\n return b + easeBackInOut(t / d, amplitude) * c;\r\n}\r\n\r\nfloat easeBackInOut(float t, float b, float c, float d) {\r\n return b + easeBackInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_back_out = "float easeBackOut(float p, float amplitude) {\r\n return ((p = p - 1.0) * p * ((amplitude + 1.0) * p + amplitude) + 1.0);\r\n}\r\n\r\nfloat easeBackOut(float p) {\r\n return easeBackOut(p, 1.70158);\r\n}\r\n\r\nfloat easeBackOut(float t, float b, float c, float d, float amplitude) {\r\n return b + easeBackOut(t / d, amplitude) * c;\r\n}\r\n\r\nfloat easeBackOut(float t, float b, float c, float d) {\r\n return b + easeBackOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_bezier = "float easeBezier(float p, vec4 curve) {\r\n float ip = 1.0 - p;\r\n return (3.0 * ip * ip * p * curve.xy + 3.0 * ip * p * p * curve.zw + p * p * p).y;\r\n}\r\n\r\nfloat easeBezier(float t, float b, float c, float d, vec4 curve) {\r\n return b + easeBezier(t / d, curve) * c;\r\n}\r\n";
|
|
|
|
var ease_bounce_in = "float easeBounceIn(float p) {\r\n if ((p = 1.0 - p) < 1.0 / 2.75) {\r\n return 1.0 - (7.5625 * p * p);\r\n } else if (p < 2.0 / 2.75) {\r\n return 1.0 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);\r\n } else if (p < 2.5 / 2.75) {\r\n return 1.0 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);\r\n }\r\n return 1.0 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);\r\n}\r\n\r\nfloat easeBounceIn(float t, float b, float c, float d) {\r\n return b + easeBounceIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_bounce_in_out = "float easeBounceInOut(float p) {\r\n bool invert = (p < 0.5);\r\n\r\n p = invert ? (1.0 - (p * 2.0)) : ((p * 2.0) - 1.0);\r\n\r\n if (p < 1.0 / 2.75) {\r\n p = 7.5625 * p * p;\r\n } else if (p < 2.0 / 2.75) {\r\n p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r\n } else if (p < 2.5 / 2.75) {\r\n p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r\n } else {\r\n p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r\n }\r\n\r\n return invert ? (1.0 - p) * 0.5 : p * 0.5 + 0.5;\r\n}\r\n\r\nfloat easeBounceInOut(float t, float b, float c, float d) {\r\n return b + easeBounceInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_bounce_out = "float easeBounceOut(float p) {\r\n if (p < 1.0 / 2.75) {\r\n return 7.5625 * p * p;\r\n } else if (p < 2.0 / 2.75) {\r\n return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;\r\n } else if (p < 2.5 / 2.75) {\r\n return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;\r\n }\r\n return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;\r\n}\r\n\r\nfloat easeBounceOut(float t, float b, float c, float d) {\r\n return b + easeBounceOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_circ_in = "float easeCircIn(float p) {\r\n return -(sqrt(1.0 - p * p) - 1.0);\r\n}\r\n\r\nfloat easeCircIn(float t, float b, float c, float d) {\r\n return b + easeCircIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_circ_in_out = "float easeCircInOut(float p) {\r\n return ((p *= 2.0) < 1.0) ? -0.5 * (sqrt(1.0 - p * p) - 1.0) : 0.5 * (sqrt(1.0 - (p -= 2.0) * p) + 1.0);\r\n}\r\n\r\nfloat easeCircInOut(float t, float b, float c, float d) {\r\n return b + easeCircInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_circ_out = "float easeCircOut(float p) {\r\n return sqrt(1.0 - (p = p - 1.0) * p);\r\n}\r\n\r\nfloat easeCircOut(float t, float b, float c, float d) {\r\n return b + easeCircOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_cubic_in = "float easeCubicIn(float t) {\r\n return t * t * t;\r\n}\r\n\r\nfloat easeCubicIn(float t, float b, float c, float d) {\r\n return b + easeCubicIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_cubic_in_out = "float easeCubicInOut(float t) {\r\n return (t /= 0.5) < 1.0 ? 0.5 * t * t * t : 0.5 * ((t-=2.0) * t * t + 2.0);\r\n}\r\n\r\nfloat easeCubicInOut(float t, float b, float c, float d) {\r\n return b + easeCubicInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_cubic_out = "float easeCubicOut(float t) {\r\n float f = t - 1.0;\r\n return f * f * f + 1.0;\r\n}\r\n\r\nfloat easeCubicOut(float t, float b, float c, float d) {\r\n return b + easeCubicOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_elastic_in = "float easeElasticIn(float p, float amplitude, float period) {\r\n float p1 = max(amplitude, 1.0);\r\n float p2 = period / min(amplitude, 1.0);\r\n float p3 = p2 / PI2 * (asin(1.0 / p1));\r\n\r\n return -(p1 * pow(2.0, 10.0 * (p -= 1.0)) * sin((p - p3) * PI2 / p2));\r\n}\r\n\r\nfloat easeElasticIn(float p) {\r\n return easeElasticIn(p, 1.0, 0.3);\r\n}\r\n\r\nfloat easeElasticIn(float t, float b, float c, float d, float amplitude, float period) {\r\n return b + easeElasticIn(t / d, amplitude, period) * c;\r\n}\r\n\r\nfloat easeElasticIn(float t, float b, float c, float d) {\r\n return b + easeElasticIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_elastic_in_out = "float easeElasticInOut(float p, float amplitude, float period) {\r\n float p1 = max(amplitude, 1.0);\r\n float p2 = period / min(amplitude, 1.0);\r\n float p3 = p2 / PI2 * (asin(1.0 / p1));\r\n\r\n return ((p *= 2.0) < 1.0) ? -0.5 * (p1 * pow(2.0, 10.0 * (p -= 1.0)) * sin((p - p3) * PI2 / p2)) : p1 * pow(2.0, -10.0 * (p -= 1.0)) * sin((p - p3) * PI2 / p2) * 0.5 + 1.0;\r\n}\r\n\r\nfloat easeElasticInOut(float p) {\r\n return easeElasticInOut(p, 1.0, 0.3);\r\n}\r\n\r\nfloat easeElasticInOut(float t, float b, float c, float d, float amplitude, float period) {\r\n return b + easeElasticInOut(t / d, amplitude, period) * c;\r\n}\r\n\r\nfloat easeElasticInOut(float t, float b, float c, float d) {\r\n return b + easeElasticInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_elastic_out = "float easeElasticOut(float p, float amplitude, float period) {\r\n float p1 = max(amplitude, 1.0);\r\n float p2 = period / min(amplitude, 1.0);\r\n float p3 = p2 / PI2 * (asin(1.0 / p1));\r\n\r\n return p1 * pow(2.0, -10.0 * p) * sin((p - p3) * PI2 / p2) + 1.0;\r\n}\r\n\r\nfloat easeElasticOut(float p) {\r\n return easeElasticOut(p, 1.0, 0.3);\r\n}\r\n\r\nfloat easeElasticOut(float t, float b, float c, float d, float amplitude, float period) {\r\n return b + easeElasticOut(t / d, amplitude, period) * c;\r\n}\r\n\r\nfloat easeElasticOut(float t, float b, float c, float d) {\r\n return b + easeElasticOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_expo_in = "float easeExpoIn(float p) {\r\n return pow(2.0, 10.0 * (p - 1.0));\r\n}\r\n\r\nfloat easeExpoIn(float t, float b, float c, float d) {\r\n return b + easeExpoIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_expo_in_out = "float easeExpoInOut(float p) {\r\n return ((p *= 2.0) < 1.0) ? 0.5 * pow(2.0, 10.0 * (p - 1.0)) : 0.5 * (2.0 - pow(2.0, -10.0 * (p - 1.0)));\r\n}\r\n\r\nfloat easeExpoInOut(float t, float b, float c, float d) {\r\n return b + easeExpoInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_expo_out = "float easeExpoOut(float p) {\r\n return 1.0 - pow(2.0, -10.0 * p);\r\n}\r\n\r\nfloat easeExpoOut(float t, float b, float c, float d) {\r\n return b + easeExpoOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quad_in = "float easeQuadIn(float t) {\r\n return t * t;\r\n}\r\n\r\nfloat easeQuadIn(float t, float b, float c, float d) {\r\n return b + easeQuadIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quad_in_out = "float easeQuadInOut(float t) {\r\n float p = 2.0 * t * t;\r\n return t < 0.5 ? p : -p + (4.0 * t) - 1.0;\r\n}\r\n\r\nfloat easeQuadInOut(float t, float b, float c, float d) {\r\n return b + easeQuadInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quad_out = "float easeQuadOut(float t) {\r\n return -t * (t - 2.0);\r\n}\r\n\r\nfloat easeQuadOut(float t, float b, float c, float d) {\r\n return b + easeQuadOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quart_in = "float easeQuartIn(float t) {\r\n return t * t * t * t;\r\n}\r\n\r\nfloat easeQuartIn(float t, float b, float c, float d) {\r\n return b + easeQuartIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quart_in_out = "float easeQuartInOut(float t) {\r\n return t < 0.5 ? 8.0 * pow(t, 4.0) : -8.0 * pow(t - 1.0, 4.0) + 1.0;\r\n}\r\n\r\nfloat easeQuartInOut(float t, float b, float c, float d) {\r\n return b + easeQuartInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quart_out = "float easeQuartOut(float t) {\r\n return 1.0 - pow(1.0 - t, 4.0);\r\n}\r\n\r\nfloat easeQuartOut(float t, float b, float c, float d) {\r\n return b + easeQuartOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quint_in = "float easeQuintIn(float t) {\r\n return pow(t, 5.0);\r\n}\r\n\r\nfloat easeQuintIn(float t, float b, float c, float d) {\r\n return b + easeQuintIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quint_in_out = "float easeQuintInOut(float t) {\r\n return (t /= 0.5) < 1.0 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2.0) * t * t * t * t + 2.0);\r\n}\r\n\r\nfloat easeQuintInOut(float t, float b, float c, float d) {\r\n return b + easeQuintInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_quint_out = "float easeQuintOut(float t) {\r\n return (t -= 1.0) * t * t * t * t + 1.0;\r\n}\r\n\r\nfloat easeQuintOut(float t, float b, float c, float d) {\r\n return b + easeQuintOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_sine_in = "float easeSineIn(float p) {\r\n return -cos(p * 1.57079632679) + 1.0;\r\n}\r\n\r\nfloat easeSineIn(float t, float b, float c, float d) {\r\n return b + easeSineIn(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_sine_in_out = "float easeSineInOut(float p) {\r\n return -0.5 * (cos(PI * p) - 1.0);\r\n}\r\n\r\nfloat easeSineInOut(float t, float b, float c, float d) {\r\n return b + easeSineInOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var ease_sine_out = "float easeSineOut(float p) {\r\n return sin(p * 1.57079632679);\r\n}\r\n\r\nfloat easeSineOut(float t, float b, float c, float d) {\r\n return b + easeSineOut(t / d) * c;\r\n}\r\n";
|
|
|
|
var quadratic_bezier = "vec3 quadraticBezier(vec3 p0, vec3 c0, vec3 p1, float t) {\r\n float tn = 1.0 - t;\r\n\r\n return tn * tn * p0 + 2.0 * tn * t * c0 + t * t * p1;\r\n}\r\n\r\nvec2 quadraticBezier(vec2 p0, vec2 c0, vec2 p1, float t) {\r\n float tn = 1.0 - t;\r\n\r\n return tn * tn * p0 + 2.0 * tn * t * c0 + t * t * p1;\r\n}";
|
|
|
|
var quaternion_rotation = "vec3 rotateVector(vec4 q, vec3 v) {\r\n return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);\r\n}\r\n\r\nvec4 quatFromAxisAngle(vec3 axis, float angle) {\r\n float halfAngle = angle * 0.5;\r\n return vec4(axis.xyz * sin(halfAngle), cos(halfAngle));\r\n}\r\n";
|
|
|
|
var quaternion_slerp = "vec4 quatSlerp(vec4 q0, vec4 q1, float t) {\r\n float s = 1.0 - t;\r\n float c = dot(q0, q1);\r\n float dir = -1.0; //c >= 0.0 ? 1.0 : -1.0;\r\n float sqrSn = 1.0 - c * c;\r\n\r\n if (sqrSn > 2.220446049250313e-16) {\r\n float sn = sqrt(sqrSn);\r\n float len = atan(sn, c * dir);\r\n\r\n s = sin(s * len) / sn;\r\n t = sin(t * len) / sn;\r\n }\r\n\r\n float tDir = t * dir;\r\n\r\n return normalize(q0 * s + q1 * tDir);\r\n}\r\n";
|
|
|
|
// generated by scripts/build_shader_chunks.js
|
|
|
|
var ShaderChunk = {
|
|
catmull_rom_spline: catmull_rom_spline,
|
|
cubic_bezier: cubic_bezier,
|
|
ease_back_in: ease_back_in,
|
|
ease_back_in_out: ease_back_in_out,
|
|
ease_back_out: ease_back_out,
|
|
ease_bezier: ease_bezier,
|
|
ease_bounce_in: ease_bounce_in,
|
|
ease_bounce_in_out: ease_bounce_in_out,
|
|
ease_bounce_out: ease_bounce_out,
|
|
ease_circ_in: ease_circ_in,
|
|
ease_circ_in_out: ease_circ_in_out,
|
|
ease_circ_out: ease_circ_out,
|
|
ease_cubic_in: ease_cubic_in,
|
|
ease_cubic_in_out: ease_cubic_in_out,
|
|
ease_cubic_out: ease_cubic_out,
|
|
ease_elastic_in: ease_elastic_in,
|
|
ease_elastic_in_out: ease_elastic_in_out,
|
|
ease_elastic_out: ease_elastic_out,
|
|
ease_expo_in: ease_expo_in,
|
|
ease_expo_in_out: ease_expo_in_out,
|
|
ease_expo_out: ease_expo_out,
|
|
ease_quad_in: ease_quad_in,
|
|
ease_quad_in_out: ease_quad_in_out,
|
|
ease_quad_out: ease_quad_out,
|
|
ease_quart_in: ease_quart_in,
|
|
ease_quart_in_out: ease_quart_in_out,
|
|
ease_quart_out: ease_quart_out,
|
|
ease_quint_in: ease_quint_in,
|
|
ease_quint_in_out: ease_quint_in_out,
|
|
ease_quint_out: ease_quint_out,
|
|
ease_sine_in: ease_sine_in,
|
|
ease_sine_in_out: ease_sine_in_out,
|
|
ease_sine_out: ease_sine_out,
|
|
quadratic_bezier: quadratic_bezier,
|
|
quaternion_rotation: quaternion_rotation,
|
|
quaternion_slerp: quaternion_slerp
|
|
|
|
};
|
|
|
|
/**
|
|
* A timeline transition segment. An instance of this class is created internally when calling {@link THREE.BAS.Timeline.add}, so you should not use this class directly.
|
|
* The instance is also passed the the compiler function if you register a transition through {@link THREE.BAS.Timeline.register}. There you can use the public properties of the segment to compile the glsl string.
|
|
* @param {string} key A string key generated by the timeline to which this segment belongs. Keys are unique.
|
|
* @param {number} start Start time of this segment in a timeline in seconds.
|
|
* @param {number} duration Duration of this segment in seconds.
|
|
* @param {object} transition Object describing the transition.
|
|
* @param {function} compiler A reference to the compiler function from a transition definition.
|
|
* @constructor
|
|
*/
|
|
function TimelineSegment(key, start, duration, transition, compiler) {
|
|
this.key = key;
|
|
this.start = start;
|
|
this.duration = duration;
|
|
this.transition = transition;
|
|
this.compiler = compiler;
|
|
|
|
this.trail = 0;
|
|
}
|
|
|
|
TimelineSegment.prototype.compile = function () {
|
|
return this.compiler(this);
|
|
};
|
|
|
|
Object.defineProperty(TimelineSegment.prototype, 'end', {
|
|
get: function get() {
|
|
return this.start + this.duration;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* A utility class to create an animation timeline which can be baked into a (vertex) shader.
|
|
* By default the timeline supports translation, scale and rotation. This can be extended or overridden.
|
|
* @constructor
|
|
*/
|
|
function Timeline() {
|
|
/**
|
|
* The total duration of the timeline in seconds.
|
|
* @type {number}
|
|
*/
|
|
this.duration = 0;
|
|
|
|
/**
|
|
* The name of the value that segments will use to read the time. Defaults to 'tTime'.
|
|
* @type {string}
|
|
*/
|
|
this.timeKey = 'tTime';
|
|
|
|
this.segments = {};
|
|
this.__key = 0;
|
|
}
|
|
|
|
// static definitions map
|
|
Timeline.segmentDefinitions = {};
|
|
|
|
/**
|
|
* Registers a transition definition for use with {@link THREE.BAS.Timeline.add}.
|
|
* @param {String} key Name of the transition. Defaults include 'scale', 'rotate' and 'translate'.
|
|
* @param {Object} definition
|
|
* @param {Function} definition.compiler A function that generates a glsl string for a transition segment. Accepts a THREE.BAS.TimelineSegment as the sole argument.
|
|
* @param {*} definition.defaultFrom The initial value for a transform.from. For example, the defaultFrom for a translation is THREE.Vector3(0, 0, 0).
|
|
* @static
|
|
*/
|
|
Timeline.register = function (key, definition) {
|
|
Timeline.segmentDefinitions[key] = definition;
|
|
|
|
return definition;
|
|
};
|
|
|
|
/**
|
|
* Add a transition to the timeline.
|
|
* @param {number} duration Duration in seconds
|
|
* @param {object} transitions An object containing one or several transitions. The keys should match transform definitions.
|
|
* The transition object for each key will be passed to the matching definition's compiler. It can have arbitrary properties, but the Timeline expects at least a 'to', 'from' and an optional 'ease'.
|
|
* @param {number|string} [positionOffset] Position in the timeline. Defaults to the end of the timeline. If a number is provided, the transition will be inserted at that time in seconds. Strings ('+=x' or '-=x') can be used for a value relative to the end of timeline.
|
|
*/
|
|
Timeline.prototype.add = function (duration, transitions, positionOffset) {
|
|
// stop rollup from complaining about eval
|
|
var _eval = eval;
|
|
|
|
var start = this.duration;
|
|
|
|
if (positionOffset !== undefined) {
|
|
if (typeof positionOffset === 'number') {
|
|
start = positionOffset;
|
|
} else if (typeof positionOffset === 'string') {
|
|
_eval('start' + positionOffset);
|
|
}
|
|
|
|
this.duration = Math.max(this.duration, start + duration);
|
|
} else {
|
|
this.duration += duration;
|
|
}
|
|
|
|
var keys = Object.keys(transitions),
|
|
key = void 0;
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
|
|
this.processTransition(key, transitions[key], start, duration);
|
|
}
|
|
};
|
|
|
|
Timeline.prototype.processTransition = function (key, transition, start, duration) {
|
|
var definition = Timeline.segmentDefinitions[key];
|
|
|
|
var segments = this.segments[key];
|
|
if (!segments) segments = this.segments[key] = [];
|
|
|
|
if (transition.from === undefined) {
|
|
if (segments.length === 0) {
|
|
transition.from = definition.defaultFrom;
|
|
} else {
|
|
transition.from = segments[segments.length - 1].transition.to;
|
|
}
|
|
}
|
|
|
|
segments.push(new TimelineSegment((this.__key++).toString(), start, duration, transition, definition.compiler));
|
|
};
|
|
|
|
/**
|
|
* Compiles the timeline into a glsl string array that can be injected into a (vertex) shader.
|
|
* @returns {Array}
|
|
*/
|
|
Timeline.prototype.compile = function () {
|
|
var c = [];
|
|
|
|
var keys = Object.keys(this.segments);
|
|
var segments = void 0;
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
segments = this.segments[keys[i]];
|
|
|
|
this.fillGaps(segments);
|
|
|
|
segments.forEach(function (s) {
|
|
c.push(s.compile());
|
|
});
|
|
}
|
|
|
|
return c;
|
|
};
|
|
Timeline.prototype.fillGaps = function (segments) {
|
|
if (segments.length === 0) return;
|
|
|
|
var s0 = void 0,
|
|
s1 = void 0;
|
|
|
|
for (var i = 0; i < segments.length - 1; i++) {
|
|
s0 = segments[i];
|
|
s1 = segments[i + 1];
|
|
|
|
s0.trail = s1.start - s0.end;
|
|
}
|
|
|
|
// pad last segment until end of timeline
|
|
s0 = segments[segments.length - 1];
|
|
s0.trail = this.duration - s0.end;
|
|
};
|
|
|
|
/**
|
|
* Get a compiled glsl string with calls to transform functions for a given key.
|
|
* The order in which these transitions are applied matters because they all operate on the same value.
|
|
* @param {string} key A key matching a transform definition.
|
|
* @returns {string}
|
|
*/
|
|
Timeline.prototype.getTransformCalls = function (key) {
|
|
var t = this.timeKey;
|
|
|
|
return this.segments[key] ? this.segments[key].map(function (s) {
|
|
return 'applyTransform' + s.key + '(' + t + ', transformed);';
|
|
}).join('\n') : '';
|
|
};
|
|
|
|
var TimelineChunks = {
|
|
vec3: function vec3(n, v, p) {
|
|
var x = (v.x || 0).toPrecision(p);
|
|
var y = (v.y || 0).toPrecision(p);
|
|
var z = (v.z || 0).toPrecision(p);
|
|
|
|
return "vec3 " + n + " = vec3(" + x + ", " + y + ", " + z + ");";
|
|
},
|
|
vec4: function vec4(n, v, p) {
|
|
var x = (v.x || 0).toPrecision(p);
|
|
var y = (v.y || 0).toPrecision(p);
|
|
var z = (v.z || 0).toPrecision(p);
|
|
var w = (v.w || 0).toPrecision(p);
|
|
|
|
return "vec4 " + n + " = vec4(" + x + ", " + y + ", " + z + ", " + w + ");";
|
|
},
|
|
delayDuration: function delayDuration(segment) {
|
|
return "\n float cDelay" + segment.key + " = " + segment.start.toPrecision(4) + ";\n float cDuration" + segment.key + " = " + segment.duration.toPrecision(4) + ";\n ";
|
|
},
|
|
progress: function progress(segment) {
|
|
// zero duration segments should always render complete
|
|
if (segment.duration === 0) {
|
|
return "float progress = 1.0;";
|
|
} else {
|
|
return "\n float progress = clamp(time - cDelay" + segment.key + ", 0.0, cDuration" + segment.key + ") / cDuration" + segment.key + ";\n " + (segment.transition.ease ? "progress = " + segment.transition.ease + "(progress" + (segment.transition.easeParams ? ", " + segment.transition.easeParams.map(function (v) {
|
|
return v.toPrecision(4);
|
|
}).join(", ") : "") + ");" : "") + "\n ";
|
|
}
|
|
},
|
|
renderCheck: function renderCheck(segment) {
|
|
var startTime = segment.start.toPrecision(4);
|
|
var endTime = (segment.end + segment.trail).toPrecision(4);
|
|
|
|
return "if (time < " + startTime + " || time > " + endTime + ") return;";
|
|
}
|
|
};
|
|
|
|
var TranslationSegment = {
|
|
compiler: function compiler(segment) {
|
|
return '\n ' + TimelineChunks.delayDuration(segment) + '\n ' + TimelineChunks.vec3('cTranslateFrom' + segment.key, segment.transition.from, 2) + '\n ' + TimelineChunks.vec3('cTranslateTo' + segment.key, segment.transition.to, 2) + '\n \n void applyTransform' + segment.key + '(float time, inout vec3 v) {\n \n ' + TimelineChunks.renderCheck(segment) + '\n ' + TimelineChunks.progress(segment) + '\n \n v += mix(cTranslateFrom' + segment.key + ', cTranslateTo' + segment.key + ', progress);\n }\n ';
|
|
},
|
|
defaultFrom: new three.Vector3(0, 0, 0)
|
|
};
|
|
|
|
Timeline.register('translate', TranslationSegment);
|
|
|
|
var ScaleSegment = {
|
|
compiler: function compiler(segment) {
|
|
var origin = segment.transition.origin;
|
|
|
|
return '\n ' + TimelineChunks.delayDuration(segment) + '\n ' + TimelineChunks.vec3('cScaleFrom' + segment.key, segment.transition.from, 2) + '\n ' + TimelineChunks.vec3('cScaleTo' + segment.key, segment.transition.to, 2) + '\n ' + (origin ? TimelineChunks.vec3('cOrigin' + segment.key, origin, 2) : '') + '\n \n void applyTransform' + segment.key + '(float time, inout vec3 v) {\n \n ' + TimelineChunks.renderCheck(segment) + '\n ' + TimelineChunks.progress(segment) + '\n \n ' + (origin ? 'v -= cOrigin' + segment.key + ';' : '') + '\n v *= mix(cScaleFrom' + segment.key + ', cScaleTo' + segment.key + ', progress);\n ' + (origin ? 'v += cOrigin' + segment.key + ';' : '') + '\n }\n ';
|
|
},
|
|
defaultFrom: new three.Vector3(1, 1, 1)
|
|
};
|
|
|
|
Timeline.register('scale', ScaleSegment);
|
|
|
|
var RotationSegment = {
|
|
compiler: function compiler(segment) {
|
|
var fromAxisAngle = new three.Vector4(segment.transition.from.axis.x, segment.transition.from.axis.y, segment.transition.from.axis.z, segment.transition.from.angle);
|
|
|
|
var toAxis = segment.transition.to.axis || segment.transition.from.axis;
|
|
var toAxisAngle = new three.Vector4(toAxis.x, toAxis.y, toAxis.z, segment.transition.to.angle);
|
|
|
|
var origin = segment.transition.origin;
|
|
|
|
return '\n ' + TimelineChunks.delayDuration(segment) + '\n ' + TimelineChunks.vec4('cRotationFrom' + segment.key, fromAxisAngle, 8) + '\n ' + TimelineChunks.vec4('cRotationTo' + segment.key, toAxisAngle, 8) + '\n ' + (origin ? TimelineChunks.vec3('cOrigin' + segment.key, origin, 2) : '') + '\n \n void applyTransform' + segment.key + '(float time, inout vec3 v) {\n ' + TimelineChunks.renderCheck(segment) + '\n ' + TimelineChunks.progress(segment) + '\n\n ' + (origin ? 'v -= cOrigin' + segment.key + ';' : '') + '\n vec3 axis = normalize(mix(cRotationFrom' + segment.key + '.xyz, cRotationTo' + segment.key + '.xyz, progress));\n float angle = mix(cRotationFrom' + segment.key + '.w, cRotationTo' + segment.key + '.w, progress);\n vec4 q = quatFromAxisAngle(axis, angle);\n v = rotateVector(q, v);\n ' + (origin ? 'v += cOrigin' + segment.key + ';' : '') + '\n }\n ';
|
|
},
|
|
|
|
defaultFrom: { axis: new three.Vector3(), angle: 0 }
|
|
};
|
|
|
|
Timeline.register('rotate', RotationSegment);
|
|
|
|
exports.BasicAnimationMaterial = BasicAnimationMaterial;
|
|
exports.LambertAnimationMaterial = LambertAnimationMaterial;
|
|
exports.PhongAnimationMaterial = PhongAnimationMaterial;
|
|
exports.StandardAnimationMaterial = StandardAnimationMaterial;
|
|
exports.PointsAnimationMaterial = PointsAnimationMaterial;
|
|
exports.DepthAnimationMaterial = DepthAnimationMaterial;
|
|
exports.DistanceAnimationMaterial = DistanceAnimationMaterial;
|
|
exports.PrefabBufferGeometry = PrefabBufferGeometry;
|
|
exports.MultiPrefabBufferGeometry = MultiPrefabBufferGeometry;
|
|
exports.ModelBufferGeometry = ModelBufferGeometry;
|
|
exports.PointBufferGeometry = PointBufferGeometry;
|
|
exports.ShaderChunk = ShaderChunk;
|
|
exports.Timeline = Timeline;
|
|
exports.TimelineSegment = TimelineSegment;
|
|
exports.TimelineChunks = TimelineChunks;
|
|
exports.TranslationSegment = TranslationSegment;
|
|
exports.ScaleSegment = ScaleSegment;
|
|
exports.RotationSegment = RotationSegment;
|
|
exports.Utils = Utils;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|