未验证 提交 12d30916 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #14333 from sunag/dev-nodematerial-r7

NodeMaterial - r7
......@@ -91,7 +91,11 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
getObjectById: function ( uuid ) {
return this.library[ uuid ] || this.nodes[ uuid ] || this.names[ uuid ];
return this.library[ uuid ] ||
this.nodes[ uuid ] ||
this.materials[ uuid ] ||
this.passes[ uuid ] ||
this.names[ uuid ];
},
......@@ -109,15 +113,62 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
},
parse: function ( json ) {
var uuid, node, object, prop, i;
resolve: function( json ) {
switch( typeof json ) {
case "boolean":
case "number":
return json;
case "string":
if (/^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/i.test(json) || this.library[ json ]) {
return this.getNode( json );
}
return json;
default:
if ( Array.isArray( json ) ) {
for(var i = 0; i < json.length; i++) {
json[i] = this.resolve( json[i] );
}
} else {
for ( var prop in json ) {
if (prop === "uuid") continue;
json[ prop ] = this.resolve( json[ prop ] );
}
}
}
return json;
},
declare: function( json ) {
var uuid, node, object;
for ( uuid in json.nodes ) {
node = json.nodes[ uuid ];
object = new THREE[ node.type ]();
object = new THREE[ node.nodeType + "Node" ]();
if ( node.name ) {
......@@ -125,15 +176,8 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
this.names[ object.name ] = object;
} else {
// ignore "uniform" shader input ( for optimization )
object.readonly = true;
}
if ( node.readonly !== undefined ) object.readonly = node.readonly;
this.nodes[ uuid ] = object;
}
......@@ -174,410 +218,35 @@ Object.assign( THREE.NodeMaterialLoader.prototype, {
}
if ( json.material ) this.material = this.materials[ uuid ];
if ( json.pass ) this.pass = this.passes[ uuid ];
if ( json.material ) this.material = this.materials[ json.material ];
if ( json.pass ) this.pass = this.passes[ json.pass ];
return json;
},
parse: function ( json ) {
var uuid;
json = this.resolve( this.declare( json ) );
for ( uuid in json.nodes ) {
node = json.nodes[ uuid ];
object = this.nodes[ uuid ];
switch ( node.type ) {
case "IntNode":
case "FloatNode":
object.value = node.value;
break;
case "ColorNode":
object.value.copy( node );
break;
case "Vector2Node":
object.x = node.x;
object.y = node.y;
break;
case "Vector3Node":
object.x = node.x;
object.y = node.y;
object.z = node.z;
break;
case "Vector4Node":
object.x = node.x;
object.y = node.y;
object.z = node.z;
object.w = node.w;
break;
case "Matrix3Node":
case "Matrix4Node":
object.value.fromArray( node.elements );
break;
case "OperatorNode":
object.a = this.getNode( node.a );
object.b = this.getNode( node.b );
object.op = node.op;
break;
case "Math1Node":
object.a = this.getNode( node.a );
object.method = node.method;
break;
case "Math2Node":
object.a = this.getNode( node.a );
object.b = this.getNode( node.b );
object.method = node.method;
break;
case "Math3Node":
object.a = this.getNode( node.a );
object.b = this.getNode( node.b );
object.c = this.getNode( node.c );
object.method = node.method;
break;
case "UVNode":
case "ColorsNode":
object.index = node.index;
break;
case "LuminanceNode":
object.rgb = this.getNode( node.rgb );
break;
case "PositionNode":
case "NormalNode":
case "ReflectNode":
case "LightNode":
object.scope = node.scope;
break;
case "SwitchNode":
object.node = this.getNode( node.node );
object.components = node.components;
break;
case "JoinNode":
for ( prop in node.inputs ) {
object[ prop ] = this.getNode( node.inputs[ prop ] );
}
break;
case "CameraNode":
object.setScope( node.scope );
if ( node.camera ) object.setCamera( this.getNode( node.camera ) );
switch ( node.scope ) {
case THREE.CameraNode.DEPTH:
object.near.number = node.near;
object.far.number = node.far;
break;
}
break;
case "ColorAdjustmentNode":
object.rgb = this.getNode( node.rgb );
object.adjustment = this.getNode( node.adjustment );
object.method = node.method;
break;
case "UVTransformNode":
object.uv = this.getNode( node.uv );
object.transform = this.getNode( node.transform );
break;
case "BumpNode":
object.value = this.getNode( node.value );
object.coord = this.getNode( node.coord );
object.scale = this.getNode( node.scale );
break;
case "BlurNode":
object.value = this.getNode( node.value );
object.coord = this.getNode( node.coord );
object.scale = this.getNode( node.scale );
object.value = this.getNode( node.value );
object.coord = this.getNode( node.coord );
object.radius = this.getNode( node.radius );
if ( node.size !== undefined ) object.size = new THREE.Vector2( node.size.x, node.size.y );
object.blurX = node.blurX;
object.blurY = node.blurY;
break;
case "ResolutionNode":
object.renderer = this.getNode( node.renderer );
break;
case "ScreenUVNode":
object.resolution = this.getNode( node.resolution );
break;
case "VelocityNode":
if ( node.target ) object.setTarget( this.getNode( node.target ) );
object.setParams( node.params );
break;
case "TimerNode":
object.scope = node.scope;
object.scale = node.scale;
break;
case "ConstNode":
object.name = node.name;
object.type = node.out;
object.value = node.value;
object.useDefine = node.useDefine === true;
break;
case "AttributeNode":
case "VarNode":
object.type = node.out;
break;
case "ReflectorNode":
object.setMirror( this.getNode( node.mirror ) );
if ( node.offset ) object.offset = this.getNode( node.offset );
break;
case "NoiseNode":
object.coord = this.getNode( node.coord );
break;
case "FunctionNode":
object.isMethod = node.isMethod;
object.useKeywords = node.useKeywords;
object.extensions = node.extensions;
object.keywords = {};
for ( prop in node.keywords ) {
object.keywords[ prop ] = this.getNode( node.keywords[ prop ] );
}
if ( node.includes ) {
for ( i = 0; i < node.includes.length; i ++ ) {
object.includes.push( this.getNode( node.includes[ i ] ) );
}
}
object.eval( node.src, object.includes, object.extensions, object.keywords );
if ( ! object.isMethod ) object.type = node.out;
break;
case "FunctionCallNode":
for ( prop in node.inputs ) {
object.inputs[ prop ] = this.getNode( node.inputs[ prop ] );
}
object.value = this.getNode( node.value );
break;
case "TextureNode":
case "CubeTextureNode":
case "ScreenNode":
if ( node.value ) object.value = this.getNode( node.value );
object.coord = this.getNode( node.coord );
if ( node.bias ) object.bias = this.getNode( node.bias );
if ( object.project !== undefined ) object.project = node.project;
break;
case "RoughnessToBlinnExponentNode":
break;
case "RawNode":
object.value = this.getNode( node.value );
break;
case "StandardNode":
case "PhongNode":
case "SpriteNode":
object.color = this.getNode( node.color );
if ( node.alpha ) object.alpha = this.getNode( node.alpha );
if ( node.specular ) object.specular = this.getNode( node.specular );
if ( node.shininess ) object.shininess = this.getNode( node.shininess );
if ( node.roughness ) object.roughness = this.getNode( node.roughness );
if ( node.metalness ) object.metalness = this.getNode( node.metalness );
if ( node.reflectivity ) object.reflectivity = this.getNode( node.reflectivity );
if ( node.clearCoat ) object.clearCoat = this.getNode( node.clearCoat );
if ( node.clearCoatRoughness ) object.clearCoatRoughness = this.getNode( node.clearCoatRoughness );
if ( node.normal ) object.normal = this.getNode( node.normal );
if ( node.normalScale ) object.normalScale = this.getNode( node.normalScale );
if ( node.emissive ) object.emissive = this.getNode( node.emissive );
if ( node.ambient ) object.ambient = this.getNode( node.ambient );
if ( node.shadow ) object.shadow = this.getNode( node.shadow );
if ( node.light ) object.light = this.getNode( node.light );
if ( node.ao ) object.ao = this.getNode( node.ao );
if ( node.environment ) object.environment = this.getNode( node.environment );
if ( node.environmentAlpha ) object.environmentAlpha = this.getNode( node.environmentAlpha );
if ( node.transform ) object.transform = this.getNode( node.transform );
if ( node.spherical === false ) object.spherical = false;
break;
default:
console.warn( node.type, "not supported." );
}
this.nodes[ uuid ].copy( json.nodes[ uuid ] );
}
for ( uuid in json.materials ) {
node = json.materials[ uuid ];
object = this.materials[ uuid ];
if ( node.name !== undefined ) object.name = node.name;
if ( node.blending !== undefined ) object.blending = node.blending;
if ( node.flatShading !== undefined ) object.flatShading = node.flatShading;
if ( node.side !== undefined ) object.side = node.side;
object.depthFunc = node.depthFunc;
object.depthTest = node.depthTest;
object.depthWrite = node.depthWrite;
if ( node.wireframe !== undefined ) object.wireframe = node.wireframe;
if ( node.wireframeLinewidth !== undefined ) object.wireframeLinewidth = node.wireframeLinewidth;
if ( node.wireframeLinecap !== undefined ) object.wireframeLinecap = node.wireframeLinecap;
if ( node.wireframeLinejoin !== undefined ) object.wireframeLinejoin = node.wireframeLinejoin;
if ( node.skinning !== undefined ) object.skinning = node.skinning;
if ( node.morphTargets !== undefined ) object.morphTargets = node.morphTargets;
if ( node.visible !== undefined ) object.visible = node.visible;
if ( node.userData !== undefined ) object.userData = node.userData;
object.vertex = this.getNode( node.vertex );
object.fragment = this.getNode( node.fragment );
if ( object.vertex === object.fragment ) {
// replace main node
object.node = object.vertex;
}
if ( node.fog !== undefined ) object.fog = node.fog;
if ( node.lights !== undefined ) object.lights = node.lights;
if ( node.transparent !== undefined ) object.transparent = node.transparent;
this.materials[ uuid ].copy( json.materials[ uuid ] );
}
for ( uuid in json.passes ) {
node = json.passes[ uuid ];
object = this.passes[ uuid ];
object.value = this.getNode( node.value );
this.passes[ uuid ].copy( json.passes[ uuid ] );
}
......
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.GLNode = function ( type ) {
this.uuid = THREE.Math.generateUUID();
this.name = "";
this.allows = {};
this.type = type;
this.userData = {};
};
THREE.GLNode.prototype.isNode = true;
THREE.GLNode.prototype.parse = function ( builder, context ) {
context = context || {};
builder.parsing = true;
var material = builder.material;
this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), 'v4' );
material.clearVertexNode();
material.clearFragmentNode();
builder.removeCache().removeSlot();
builder.parsing = false;
};
THREE.GLNode.prototype.parseAndBuildCode = function ( builder, output, context ) {
context = context || {};
this.parse( builder, context );
return this.buildCode( builder, output, context );
};
THREE.GLNode.prototype.buildCode = function ( builder, output, context ) {
context = context || {};
var material = builder.material;
var data = { result: this.build( builder.addCache( context.cache, context.requires ).addSlot( context.slot ), output ) };
if ( builder.isShader( 'vertex' ) ) data.code = material.clearVertexNode();
else data.code = material.clearFragmentNode();
builder.removeCache().removeSlot();
return data;
};
THREE.GLNode.prototype.build = function ( builder, output, uuid ) {
output = output || this.getType( builder, output );
var material = builder.material, data = material.getDataNode( uuid || this.uuid );
if ( builder.parsing ) this.appendDepsNode( builder, data, output );
if ( this.allows[ builder.shader ] === false ) {
throw new Error( 'Shader ' + shader + ' is not compatible with this node.' );
}
if ( material.nodes.indexOf( this ) === - 1 ) {
material.nodes.push( this );
}
if ( this.updateFrame !== undefined && material.updaters.indexOf( this ) === - 1 ) {
material.updaters.push( this );
}
return this.generate( builder, output, uuid );
};
THREE.GLNode.prototype.appendDepsNode = function ( builder, data, output ) {
data.deps = ( data.deps || 0 ) + 1;
var outputLen = builder.getFormatLength( output );
if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
data.outputMax = outputLen;
data.output = output;
}
};
THREE.GLNode.prototype.getType = function ( builder, output ) {
return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
};
THREE.GLNode.prototype.getJSONNode = function ( meta ) {
var isRootObject = ( meta === undefined || typeof meta === 'string' );
if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
return meta.nodes[ this.uuid ];
}
};
THREE.GLNode.prototype.createJSONNode = function ( meta ) {
var isRootObject = ( meta === undefined || typeof meta === 'string' );
var data = {};
if ( typeof this.nodeType !== "string" ) throw new Error( "Node does not allow serialization." );
data.uuid = this.uuid;
data.type = this.nodeType + "Node";
if ( this.name !== "" ) data.name = this.name;
if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
if ( ! isRootObject ) {
meta.nodes[ this.uuid ] = data;
}
return data;
};
THREE.GLNode.prototype.toJSON = function ( meta ) {
return this.getJSONNode( meta ) || this.createJSONNode( meta );
};
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.NodeBuilder = function ( material, renderer ) {
this.material = material;
this.renderer = renderer;
this.caches = [];
this.slots = [];
this.keywords = {};
this.parsing = false;
this.optimize = true;
this.update();
};
THREE.NodeBuilder.type = {
float: 'fv1',
vec2: 'v2',
vec3: 'v3',
vec4: 'v4',
mat4: 'v4',
int: 'iv1'
};
THREE.NodeBuilder.constructors = [
'float',
'vec2',
'vec3',
'vec4'
];
THREE.NodeBuilder.elements = [
'x',
'y',
'z',
'w'
];
THREE.NodeBuilder.prototype = {
constructor: THREE.NodeBuilder,
addCache: function ( name, requires ) {
this.caches.push( {
name: name || '',
requires: requires || {}
} );
return this.update();
},
removeCache: function () {
this.caches.pop();
return this.update();
},
addSlot: function ( name ) {
this.slots.push( {
name: name || ''
} );
return this.update();
},
removeSlot: function () {
this.slots.pop();
return this.update();
},
isCache: function ( name ) {
var i = this.caches.length;
while ( i -- ) {
if ( this.caches[ i ].name == name ) return true;
}
return false;
},
isSlot: function ( name ) {
var i = this.slots.length;
while ( i -- ) {
if ( this.slots[ i ].name == name ) return true;
}
return false;
},
update: function () {
var cache = this.caches[ this.caches.length - 1 ];
var slot = this.slots[ this.slots.length - 1 ];
this.slot = slot ? slot.name : '';
this.cache = cache ? cache.name : '';
this.requires = cache ? cache.requires : {};
return this;
},
require: function ( name, node ) {
this.requires[ name ] = node;
return this;
},
include: function ( node, parent, source ) {
this.material.include( this, node, parent, source );
return this;
},
colorToVector: function ( color ) {
return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
},
getConstructorFromLength: function ( len ) {
return THREE.NodeBuilder.constructors[ len - 1 ];
},
getFormatName: function ( format ) {
return format.replace( /c/g, 'v3' ).replace( /fv1/g, 'v1' ).replace( /iv1/g, 'i' );
},
isFormatMatrix: function ( format ) {
return /^m/.test( format );
},
getFormatLength: function ( format ) {
return parseInt( this.getFormatName( format ).substr( 1 ) );
},
getFormatFromLength: function ( len ) {
if ( len == 1 ) return 'fv1';
return 'v' + len;
},
format: function ( code, from, to ) {
var format = this.getFormatName( to + '=' + from );
switch ( format ) {
case 'v1=v2': return code + '.x';
case 'v1=v3': return code + '.x';
case 'v1=v4': return code + '.x';
case 'v1=i': return 'float(' + code + ')';
case 'v2=v1': return 'vec2(' + code + ')';
case 'v2=v3': return code + '.xy';
case 'v2=v4': return code + '.xy';
case 'v2=i': return 'vec2(float(' + code + '))';
case 'v3=v1': return 'vec3(' + code + ')';
case 'v3=v2': return 'vec3(' + code + ',0.0)';
case 'v3=v4': return code + '.xyz';
case 'v3=i': return 'vec2(float(' + code + '))';
case 'v4=v1': return 'vec4(' + code + ')';
case 'v4=v2': return 'vec4(' + code + ',0.0,1.0)';
case 'v4=v3': return 'vec4(' + code + ',1.0)';
case 'v4=i': return 'vec4(float(' + code + '))';
case 'i=v1': return 'int(' + code + ')';
case 'i=v2': return 'int(' + code + '.x)';
case 'i=v3': return 'int(' + code + '.x)';
case 'i=v4': return 'int(' + code + '.x)';
}
return code;
},
getTypeByFormat: function ( format ) {
return THREE.NodeBuilder.type[ format ] || format;
},
getUuid: function ( uuid, useCache ) {
useCache = useCache !== undefined ? useCache : true;
if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
return uuid;
},
getElementByIndex: function ( index ) {
return THREE.NodeBuilder.elements[ index ];
},
getIndexByElement: function ( elm ) {
return THREE.NodeBuilder.elements.indexOf( elm );
},
isShader: function ( shader ) {
return this.shader == shader;
},
setShader: function ( shader ) {
this.shader = shader;
return this;
}
};
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.NodeFrame = function ( time ) {
this.time = time !== undefined ? time : 0;
this.frameId = 0;
};
THREE.NodeFrame.prototype.update = function ( delta ) {
++this.frameId;
this.time += delta;
this.delta = delta;
return this;
};
THREE.NodeFrame.prototype.updateNode = function ( node ) {
if ( node.frameId === this.frameId ) return this;
node.updateFrame( this );
node.frameId = this.frameId;
return this;
};
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.NodeLib = {
nodes: {},
keywords: {},
add: function ( node ) {
this.nodes[ node.name ] = node;
},
addKeyword: function ( name, callback, cache ) {
cache = cache !== undefined ? cache : true;
this.keywords[ name ] = { callback: callback, cache: cache };
},
remove: function ( node ) {
delete this.nodes[ node.name ];
},
removeKeyword: function ( name ) {
delete this.keywords[ name ];
},
get: function ( name ) {
return this.nodes[ name ];
},
getKeyword: function ( name, material ) {
return this.keywords[ name ].callback.call( this, material );
},
getKeywordData: function ( name ) {
return this.keywords[ name ];
},
contains: function ( name ) {
return this.nodes[ name ] != undefined;
},
containsKeyword: function ( name ) {
return this.keywords[ name ] != undefined;
}
};
//
// Keywords
//
THREE.NodeLib.addKeyword( 'uv', function () {
return new THREE.UVNode();
} );
THREE.NodeLib.addKeyword( 'uv2', function () {
return new THREE.UVNode( 1 );
} );
THREE.NodeLib.addKeyword( 'position', function () {
return new THREE.PositionNode();
} );
THREE.NodeLib.addKeyword( 'worldPosition', function () {
return new THREE.PositionNode( THREE.PositionNode.WORLD );
} );
THREE.NodeLib.addKeyword( 'normal', function () {
return new THREE.NormalNode();
} );
THREE.NodeLib.addKeyword( 'worldNormal', function () {
return new THREE.NormalNode( THREE.NormalNode.WORLD );
} );
THREE.NodeLib.addKeyword( 'viewPosition', function () {
return new THREE.PositionNode( THREE.NormalNode.VIEW );
} );
THREE.NodeLib.addKeyword( 'viewNormal', function () {
return new THREE.NormalNode( THREE.NormalNode.VIEW );
} );
THREE.NodeLib.addKeyword( 'time', function () {
return new THREE.TimerNode();
} );
//
// Luma
//
THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA vec3(0.2125, 0.7154, 0.0721)" ) );
//
// NormalMap
//
THREE.NodeLib.add( new THREE.FunctionNode( [
// Per-Pixel Tangent Space Normal Mapping
// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
" vec3 q0 = dFdx( eye_pos );",
" vec3 q1 = dFdy( eye_pos );",
" vec2 st0 = dFdx( mUv.st );",
" vec2 st1 = dFdy( mUv.st );",
" float factor = sign( st1.t * st0.s - st0.t * st1.s );",
" factor *= float( gl_FrontFacing ) * 2.0 - 1.0;",
" vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * factor );",
" vec3 T = normalize( ( -q0 * st1.s + q1 * st0.s ) * factor );",
" vec3 N = normalize( surf_norm );",
" vec3 mapN = map * 2.0 - 1.0;",
" mapN.xy = scale * mapN.xy;",
" mat3 tsn = mat3( S, T, N );",
" return normalize( tsn * mapN );",
"}"
].join( "\n" ), null, { derivatives: true } ) );
//
// Noise
//
THREE.NodeLib.add( new THREE.FunctionNode( [
"float snoise(vec2 co) {",
" return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
"}"
].join( "\n" ) ) );
//
// Hue
//
THREE.NodeLib.add( new THREE.FunctionNode( [
"vec3 hue_rgb(vec3 rgb, float adjustment) {",
" const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
" const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
" vec3 yiq = RGBtoYIQ * rgb;",
" float hue = atan(yiq.z, yiq.y) + adjustment;",
" float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
" return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
"}"
].join( "\n" ) ) );
//
// Saturation
//
THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 16 of OpenGL Shading Language
"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
" vec3 intensity = vec3(dot(rgb, LUMA));",
" return mix(intensity, rgb, adjustment);",
"}"
].join( "\n" ) ) );
//
// Luminance
//
THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 10 of Graphics Shaders
"float luminance_rgb(vec3 rgb) {",
" return dot(rgb, LUMA);",
"}"
].join( "\n" ) ) );
//
// Vibrance
//
THREE.NodeLib.add( new THREE.FunctionNode( [
// Shader by Evan Wallace adapted by @lo-th
"vec3 vibrance_rgb(vec3 rgb, float adjustment) {",
" float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
" float mx = max(rgb.r, max(rgb.g, rgb.b));",
" float amt = (mx - average) * (-3.0 * adjustment);",
" return mix(rgb.rgb, vec3(mx), amt);",
"}"
].join( "\n" ) ) );
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.NodeMaterial = function ( vertex, fragment ) {
THREE.ShaderMaterial.call( this );
this.defines.UUID = this.uuid;
this.vertex = vertex || new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) );
this.fragment = fragment || new THREE.RawNode( new THREE.ColorNode( 0xFF0000 ) );
this.updaters = [];
};
THREE.NodeMaterial.types = {
t: 'sampler2D',
tc: 'samplerCube',
bv1: 'bool',
iv1: 'int',
fv1: 'float',
c: 'vec3',
v2: 'vec2',
v3: 'vec3',
v4: 'vec4',
m3: 'mat3',
m4: 'mat4'
};
THREE.NodeMaterial.addShortcuts = function ( proto, prop, list ) {
function applyShortcut( prop, name ) {
return {
get: function () {
return this[ prop ][ name ];
},
set: function ( val ) {
this[ prop ][ name ] = val;
}
};
}
return ( function () {
var shortcuts = {};
for ( var i = 0; i < list.length; ++ i ) {
var name = list[ i ];
shortcuts[ name ] = applyShortcut( prop, name );
}
Object.defineProperties( proto, shortcuts );
} )();
};
THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
THREE.NodeMaterial.prototype.type = "NodeMaterial";
THREE.NodeMaterial.prototype.updateFrame = function ( frame ) {
for ( var i = 0; i < this.updaters.length; ++ i ) {
frame.updateNode( this.updaters[ i ] );
}
};
THREE.NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
if ( this.needsUpdate ) {
this.build( { dispose: false, renderer: renderer } );
shader.uniforms = this.uniforms;
shader.vertexShader = this.vertexShader;
shader.fragmentShader = this.fragmentShader;
}
};
THREE.NodeMaterial.prototype.build = function ( params ) {
params = params || {};
params.dispose = params.dispose !== undefined ? params.dispose : true;
var vertex, fragment;
this.nodes = [];
this.defines = { UUID: this.uuid };
this.uniforms = {};
this.attributes = {};
this.extensions = {};
this.nodeData = {};
this.vertexUniform = [];
this.fragmentUniform = [];
this.vars = [];
this.vertexTemps = [];
this.fragmentTemps = [];
this.uniformList = [];
this.consts = [];
this.functions = [];
this.updaters = [];
this.requires = {
uv: [],
color: [],
lights: this.lights,
fog: this.fog
};
this.vertexPars = '';
this.fragmentPars = '';
this.vertexCode = '';
this.fragmentCode = '';
this.vertexNode = '';
this.fragmentNode = '';
this.prefixCode = [
"#ifdef GL_EXT_shader_texture_lod",
" #define texCube(a, b) textureCube(a, b)",
" #define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
" #define tex2D(a, b) texture2D(a, b)",
" #define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
"#else",
" #define texCube(a, b) textureCube(a, b)",
" #define texCubeBias(a, b, c) textureCube(a, b, c)",
" #define tex2D(a, b) texture2D(a, b)",
" #define tex2DBias(a, b, c) texture2D(a, b, c)",
"#endif",
"#include <packing>"
].join( "\n" );
var builder = new THREE.NodeBuilder( this, params.renderer );
vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
if ( this.requires.uv[ 0 ] ) {
this.addVertexPars( 'varying vec2 vUv;' );
this.addFragmentPars( 'varying vec2 vUv;' );
this.addVertexCode( 'vUv = uv;' );
}
if ( this.requires.uv[ 1 ] ) {
this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
this.addFragmentPars( 'varying vec2 vUv2;' );
this.addVertexCode( 'vUv2 = uv2;' );
}
if ( this.requires.color[ 0 ] ) {
this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
this.addFragmentPars( 'varying vec4 vColor;' );
this.addVertexCode( 'vColor = color;' );
}
if ( this.requires.color[ 1 ] ) {
this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
this.addFragmentPars( 'varying vec4 vColor2;' );
this.addVertexCode( 'vColor2 = color2;' );
}
if ( this.requires.position ) {
this.addVertexPars( 'varying vec3 vPosition;' );
this.addFragmentPars( 'varying vec3 vPosition;' );
this.addVertexCode( 'vPosition = transformed;' );
}
if ( this.requires.worldPosition ) {
this.addVertexPars( 'varying vec3 vWPosition;' );
this.addFragmentPars( 'varying vec3 vWPosition;' );
this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
}
if ( this.requires.normal ) {
this.addVertexPars( 'varying vec3 vObjectNormal;' );
this.addFragmentPars( 'varying vec3 vObjectNormal;' );
this.addVertexCode( 'vObjectNormal = normal;' );
}
if ( this.requires.worldNormal ) {
this.addVertexPars( 'varying vec3 vWNormal;' );
this.addFragmentPars( 'varying vec3 vWNormal;' );
this.addVertexCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
}
this.fog = this.requires.fog;
this.lights = this.requires.lights;
this.transparent = this.requires.transparent || this.blending > THREE.NormalBlending;
this.vertexShader = [
this.prefixCode,
this.vertexPars,
this.getCodePars( this.vertexUniform, 'uniform' ),
this.getIncludes( this.consts[ 'vertex' ] ),
this.getIncludes( this.functions[ 'vertex' ] ),
'void main(){',
this.getCodePars( this.vertexTemps ),
vertex,
this.vertexCode,
'}'
].join( "\n" );
this.fragmentShader = [
this.prefixCode,
this.fragmentPars,
this.getCodePars( this.fragmentUniform, 'uniform' ),
this.getIncludes( this.consts[ 'fragment' ] ),
this.getIncludes( this.functions[ 'fragment' ] ),
'void main(){',
this.getCodePars( this.fragmentTemps ),
this.fragmentCode,
fragment,
'}'
].join( "\n" );
if ( params.dispose ) {
// force update
this.dispose();
}
return this;
};
THREE.NodeMaterial.prototype.define = function ( name, value ) {
this.defines[ name ] = value == undefined ? 1 : value;
};
THREE.NodeMaterial.prototype.isDefined = function ( name ) {
return this.defines[ name ] != undefined;
};
THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
for ( var name in uniforms ) {
this.uniforms[ name ] = uniforms[ name ];
}
};
THREE.NodeMaterial.prototype.createUniform = function ( type, node, ns, needsUpdate ) {
var index = this.uniformList.length;
var uniform = new THREE.NodeUniform( {
type: type,
name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
node: node,
needsUpdate: needsUpdate
} );
this.uniformList.push( uniform );
return uniform;
};
THREE.NodeMaterial.prototype.getVertexTemp = function ( uuid, type, ns ) {
var data = this.vertexTemps[ uuid ];
if ( ! data ) {
var index = this.vertexTemps.length,
name = ns ? ns : 'nVt' + index;
data = { name: name, type: type };
this.vertexTemps.push( data );
this.vertexTemps[ uuid ] = data;
}
return data;
};
THREE.NodeMaterial.prototype.getFragmentTemp = function ( uuid, type, ns ) {
var data = this.fragmentTemps[ uuid ];
if ( ! data ) {
var index = this.fragmentTemps.length,
name = ns ? ns : 'nVt' + index;
data = { name: name, type: type };
this.fragmentTemps.push( data );
this.fragmentTemps[ uuid ] = data;
}
return data;
};
THREE.NodeMaterial.prototype.getVar = function ( uuid, type, ns ) {
var data = this.vars[ uuid ];
if ( ! data ) {
var index = this.vars.length,
name = ns ? ns : 'nVv' + index;
data = { name: name, type: type };
this.vars.push( data );
this.vars[ uuid ] = data;
this.addVertexPars( 'varying ' + type + ' ' + name + ';' );
this.addFragmentPars( 'varying ' + type + ' ' + name + ';' );
}
return data;
};
THREE.NodeMaterial.prototype.getAttribute = function ( name, type ) {
if ( ! this.attributes[ name ] ) {
var varying = this.getVar( name, type );
this.addVertexPars( 'attribute ' + type + ' ' + name + ';' );
this.addVertexCode( varying.name + ' = ' + name + ';' );
this.attributes[ name ] = { varying: varying, name: name, type: type };
}
return this.attributes[ name ];
};
THREE.NodeMaterial.prototype.getIncludes = function () {
function sortByPosition( a, b ) {
return a.deps.length - b.deps.length;
}
return function ( incs ) {
if ( ! incs ) return '';
var code = '', incs = incs.sort( sortByPosition );
for ( var i = 0; i < incs.length; i ++ ) {
if ( incs[ i ].src ) code += incs[ i ].src + '\n';
}
return code;
};
}();
THREE.NodeMaterial.prototype.addVertexPars = function ( code ) {
this.vertexPars += code + '\n';
};
THREE.NodeMaterial.prototype.addFragmentPars = function ( code ) {
this.fragmentPars += code + '\n';
};
THREE.NodeMaterial.prototype.addVertexCode = function ( code ) {
this.vertexCode += code + '\n';
};
THREE.NodeMaterial.prototype.addFragmentCode = function ( code ) {
this.fragmentCode += code + '\n';
};
THREE.NodeMaterial.prototype.addVertexNode = function ( code ) {
this.vertexNode += code + '\n';
};
THREE.NodeMaterial.prototype.clearVertexNode = function () {
var code = this.vertexNode;
this.vertexNode = '';
return code;
};
THREE.NodeMaterial.prototype.addFragmentNode = function ( code ) {
this.fragmentNode += code + '\n';
};
THREE.NodeMaterial.prototype.clearFragmentNode = function () {
var code = this.fragmentNode;
this.fragmentNode = '';
return code;
};
THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
prefix = prefix || '';
var code = '';
for ( var i = 0, l = pars.length; i < l; ++ i ) {
var parsType = pars[ i ].type;
var parsName = pars[ i ].name;
var parsValue = pars[ i ].value;
if ( parsType == 't' && parsValue instanceof THREE.CubeTexture ) parsType = 'tc';
var type = THREE.NodeMaterial.types[ parsType ];
if ( type == undefined ) throw new Error( "Node pars " + parsType + " not found." );
code += prefix + ' ' + type + ' ' + parsName + ';\n';
}
return code;
};
THREE.NodeMaterial.prototype.createVertexUniform = function ( type, node, ns, needsUpdate ) {
var uniform = this.createUniform( type, node, ns, needsUpdate );
this.vertexUniform.push( uniform );
this.vertexUniform[ uniform.name ] = uniform;
this.uniforms[ uniform.name ] = uniform;
return uniform;
};
THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, node, ns, needsUpdate ) {
var uniform = this.createUniform( type, node, ns, needsUpdate );
this.fragmentUniform.push( uniform );
this.fragmentUniform[ uniform.name ] = uniform;
this.uniforms[ uniform.name ] = uniform;
return uniform;
};
THREE.NodeMaterial.prototype.getDataNode = function ( uuid ) {
return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
};
THREE.NodeMaterial.prototype.include = function ( builder, node, parent, source ) {
var includes;
node = typeof node === 'string' ? THREE.NodeLib.get( node ) : node;
if ( node instanceof THREE.FunctionNode ) {
includes = this.functions[ builder.shader ] = this.functions[ builder.shader ] || [];
} else if ( node instanceof THREE.ConstNode ) {
includes = this.consts[ builder.shader ] = this.consts[ builder.shader ] || [];
}
var included = includes[ node.name ];
if ( ! included ) {
included = includes[ node.name ] = {
node: node,
deps: []
};
includes.push( included );
included.src = node.build( builder, 'source' );
}
if ( node instanceof THREE.FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
includes[ parent.name ].deps.push( node );
if ( node.includes && node.includes.length ) {
var i = 0;
do {
this.include( builder, node.includes[ i ++ ], parent );
} while ( i < node.includes.length );
}
}
if ( source ) {
included.src = source;
}
};
THREE.NodeMaterial.prototype.toJSON = function ( meta ) {
var isRootObject = ( meta === undefined || typeof meta === 'string' );
if ( isRootObject ) {
meta = {
nodes: {}
};
}
if ( meta && ! meta.materials ) meta.materials = {};
if ( ! meta.materials[ this.uuid ] ) {
var data = {};
data.uuid = this.uuid;
data.type = this.type;
meta.materials[ data.uuid ] = data;
if ( this.name !== "" ) data.name = this.name;
if ( this.blending !== THREE.NormalBlending ) data.blending = this.blending;
if ( this.flatShading === true ) data.flatShading = this.flatShading;
if ( this.side !== THREE.FrontSide ) data.side = this.side;
if ( this.transparent === true ) data.transparent = this.transparent;
data.depthFunc = this.depthFunc;
data.depthTest = this.depthTest;
data.depthWrite = this.depthWrite;
if ( this.wireframe === true ) data.wireframe = this.wireframe;
if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
if ( this.morphTargets === true ) data.morphTargets = true;
if ( this.skinning === true ) data.skinning = true;
data.fog = this.fog;
data.lights = this.lights;
if ( this.visible === false ) data.visible = false;
if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
data.vertex = this.vertex.toJSON( meta ).uuid;
data.fragment = this.fragment.toJSON( meta ).uuid;
}
meta.material = this.uuid;
return meta;
};
// TODO: all nodes
// core
export { GLNode } from './core/GLNode.js';
export { TempNode } from './core/TempNode.js';
export { InputNode } from './core/InputNode.js';
export { ConstNode } from './core/ConstNode.js';
export { VarNode } from './core/VarNode.js';
export { StructNode } from './core/StructNode.js';
export { AttributeNode } from './core/AttributeNode.js';
export { FunctionNode } from './core/FunctionNode.js';
export { FunctionCallNode } from './core/FunctionCallNode.js';
export { NodeLib } from './core/NodeLib.js';
export { NodeUtils } from './core/NodeUtils.js';
export { NodeFrame } from './core/NodeFrame.js';
export { NodeUniform } from './core/NodeUniform.js';
export { NodeBuilder } from './core/NodeBuilder.js';
// inputs
export { IntNode } from './inputs/IntNode.js';
export { FloatNode } from './inputs/FloatNode.js';
export { Vector2Node } from './inputs/Vector2Node.js';
export { Vector3Node } from './inputs/Vector3Node.js';
export { Vector4Node } from './inputs/Vector4Node.js';
export { ColorNode } from './inputs/ColorNode.js';
export { Matrix3Node } from './inputs/Matrix3Node.js';
export { Matrix4Node } from './inputs/Matrix4Node.js';
export { TextureNode } from './inputs/TextureNode.js';
export { CubeTextureNode } from './inputs/CubeTextureNode.js';
export { ScreenNode } from './inputs/ScreenNode.js';
export { ReflectorNode } from './inputs/ReflectorNode.js';
export { PropertyNode } from './inputs/PropertyNode.js';
// accessors
export { UVNode } from './accessors/UVNode.js';
export { ColorsNode } from './accessors/ColorsNode.js';
export { PositionNode } from './accessors/PositionNode.js';
export { NormalNode } from './accessors/NormalNode.js';
export { CameraNode } from './accessors/CameraNode.js';
export { LightNode } from './accessors/LightNode.js';
export { ReflectNode } from './accessors/ReflectNode.js';
export { ScreenUVNode } from './accessors/ScreenUVNode.js';
export { ResolutionNode } from './accessors/ResolutionNode.js';
// math
export { Math1Node } from './math/Math1Node.js';
export { Math2Node } from './math/Math2Node.js';
export { Math3Node } from './math/Math3Node.js';
export { OperatorNode } from './math/OperatorNode.js';
// procedural
export { NoiseNode } from './procedural/NoiseNode.js';
// bsdfs
export { BlinnShininessExponentNode } from './bsdfs/BlinnShininessExponentNode.js';
export { BlinnExponentToRoughnessNode } from './bsdfs/BlinnExponentToRoughnessNode.js';
export { RoughnessToBlinnExponentNode } from './bsdfs/RoughnessToBlinnExponentNode.js';
// misc
export { TextureCubeUVNode } from './misc/TextureCubeUVNode.js';
export { TextureCubeNode } from './misc/TextureCubeNode.js';
export { NormalMapNode } from './misc/NormalMapNode.js';
export { BumpMapNode } from './misc/BumpMapNode.js';
// utils
export { BypassNode } from './utils/BypassNode.js';
export { JoinNode } from './utils/JoinNode.js';
export { SwitchNode } from './utils/SwitchNode.js';
export { TimerNode } from './utils/TimerNode.js';
export { VelocityNode } from './utils/VelocityNode.js';
export { UVTransformNode } from './utils/UVTransformNode.js';
export { MaxMIPLevelNode } from './utils/MaxMIPLevelNode.js';
// effects
export { BlurNode } from './effects/BlurNode.js';
export { ColorAdjustmentNode } from './effects/ColorAdjustmentNode.js';
export { LuminanceNode } from './effects/LuminanceNode.js';
// material nodes
export { RawNode } from './materials/nodes/RawNode.js';
export { SpriteNode } from './materials/nodes/SpriteNode.js';
export { PhongNode } from './materials/nodes/PhongNode.js';
export { StandardNode } from './materials/nodes/StandardNode.js';
export { MeshStandardNode } from './materials/nodes/MeshStandardNode.js';
// materials
export { NodeMaterial } from './materials/NodeMaterial.js';
export { SpriteNodeMaterial } from './materials/SpriteNodeMaterial.js';
export { PhongNodeMaterial } from './materials/PhongNodeMaterial.js';
export { StandardNodeMaterial } from './materials/StandardNodeMaterial.js';
export { MeshStandardNodeMaterial } from './materials/MeshStandardNodeMaterial.js';
// postprocessing
//export { NodePass } from './postprocessing/NodePass.js';
import {
// core
GLNode,
TempNode,
InputNode,
ConstNode,
VarNode,
StructNode,
AttributeNode,
FunctionNode,
FunctionCallNode,
NodeLib,
NodeUtils,
NodeFrame,
NodeUniform,
NodeBuilder,
// inputs
IntNode,
FloatNode,
Vector2Node,
Vector3Node,
Vector4Node,
ColorNode,
Matrix3Node,
Matrix4Node,
TextureNode,
CubeTextureNode,
ScreenNode,
ReflectorNode,
PropertyNode,
// accessors
UVNode,
ColorsNode,
PositionNode,
NormalNode,
CameraNode,
LightNode,
ReflectNode,
ScreenUVNode,
ResolutionNode,
// math
Math1Node,
Math2Node,
Math3Node,
OperatorNode,
// procedural
NoiseNode,
// bsdfs
BlinnShininessExponentNode,
BlinnExponentToRoughnessNode,
RoughnessToBlinnExponentNode,
// misc
TextureCubeUVNode,
TextureCubeNode,
NormalMapNode,
BumpMapNode,
// utils
BypassNode,
JoinNode,
SwitchNode,
TimerNode,
VelocityNode,
UVTransformNode,
MaxMIPLevelNode,
// effects
BlurNode,
ColorAdjustmentNode,
LuminanceNode,
// material nodes
RawNode,
SpriteNode,
PhongNode,
StandardNode,
MeshStandardNode,
// materials
NodeMaterial,
SpriteNodeMaterial,
PhongNodeMaterial,
StandardNodeMaterial,
MeshStandardNodeMaterial
} from './Nodes.js';
// core
THREE.GLNode = GLNode;
THREE.TempNode = TempNode;
THREE.InputNode = InputNode;
THREE.ConstNode = ConstNode;
THREE.VarNode = VarNode;
THREE.StructNode = StructNode;
THREE.AttributeNode = AttributeNode;
THREE.FunctionNode = FunctionNode;
THREE.FunctionCallNode = FunctionCallNode;
THREE.NodeLib = NodeLib;
THREE.NodeUtils = NodeUtils;
THREE.NodeFrame = NodeFrame;
THREE.NodeUniform = NodeUniform;
THREE.NodeBuilder = NodeBuilder;
// inputs
THREE.IntNode = IntNode;
THREE.FloatNode = FloatNode;
THREE.Vector2Node = Vector2Node;
THREE.Vector3Node = Vector3Node;
THREE.Vector4Node = Vector4Node;
THREE.ColorNode = ColorNode;
THREE.Matrix3Node = Matrix3Node;
THREE.Matrix4Node = Matrix4Node;
THREE.TextureNode = TextureNode;
THREE.CubeTextureNode = CubeTextureNode;
THREE.ScreenNode = ScreenNode;
THREE.ReflectorNode = ReflectorNode;
THREE.PropertyNode = PropertyNode;
// accessors
THREE.UVNode = UVNode;
THREE.ColorsNode = ColorsNode;
THREE.PositionNode = PositionNode;
THREE.NormalNode = NormalNode;
THREE.CameraNode = CameraNode;
THREE.LightNode = LightNode;
THREE.ReflectNode = ReflectNode;
THREE.ScreenUVNode = ScreenUVNode;
THREE.ResolutionNode = ResolutionNode;
// math
THREE.Math1Node = Math1Node;
THREE.Math2Node = Math2Node;
THREE.Math3Node = Math3Node;
THREE.OperatorNode = OperatorNode;
// procedural
THREE.NoiseNode = NoiseNode;
// bsdfs
THREE.BlinnShininessExponentNode = BlinnShininessExponentNode;
THREE.BlinnExponentToRoughnessNode = BlinnExponentToRoughnessNode;
THREE.RoughnessToBlinnExponentNode = RoughnessToBlinnExponentNode;
// misc
THREE.TextureCubeUVNode = TextureCubeUVNode;
THREE.TextureCubeNode = TextureCubeNode;
THREE.NormalMapNode = NormalMapNode;
THREE.BumpMapNode = BumpMapNode;
// utils
THREE.BypassNode = BypassNode;
THREE.JoinNode = JoinNode;
THREE.SwitchNode = SwitchNode;
THREE.TimerNode = TimerNode;
THREE.VelocityNode = VelocityNode;
THREE.UVTransformNode = UVTransformNode;
THREE.MaxMIPLevelNode = MaxMIPLevelNode;
// effects
THREE.BlurNode = BlurNode;
THREE.ColorAdjustmentNode = ColorAdjustmentNode;
THREE.LuminanceNode = LuminanceNode;
// material nodes
THREE.RawNode = RawNode;
THREE.SpriteNode = SpriteNode;
THREE.PhongNode = PhongNode;
THREE.StandardNode = StandardNode;
THREE.MeshStandardNode = MeshStandardNode;
// materials
THREE.NodeMaterial = NodeMaterial;
THREE.SpriteNodeMaterial = SpriteNodeMaterial;
THREE.PhongNodeMaterial = PhongNodeMaterial;
THREE.StandardNodeMaterial = StandardNodeMaterial;
THREE.MeshStandardNodeMaterial = MeshStandardNodeMaterial;
/**
* @author sunag / http://www.sunag.com.br/
*/
THREE.VarNode = function ( type ) {
THREE.GLNode.call( this, type );
};
THREE.VarNode.prototype = Object.create( THREE.GLNode.prototype );
THREE.VarNode.prototype.constructor = THREE.VarNode;
THREE.VarNode.prototype.nodeType = "Var";
THREE.VarNode.prototype.getType = function ( builder ) {
return builder.getTypeByFormat( this.type );
};
THREE.VarNode.prototype.generate = function ( builder, output ) {
var varying = builder.material.getVar( this.uuid, this.type );
return builder.format( varying.name, this.getType( builder ), output );
};
THREE.VarNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.out = this.type;
}
return data;
};
......@@ -2,46 +2,66 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.CameraNode = function ( scope, camera ) {
import { TempNode } from '../core/TempNode.js';
import { FunctionNode } from '../core/FunctionNode.js';
import { FloatNode } from '../inputs/FloatNode.js';
import { PositionNode } from '../accessors/PositionNode.js';
function CameraNode( scope, camera ) {
THREE.TempNode.call( this, 'v3' );
TempNode.call( this, 'v3' );
this.setScope( scope || THREE.CameraNode.POSITION );
this.setScope( scope || CameraNode.POSITION );
this.setCamera( camera );
};
THREE.CameraNode.fDepthColor = new THREE.FunctionNode( [
"float depthColor( float mNear, float mFar ) {",
" #ifdef USE_LOGDEPTHBUF_EXT",
" float depth = gl_FragDepthEXT / gl_FragCoord.w;",
" #else",
" float depth = gl_FragCoord.z / gl_FragCoord.w;",
" #endif",
" return 1.0 - smoothstep( mNear, mFar, depth );",
"}"
].join( "\n" ) );
THREE.CameraNode.POSITION = 'position';
THREE.CameraNode.DEPTH = 'depth';
THREE.CameraNode.TO_VERTEX = 'toVertex';
THREE.CameraNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.CameraNode.prototype.constructor = THREE.CameraNode;
THREE.CameraNode.prototype.nodeType = "Camera";
THREE.CameraNode.prototype.setCamera = function ( camera ) {
CameraNode.Nodes = (function() {
var depthColor = new FunctionNode( [
"float depthColor( float mNear, float mFar ) {",
" #ifdef USE_LOGDEPTHBUF_EXT",
" float depth = gl_FragDepthEXT / gl_FragCoord.w;",
" #else",
" float depth = gl_FragCoord.z / gl_FragCoord.w;",
" #endif",
" return 1.0 - smoothstep( mNear, mFar, depth );",
"}"
].join( "\n" ) );
return {
depthColor: depthColor
};
})();
CameraNode.POSITION = 'position';
CameraNode.DEPTH = 'depth';
CameraNode.TO_VERTEX = 'toVertex';
CameraNode.prototype = Object.create( TempNode.prototype );
CameraNode.prototype.constructor = CameraNode;
CameraNode.prototype.nodeType = "Camera";
CameraNode.prototype.setCamera = function ( camera ) {
this.camera = camera;
this.updateFrame = camera !== undefined ? this.onUpdateFrame : undefined;
};
THREE.CameraNode.prototype.setScope = function ( scope ) {
CameraNode.prototype.setScope = function ( scope ) {
switch ( this.scope ) {
case THREE.CameraNode.DEPTH:
case CameraNode.DEPTH:
delete this.near;
delete this.far;
......@@ -54,12 +74,12 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
switch ( scope ) {
case THREE.CameraNode.DEPTH:
case CameraNode.DEPTH:
var camera = this.camera;
this.near = new THREE.FloatNode( camera ? camera.near : 1 );
this.far = new THREE.FloatNode( camera ? camera.far : 1200 );
this.near = new FloatNode( camera ? camera.near : 1 );
this.far = new FloatNode( camera ? camera.far : 1200 );
break;
......@@ -67,12 +87,13 @@ THREE.CameraNode.prototype.setScope = function ( scope ) {
};
THREE.CameraNode.prototype.getType = function ( builder ) {
CameraNode.prototype.getType = function ( builder ) {
switch ( this.scope ) {
case THREE.CameraNode.DEPTH:
return 'fv1';
case CameraNode.DEPTH:
return 'f';
}
......@@ -80,12 +101,13 @@ THREE.CameraNode.prototype.getType = function ( builder ) {
};
THREE.CameraNode.prototype.isUnique = function ( builder ) {
CameraNode.prototype.isUnique = function ( builder ) {
switch ( this.scope ) {
case THREE.CameraNode.DEPTH:
case THREE.CameraNode.TO_VERTEX:
case CameraNode.DEPTH:
case CameraNode.TO_VERTEX:
return true;
}
......@@ -94,11 +116,12 @@ THREE.CameraNode.prototype.isUnique = function ( builder ) {
};
THREE.CameraNode.prototype.isShared = function ( builder ) {
CameraNode.prototype.isShared = function ( builder ) {
switch ( this.scope ) {
case THREE.CameraNode.POSITION:
case CameraNode.POSITION:
return false;
}
......@@ -107,32 +130,29 @@ THREE.CameraNode.prototype.isShared = function ( builder ) {
};
THREE.CameraNode.prototype.generate = function ( builder, output ) {
CameraNode.prototype.generate = function ( builder, output ) {
var material = builder.material;
var result;
switch ( this.scope ) {
case THREE.CameraNode.POSITION:
case CameraNode.POSITION:
result = 'cameraPosition';
break;
case THREE.CameraNode.DEPTH:
var func = THREE.CameraNode.fDepthColor;
case CameraNode.DEPTH:
builder.include( func );
var depthColor = builder.include( CameraNode.Nodes.depthColor );
result = func.name + '(' + this.near.build( builder, 'fv1' ) + ',' + this.far.build( builder, 'fv1' ) + ')';
result = depthColor + '( ' + this.near.build( builder, 'f' ) + ', ' + this.far.build( builder, 'f' ) + ' )';
break;
case THREE.CameraNode.TO_VERTEX:
case CameraNode.TO_VERTEX:
result = 'normalize( ' + new THREE.PositionNode( THREE.PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
result = 'normalize( ' + new PositionNode( PositionNode.WORLD ).build( builder, 'v3' ) + ' - cameraPosition )';
break;
......@@ -142,11 +162,11 @@ THREE.CameraNode.prototype.generate = function ( builder, output ) {
};
THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
CameraNode.prototype.onUpdateFrame = function ( frame ) {
switch ( this.scope ) {
case THREE.CameraNode.DEPTH:
case CameraNode.DEPTH:
var camera = this.camera;
......@@ -159,7 +179,32 @@ THREE.CameraNode.prototype.onUpdateFrame = function ( frame ) {
};
THREE.CameraNode.prototype.toJSON = function ( meta ) {
CameraNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.setScope( source.scope );
if ( source.camera ) {
this.setCamera( source.camera );
}
switch ( source.scope ) {
case CameraNode.DEPTH:
this.near.number = source.near;
this.far.number = source.far;
break;
}
};
CameraNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -173,7 +218,7 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
switch ( this.scope ) {
case THREE.CameraNode.DEPTH:
case CameraNode.DEPTH:
data.near = this.near.value;
data.far = this.far.value;
......@@ -187,3 +232,5 @@ THREE.CameraNode.prototype.toJSON = function ( meta ) {
return data;
};
export { CameraNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
import { NodeLib } from '../core/NodeLib.js';
var vertexDict = [ 'color', 'color2' ],
fragmentDict = [ 'vColor', 'vColor2' ];
function ColorsNode( index ) {
THREE.ColorsNode = function ( index ) {
THREE.TempNode.call( this, 'v4', { shared: false } );
TempNode.call( this, 'v4', { shared: false } );
this.index = index || 0;
};
THREE.ColorsNode.vertexDict = [ 'color', 'color2' ];
THREE.ColorsNode.fragmentDict = [ 'vColor', 'vColor2' ];
THREE.ColorsNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.ColorsNode.prototype.constructor = THREE.ColorsNode;
THREE.ColorsNode.prototype.generate = function ( builder, output ) {
ColorsNode.prototype = Object.create( TempNode.prototype );
ColorsNode.prototype.constructor = ColorsNode;
var material = builder.material;
var result;
ColorsNode.prototype.generate = function ( builder, output ) {
material.requires.color[ this.index ] = true;
builder.requires.color[ this.index ] = true;
if ( builder.isShader( 'vertex' ) ) result = THREE.ColorsNode.vertexDict[ this.index ];
else result = THREE.ColorsNode.fragmentDict[ this.index ];
var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
return builder.format( result, this.getType( builder ), output );
};
THREE.ColorsNode.prototype.toJSON = function ( meta ) {
ColorsNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.index = source.index;
};
ColorsNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -45,3 +52,5 @@ THREE.ColorsNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ColorsNode };
......@@ -2,21 +2,23 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.LightNode = function ( scope ) {
import { TempNode } from '../core/TempNode.js';
THREE.TempNode.call( this, 'v3', { shared: false } );
function LightNode( scope ) {
this.scope = scope || THREE.LightNode.TOTAL;
TempNode.call( this, 'v3', { shared: false } );
this.scope = scope || LightNode.TOTAL;
};
THREE.LightNode.TOTAL = 'total';
LightNode.TOTAL = 'total';
THREE.LightNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.LightNode.prototype.constructor = THREE.LightNode;
THREE.LightNode.prototype.nodeType = "Light";
LightNode.prototype = Object.create( TempNode.prototype );
LightNode.prototype.constructor = LightNode;
LightNode.prototype.nodeType = "Light";
THREE.LightNode.prototype.generate = function ( builder, output ) {
LightNode.prototype.generate = function ( builder, output ) {
if ( builder.isCache( 'light' ) ) {
......@@ -32,7 +34,15 @@ THREE.LightNode.prototype.generate = function ( builder, output ) {
};
THREE.LightNode.prototype.toJSON = function ( meta ) {
LightNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.scope = source.scope;
};
LightNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -47,3 +57,5 @@ THREE.LightNode.prototype.toJSON = function ( meta ) {
return data;
};
export { LightNode };
......@@ -2,27 +2,31 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.NormalNode = function ( scope ) {
import { TempNode } from '../core/TempNode.js';
import { NodeLib } from '../core/NodeLib.js';
function NormalNode( scope ) {
THREE.TempNode.call( this, 'v3' );
TempNode.call( this, 'v3' );
this.scope = scope || THREE.NormalNode.LOCAL;
this.scope = scope || NormalNode.LOCAL;
};
THREE.NormalNode.LOCAL = 'local';
THREE.NormalNode.WORLD = 'world';
THREE.NormalNode.VIEW = 'view';
NormalNode.LOCAL = 'local';
NormalNode.WORLD = 'world';
NormalNode.VIEW = 'view';
THREE.NormalNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.NormalNode.prototype.constructor = THREE.NormalNode;
THREE.NormalNode.prototype.nodeType = "Normal";
NormalNode.prototype = Object.create( TempNode.prototype );
NormalNode.prototype.constructor = NormalNode;
NormalNode.prototype.nodeType = "Normal";
THREE.NormalNode.prototype.isShared = function ( builder ) {
NormalNode.prototype.isShared = function ( builder ) {
switch ( this.scope ) {
case THREE.NormalNode.WORLD:
case NormalNode.WORLD:
return true;
}
......@@ -31,32 +35,29 @@ THREE.NormalNode.prototype.isShared = function ( builder ) {
};
THREE.NormalNode.prototype.generate = function ( builder, output ) {
NormalNode.prototype.generate = function ( builder, output ) {
var material = builder.material;
var result;
switch ( this.scope ) {
case THREE.NormalNode.LOCAL:
case NormalNode.LOCAL:
material.requires.normal = true;
builder.requires.normal = true;
if ( builder.isShader( 'vertex' ) ) result = 'normal';
else result = 'vObjectNormal';
result = builder.isShader( 'vertex' ) ? 'normal' : 'vObjectNormal';
break;
case THREE.NormalNode.WORLD:
material.requires.worldNormal = true;
case NormalNode.WORLD:
if ( builder.isShader( 'vertex' ) ) result = '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz';
else result = 'vWNormal';
builder.requires.worldNormal = true;
result = builder.isShader( 'vertex' ) ? '( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz' : 'vWNormal';
break;
case THREE.NormalNode.VIEW:
case NormalNode.VIEW:
result = 'vNormal';
......@@ -68,7 +69,15 @@ THREE.NormalNode.prototype.generate = function ( builder, output ) {
};
THREE.NormalNode.prototype.toJSON = function ( meta ) {
NormalNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.scope = source.scope;
};
NormalNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -83,3 +92,23 @@ THREE.NormalNode.prototype.toJSON = function ( meta ) {
return data;
};
NodeLib.addKeyword( 'normal', function () {
return new NormalNode();
} );
NodeLib.addKeyword( 'worldNormal', function () {
return new NormalNode( NormalNode.WORLD );
} );
NodeLib.addKeyword( 'viewNormal', function () {
return new NormalNode( NormalNode.VIEW );
} );
export { NormalNode };
......@@ -2,28 +2,32 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.PositionNode = function ( scope ) {
import { TempNode } from '../core/TempNode.js';
import { NodeLib } from '../core/NodeLib.js';
function PositionNode( scope ) {
THREE.TempNode.call( this, 'v3' );
TempNode.call( this, 'v3' );
this.scope = scope || THREE.PositionNode.LOCAL;
this.scope = scope || PositionNode.LOCAL;
};
THREE.PositionNode.LOCAL = 'local';
THREE.PositionNode.WORLD = 'world';
THREE.PositionNode.VIEW = 'view';
THREE.PositionNode.PROJECTION = 'projection';
PositionNode.LOCAL = 'local';
PositionNode.WORLD = 'world';
PositionNode.VIEW = 'view';
PositionNode.PROJECTION = 'projection';
THREE.PositionNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.PositionNode.prototype.constructor = THREE.PositionNode;
THREE.PositionNode.prototype.nodeType = "Position";
PositionNode.prototype = Object.create( TempNode.prototype );
PositionNode.prototype.constructor = PositionNode;
PositionNode.prototype.nodeType = "Position";
THREE.PositionNode.prototype.getType = function ( builder ) {
PositionNode.prototype.getType = function ( builder ) {
switch ( this.scope ) {
case THREE.PositionNode.PROJECTION:
case PositionNode.PROJECTION:
return 'v4';
}
......@@ -32,12 +36,13 @@ THREE.PositionNode.prototype.getType = function ( builder ) {
};
THREE.PositionNode.prototype.isShared = function ( builder ) {
PositionNode.prototype.isShared = function ( builder ) {
switch ( this.scope ) {
case THREE.PositionNode.LOCAL:
case THREE.PositionNode.WORLD:
case PositionNode.LOCAL:
case PositionNode.WORLD:
return false;
}
......@@ -46,42 +51,37 @@ THREE.PositionNode.prototype.isShared = function ( builder ) {
};
THREE.PositionNode.prototype.generate = function ( builder, output ) {
PositionNode.prototype.generate = function ( builder, output ) {
var material = builder.material;
var result;
switch ( this.scope ) {
case THREE.PositionNode.LOCAL:
case PositionNode.LOCAL:
material.requires.position = true;
builder.requires.position = true;
if ( builder.isShader( 'vertex' ) ) result = 'transformed';
else result = 'vPosition';
result = builder.isShader( 'vertex' ) ? 'transformed' : 'vPosition';
break;
case THREE.PositionNode.WORLD:
case PositionNode.WORLD:
material.requires.worldPosition = true;
builder.requires.worldPosition = true;
if ( builder.isShader( 'vertex' ) ) result = 'vWPosition';
else result = 'vWPosition';
result = 'vWPosition';
break;
case THREE.PositionNode.VIEW:
case PositionNode.VIEW:
if ( builder.isShader( 'vertex' ) ) result = '-mvPosition.xyz';
else result = 'vViewPosition';
result = builder.isShader( 'vertex' ) ? '-mvPosition.xyz' : 'vViewPosition';
break;
case THREE.PositionNode.PROJECTION:
case PositionNode.PROJECTION:
if ( builder.isShader( 'vertex' ) ) result = '(projectionMatrix * modelViewMatrix * vec4( position, 1.0 ))';
else result = 'vec4( 0.0 )';
result = builder.isShader( 'vertex' ) ? '( projectionMatrix * modelViewMatrix * vec4( position, 1.0 ) )' : 'vec4( 0.0 )';
break;
......@@ -91,7 +91,15 @@ THREE.PositionNode.prototype.generate = function ( builder, output ) {
};
THREE.PositionNode.prototype.toJSON = function ( meta ) {
PositionNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.scope = source.scope;
};
PositionNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -106,3 +114,23 @@ THREE.PositionNode.prototype.toJSON = function ( meta ) {
return data;
};
NodeLib.addKeyword( 'position', function () {
return new PositionNode();
} );
NodeLib.addKeyword( 'worldPosition', function () {
return new PositionNode( PositionNode.WORLD );
} );
NodeLib.addKeyword( 'viewPosition', function () {
return new PositionNode( NormalNode.VIEW );
} );
export { PositionNode };
......@@ -2,27 +2,30 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.ReflectNode = function ( scope ) {
import { TempNode } from '../core/TempNode.js';
THREE.TempNode.call( this, 'v3', { unique: true } );
function ReflectNode( scope ) {
this.scope = scope || THREE.ReflectNode.CUBE;
TempNode.call( this, 'v3', { unique: true } );
this.scope = scope || ReflectNode.CUBE;
};
THREE.ReflectNode.CUBE = 'cube';
THREE.ReflectNode.SPHERE = 'sphere';
THREE.ReflectNode.VECTOR = 'vector';
ReflectNode.CUBE = 'cube';
ReflectNode.SPHERE = 'sphere';
ReflectNode.VECTOR = 'vector';
THREE.ReflectNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.ReflectNode.prototype.constructor = THREE.ReflectNode;
THREE.ReflectNode.prototype.nodeType = "Reflect";
ReflectNode.prototype = Object.create( TempNode.prototype );
ReflectNode.prototype.constructor = ReflectNode;
ReflectNode.prototype.nodeType = "Reflect";
THREE.ReflectNode.prototype.getType = function ( builder ) {
ReflectNode.prototype.getType = function ( builder ) {
switch ( this.scope ) {
case THREE.ReflectNode.SPHERE:
case ReflectNode.SPHERE:
return 'v2';
}
......@@ -31,47 +34,57 @@ THREE.ReflectNode.prototype.getType = function ( builder ) {
};
THREE.ReflectNode.prototype.generate = function ( builder, output ) {
ReflectNode.prototype.generate = function ( builder, output ) {
var result;
if ( builder.isShader( 'fragment' ) ) {
var result;
switch ( this.scope ) {
switch ( this.scope ) {
case THREE.ReflectNode.VECTOR:
case ReflectNode.VECTOR:
builder.material.addFragmentNode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( vViewPosition ), normal ), viewMatrix );' );
result = 'reflectVec';
result = 'reflectVec';
break;
break;
case THREE.ReflectNode.CUBE:
case ReflectNode.CUBE:
var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
builder.material.addFragmentNode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
builder.addNodeCode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
result = 'reflectCubeVec';
result = 'reflectCubeVec';
break;
break;
case THREE.ReflectNode.SPHERE:
case ReflectNode.SPHERE:
var reflectVec = new THREE.ReflectNode( THREE.ReflectNode.VECTOR ).build( builder, 'v3' );
var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
builder.material.addFragmentNode( 'vec2 reflectSphereVec = normalize((viewMatrix * vec4(' + reflectVec + ', 0.0 )).xyz + vec3(0.0,0.0,1.0)).xy * 0.5 + 0.5;' );
builder.addNodeCode( 'vec2 reflectSphereVec = normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5;' );
result = 'reflectSphereVec';
result = 'reflectSphereVec';
break;
break;
}
}
return builder.format( result, this.getType( this.type ), output );
return builder.format( result, this.getType( this.type ), output );
} else {
console.warn( "THREE.ReflectNode is not compatible with " + builder.shader + " shader." );
return builder.format( 'vec3( 0.0 )', this.type, output );
}
};
THREE.ReflectNode.prototype.toJSON = function ( meta ) {
ReflectNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -86,3 +99,5 @@ THREE.ReflectNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ReflectNode };
......@@ -2,19 +2,21 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.ResolutionNode = function ( renderer ) {
import { Vector2Node } from '../inputs/Vector2Node.js';
function ResolutionNode( renderer ) {
THREE.Vector2Node.call( this );
Vector2Node.call( this );
this.renderer = renderer;
};
THREE.ResolutionNode.prototype = Object.create( THREE.Vector2Node.prototype );
THREE.ResolutionNode.prototype.constructor = THREE.ResolutionNode;
THREE.ResolutionNode.prototype.nodeType = "Resolution";
ResolutionNode.prototype = Object.create( Vector2Node.prototype );
ResolutionNode.prototype.constructor = ResolutionNode;
ResolutionNode.prototype.nodeType = "Resolution";
THREE.ResolutionNode.prototype.updateFrame = function ( frame ) {
ResolutionNode.prototype.updateFrame = function ( frame ) {
var size = this.renderer.getSize(),
pixelRatio = this.renderer.getPixelRatio();
......@@ -24,7 +26,15 @@ THREE.ResolutionNode.prototype.updateFrame = function ( frame ) {
};
THREE.ResolutionNode.prototype.toJSON = function ( meta ) {
ResolutionNode.prototype.copy = function ( source ) {
Vector2Node.prototype.copy.call( this, source );
this.renderer = source.renderer;
};
ResolutionNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -39,3 +49,5 @@ THREE.ResolutionNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ResolutionNode };
......@@ -2,26 +2,27 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.ScreenUVNode = function ( resolution ) {
import { TempNode } from '../core/TempNode.js';
function ScreenUVNode( resolution ) {
THREE.TempNode.call( this, 'v2' );
TempNode.call( this, 'v2' );
this.resolution = resolution;
};
THREE.ScreenUVNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.ScreenUVNode.prototype.constructor = THREE.ScreenUVNode;
THREE.ScreenUVNode.prototype.nodeType = "ScreenUV";
ScreenUVNode.prototype = Object.create( TempNode.prototype );
ScreenUVNode.prototype.constructor = ScreenUVNode;
ScreenUVNode.prototype.nodeType = "ScreenUV";
THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
ScreenUVNode.prototype.generate = function ( builder, output ) {
var material = builder.material;
var result;
if ( builder.isShader( 'fragment' ) ) {
result = '(gl_FragCoord.xy/' + this.resolution.build( builder, 'v2' ) + ')';
result = '( gl_FragCoord.xy / ' + this.resolution.build( builder, 'v2' ) + ')';
} else {
......@@ -35,7 +36,15 @@ THREE.ScreenUVNode.prototype.generate = function ( builder, output ) {
};
THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
ScreenUVNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.resolution = source.resolution;
};
ScreenUVNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -50,3 +59,6 @@ THREE.ScreenUVNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ScreenUVNode };
......@@ -2,36 +2,43 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.UVNode = function ( index ) {
import { TempNode } from '../core/TempNode.js';
import { NodeLib } from '../core/NodeLib.js';
var vertexDict = [ 'uv', 'uv2' ],
fragmentDict = [ 'vUv', 'vUv2' ];
function UVNode( index ) {
THREE.TempNode.call( this, 'v2', { shared: false } );
TempNode.call( this, 'v2', { shared: false } );
this.index = index || 0;
};
THREE.UVNode.vertexDict = [ 'uv', 'uv2' ];
THREE.UVNode.fragmentDict = [ 'vUv', 'vUv2' ];
UVNode.prototype = Object.create( TempNode.prototype );
UVNode.prototype.constructor = UVNode;
UVNode.prototype.nodeType = "UV";
THREE.UVNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.UVNode.prototype.constructor = THREE.UVNode;
THREE.UVNode.prototype.nodeType = "UV";
UVNode.prototype.generate = function ( builder, output ) {
THREE.UVNode.prototype.generate = function ( builder, output ) {
builder.requires.uv[ this.index ] = true;
var material = builder.material;
var result;
material.requires.uv[ this.index ] = true;
if ( builder.isShader( 'vertex' ) ) result = THREE.UVNode.vertexDict[ this.index ];
else result = THREE.UVNode.fragmentDict[ this.index ];
var result = builder.isShader( 'vertex' ) ? vertexDict[ this.index ] : fragmentDict[ this.index ];
return builder.format( result, this.getType( builder ), output );
};
THREE.UVNode.prototype.toJSON = function ( meta ) {
UVNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.index = source.index;
};
UVNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -46,3 +53,17 @@ THREE.UVNode.prototype.toJSON = function ( meta ) {
return data;
};
NodeLib.addKeyword( 'uv', function () {
return new UVNode();
} );
NodeLib.addKeyword( 'uv2', function () {
return new UVNode( 1 );
} );
export { UVNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
function BlinnExponentToRoughnessNode( blinnExponent ) {
TempNode.call( this, 'f' );
this.blinnExponent = blinnExponent || new BlinnShininessExponentNode();
};
BlinnExponentToRoughnessNode.prototype = Object.create( TempNode.prototype );
BlinnExponentToRoughnessNode.prototype.constructor = BlinnExponentToRoughnessNode;
BlinnExponentToRoughnessNode.prototype.nodeType = "BlinnExponentToRoughness";
BlinnExponentToRoughnessNode.prototype.generate = function ( builder, output ) {
return builder.format( 'BlinnExponentToGGXRoughness( ' + this.blinnExponent.build( builder, 'f' ) + ' )', this.type, output );
};
BlinnExponentToRoughnessNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.blinnExponent = source.blinnExponent;
};
BlinnExponentToRoughnessNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.blinnExponent = this.blinnExponent;
}
return data;
};
export { BlinnExponentToRoughnessNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
function BlinnShininessExponentNode() {
TempNode.call( this, 'f' );
};
BlinnShininessExponentNode.prototype = Object.create( TempNode.prototype );
BlinnShininessExponentNode.prototype.constructor = BlinnShininessExponentNode;
BlinnShininessExponentNode.prototype.nodeType = "BlinnShininessExponent";
BlinnShininessExponentNode.prototype.generate = function ( builder, output ) {
if ( builder.isCache( 'clearCoat' ) ) {
return builder.format( 'Material_ClearCoat_BlinnShininessExponent( material )', this.type, output );
} else {
return builder.format( 'Material_BlinnShininessExponent( material )', this.type, output );
}
};
export { BlinnShininessExponentNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
import { FunctionNode } from '../core/FunctionNode.js';
import { MaxMIPLevelNode } from '../utils/MaxMIPLevelNode.js';
import { BlinnShininessExponentNode } from './BlinnShininessExponentNode.js';
function RoughnessToBlinnExponentNode( texture ) {
TempNode.call( this, 'f' );
this.texture = texture;
this.maxMIPLevel = new MaxMIPLevelNode( texture );
this.blinnShininessExponent = new BlinnShininessExponentNode();
};
RoughnessToBlinnExponentNode.Nodes = (function() {
var getSpecularMIPLevel = new FunctionNode( [
// taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
"float getSpecularMIPLevel( const in float blinnShininessExponent, const in float maxMIPLevelScalar ) {",
// float envMapWidth = pow( 2.0, maxMIPLevelScalar );
// float desiredMIPLevel = log2( envMapWidth * sqrt( 3.0 ) ) - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
" float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );",
// clamp to allowable LOD ranges.
" return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );",
"}"
].join( "\n" ) );
return {
getSpecularMIPLevel: getSpecularMIPLevel
};
})();
RoughnessToBlinnExponentNode.prototype = Object.create( TempNode.prototype );
RoughnessToBlinnExponentNode.prototype.constructor = RoughnessToBlinnExponentNode;
RoughnessToBlinnExponentNode.prototype.nodeType = "RoughnessToBlinnExponent";
RoughnessToBlinnExponentNode.prototype.generate = function ( builder, output ) {
if ( builder.isShader( 'fragment' ) ) {
this.maxMIPLevel.texture = this.texture;
var getSpecularMIPLevel = builder.include( RoughnessToBlinnExponentNode.Nodes.getSpecularMIPLevel );
return builder.format( getSpecularMIPLevel + '( ' + this.blinnShininessExponent.build( builder, 'f' ) + ', ' + this.maxMIPLevel.build( builder, 'f' ) + ' )', this.type, output );
} else {
console.warn( "THREE.RoughnessToBlinnExponentNode is not compatible with " + builder.shader + " shader." );
return builder.format( '0.0', this.type, output );
}
};
RoughnessToBlinnExponentNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.texture = source.texture;
};
RoughnessToBlinnExponentNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.texture = this.texture;
}
return data;
};
export { RoughnessToBlinnExponentNode };
......@@ -2,25 +2,27 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.AttributeNode = function ( name, type ) {
import { GLNode } from './GLNode.js';
THREE.GLNode.call( this, type );
function AttributeNode( name, type ) {
GLNode.call( this, type );
this.name = name;
};
THREE.AttributeNode.prototype = Object.create( THREE.GLNode.prototype );
THREE.AttributeNode.prototype.constructor = THREE.AttributeNode;
THREE.AttributeNode.prototype.nodeType = "Attribute";
AttributeNode.prototype = Object.create( GLNode.prototype );
AttributeNode.prototype.constructor = AttributeNode;
AttributeNode.prototype.nodeType = "Attribute";
THREE.AttributeNode.prototype.getAttributeType = function ( builder ) {
AttributeNode.prototype.getAttributeType = function ( builder ) {
return typeof this.type === 'number' ? builder.getConstructorFromLength( this.type ) : this.type;
};
THREE.AttributeNode.prototype.getType = function ( builder ) {
AttributeNode.prototype.getType = function ( builder ) {
var type = this.getAttributeType( builder );
......@@ -28,17 +30,28 @@ THREE.AttributeNode.prototype.getType = function ( builder ) {
};
THREE.AttributeNode.prototype.generate = function ( builder, output ) {
AttributeNode.prototype.generate = function ( builder, output ) {
var type = this.getAttributeType( builder );
var attribute = builder.material.getAttribute( this.name, type );
var attribute = builder.getAttribute( this.name, type ),
name = builder.isShader( 'vertex' ) ? this.name : attribute.varying.name;
console.log( attribute );
return builder.format( name, this.getType( builder ), output );
return builder.format( builder.isShader( 'vertex' ) ? this.name : attribute.varying.name, this.getType( builder ), output );
};
AttributeNode.prototype.copy = function ( source ) {
GLNode.prototype.copy.call( this, source );
this.type = source.type;
};
THREE.AttributeNode.prototype.toJSON = function ( meta ) {
AttributeNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -46,10 +59,12 @@ THREE.AttributeNode.prototype.toJSON = function ( meta ) {
data = this.createJSONNode( meta );
data.out = this.type;
data.type = this.type;
}
return data;
};
export { AttributeNode };
......@@ -2,41 +2,44 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.ConstNode = function ( src, useDefine ) {
import { TempNode } from './TempNode.js';
THREE.TempNode.call( this );
function ConstNode( src, useDefine ) {
this.eval( src || THREE.ConstNode.PI, useDefine );
TempNode.call( this );
this.eval( src || ConstNode.PI, useDefine );
};
THREE.ConstNode.PI = 'PI';
THREE.ConstNode.PI2 = 'PI2';
THREE.ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
THREE.ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
THREE.ConstNode.LOG2 = 'LOG2';
THREE.ConstNode.EPSILON = 'EPSILON';
ConstNode.PI = 'PI';
ConstNode.PI2 = 'PI2';
ConstNode.RECIPROCAL_PI = 'RECIPROCAL_PI';
ConstNode.RECIPROCAL_PI2 = 'RECIPROCAL_PI2';
ConstNode.LOG2 = 'LOG2';
ConstNode.EPSILON = 'EPSILON';
ConstNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
THREE.ConstNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.ConstNode.prototype.constructor = THREE.ConstNode;
THREE.ConstNode.prototype.nodeType = "Const";
ConstNode.prototype = Object.create( TempNode.prototype );
ConstNode.prototype.constructor = ConstNode;
ConstNode.prototype.nodeType = "Const";
THREE.ConstNode.prototype.getType = function ( builder ) {
ConstNode.prototype.getType = function ( builder ) {
return builder.getTypeByFormat( this.type );
};
THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
ConstNode.prototype.eval = function ( src, useDefine ) {
src = ( src || '' ).trim();
this.src = src || '';
var name, type, value = "";
var rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\=?\s?(.*?)(\;|$)/i;
var match = src.match( rDeclaration );
var match = this.src.match( ConstNode.rDeclaration );
this.useDefine = useDefine;
this.useDefine = useDefine || this.src.charAt(0) === '#';
if ( match && match.length > 1 ) {
......@@ -46,8 +49,8 @@ THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
} else {
name = src;
type = 'fv1';
name = this.src;
type = 'f';
}
......@@ -57,7 +60,7 @@ THREE.ConstNode.prototype.eval = function ( src, useDefine ) {
};
THREE.ConstNode.prototype.build = function ( builder, output ) {
ConstNode.prototype.build = function ( builder, output ) {
if ( output === 'source' ) {
......@@ -71,6 +74,10 @@ THREE.ConstNode.prototype.build = function ( builder, output ) {
return 'const ' + this.type + ' ' + this.name + ' = ' + this.value + ';';
} else if (this.useDefine) {
return this.src;
}
} else {
......@@ -83,13 +90,21 @@ THREE.ConstNode.prototype.build = function ( builder, output ) {
};
THREE.ConstNode.prototype.generate = function ( builder, output ) {
ConstNode.prototype.generate = function ( builder, output ) {
return builder.format( this.name, this.getType( builder ), output );
};
THREE.ConstNode.prototype.toJSON = function ( meta ) {
ConstNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.eval( source.src, source.useDefine );
};
ConstNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -97,10 +112,8 @@ THREE.ConstNode.prototype.toJSON = function ( meta ) {
data = this.createJSONNode( meta );
data.name = this.name;
data.out = this.type;
data.src = this.src;
if ( this.value ) data.value = this.value;
if ( data.useDefine === true ) data.useDefine = true;
}
......@@ -108,3 +121,5 @@ THREE.ConstNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ConstNode };
......@@ -2,63 +2,77 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.FunctionCallNode = function ( func, inputs ) {
import { TempNode } from './TempNode.js';
function FunctionCallNode( func, inputs ) {
THREE.TempNode.call( this );
TempNode.call( this );
this.setFunction( func, inputs );
};
THREE.FunctionCallNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.FunctionCallNode.prototype.constructor = THREE.FunctionCallNode;
THREE.FunctionCallNode.prototype.nodeType = "FunctionCall";
FunctionCallNode.prototype = Object.create( TempNode.prototype );
FunctionCallNode.prototype.constructor = FunctionCallNode;
FunctionCallNode.prototype.nodeType = "FunctionCall";
THREE.FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
FunctionCallNode.prototype.setFunction = function ( func, inputs ) {
this.value = func;
this.inputs = inputs || [];
};
THREE.FunctionCallNode.prototype.getFunction = function () {
FunctionCallNode.prototype.getFunction = function () {
return this.value;
};
THREE.FunctionCallNode.prototype.getType = function ( builder ) {
FunctionCallNode.prototype.getType = function ( builder ) {
return this.value.getType( builder );
};
THREE.FunctionCallNode.prototype.generate = function ( builder, output ) {
FunctionCallNode.prototype.generate = function ( builder, output ) {
var material = builder.material;
var type = this.getType( builder ),
func = this.value;
var type = this.getType( builder );
var func = this.value;
var code = func.build( builder, output ) + '(';
var params = [];
var code = func.build( builder, output ) + '( ',
params = [];
for ( var i = 0; i < func.inputs.length; i ++ ) {
var inpt = func.inputs[ i ];
var param = this.inputs[ i ] || this.inputs[ inpt.name ];
var inpt = func.inputs[ i ],
param = this.inputs[ i ] || this.inputs[ inpt.name ];
params.push( param.build( builder, builder.getTypeByFormat( inpt.type ) ) );
}
code += params.join( ',' ) + ')';
code += params.join( ', ' ) + ' )';
return builder.format( code, type, output );
};
THREE.FunctionCallNode.prototype.toJSON = function ( meta ) {
FunctionCallNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
for ( var prop in source.inputs ) {
this.inputs[ prop ] = source.inputs[ prop ];
}
this.value = source.value;
};
FunctionCallNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -76,8 +90,8 @@ THREE.FunctionCallNode.prototype.toJSON = function ( meta ) {
for ( var i = 0; i < func.inputs.length; i ++ ) {
var inpt = func.inputs[ i ];
var node = this.inputs[ i ] || this.inputs[ inpt.name ];
var inpt = func.inputs[ i ],
node = this.inputs[ i ] || this.inputs[ inpt.name ];
data.inputs[ inpt.name ] = node.toJSON( meta ).uuid;
......@@ -90,3 +104,5 @@ THREE.FunctionCallNode.prototype.toJSON = function ( meta ) {
return data;
};
export { FunctionCallNode };
......@@ -3,40 +3,48 @@
* @thanks bhouston / https://clara.io/
*/
THREE.FunctionNode = function ( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions ) {
import { TempNode } from './TempNode.js';
import { NodeLib } from './NodeLib.js';
src = src || '';
function FunctionNode( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions, includes ) {
this.isMethod = typeof includesOrType !== "string";
this.useKeywords = true;
THREE.TempNode.call( this, this.isMethod ? null : includesOrType );
TempNode.call( this, this.isMethod ? null : includesOrType );
if ( this.isMethod ) this.eval( src, includesOrType, extensionsOrIncludes, keywordsOrExtensions );
else this.eval( src, extensionsOrIncludes, keywordsOrExtensions );
if ( this.isMethod ) {
this.eval( src, includesOrType, extensionsOrKeywords, keywordsOrExtensions );
} else {
this.eval( src, includes, keywordsOrExtensions, extensionsOrKeywords );
}
};
THREE.FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s?\((.*?)\)/i;
THREE.FunctionNode.rProperties = /[a-z_0-9]+/ig;
FunctionNode.rDeclaration = /^([a-z_0-9]+)\s([a-z_0-9]+)\s*\((.*?)\)/i;
FunctionNode.rProperties = /[a-z_0-9]+/ig;
THREE.FunctionNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.FunctionNode.prototype.constructor = THREE.FunctionNode;
THREE.FunctionNode.prototype.nodeType = "Function";
FunctionNode.prototype = Object.create( TempNode.prototype );
FunctionNode.prototype.constructor = FunctionNode;
FunctionNode.prototype.nodeType = "Function";
THREE.FunctionNode.prototype.isShared = function ( builder, output ) {
FunctionNode.prototype.isShared = function ( builder, output ) {
return ! this.isMethod;
};
THREE.FunctionNode.prototype.getType = function ( builder ) {
FunctionNode.prototype.getType = function ( builder ) {
return builder.getTypeByFormat( this.type );
};
THREE.FunctionNode.prototype.getInputByName = function ( name ) {
FunctionNode.prototype.getInputByName = function ( name ) {
var i = this.inputs.length;
......@@ -49,7 +57,7 @@ THREE.FunctionNode.prototype.getInputByName = function ( name ) {
};
THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
FunctionNode.prototype.getIncludeByName = function ( name ) {
var i = this.includes.length;
......@@ -62,9 +70,9 @@ THREE.FunctionNode.prototype.getIncludeByName = function ( name ) {
};
THREE.FunctionNode.prototype.generate = function ( builder, output ) {
FunctionNode.prototype.generate = function ( builder, output ) {
var match, offset = 0, src = this.value;
var match, offset = 0, src = this.src;
for ( var i = 0; i < this.includes.length; i ++ ) {
......@@ -74,26 +82,27 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
for ( var ext in this.extensions ) {
builder.material.extensions[ ext ] = true;
builder.extensions[ ext ] = true;
}
while ( match = THREE.FunctionNode.rProperties.exec( this.value ) ) {
while ( match = FunctionNode.rProperties.exec( this.src ) ) {
var prop = match[ 0 ], isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true;
var reference = prop;
var prop = match[ 0 ],
isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true,
reference = prop;
if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && THREE.NodeLib.containsKeyword( prop ) ) ) {
if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) {
var node = this.keywords[ prop ];
if ( ! node ) {
var keyword = THREE.NodeLib.getKeywordData( prop );
var keyword = NodeLib.getKeywordData( prop );
if ( keyword.cache ) node = builder.keywords[ prop ];
node = node || THREE.NodeLib.getKeyword( prop, builder );
node = node || NodeLib.getKeyword( prop, builder );
if ( keyword.cache ) builder.keywords[ prop ] = node;
......@@ -111,9 +120,9 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
}
if ( this.getIncludeByName( reference ) === undefined && THREE.NodeLib.contains( reference ) ) {
if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) {
builder.include( THREE.NodeLib.get( reference ) );
builder.include( NodeLib.get( reference ) );
}
......@@ -131,15 +140,15 @@ THREE.FunctionNode.prototype.generate = function ( builder, output ) {
} else {
return builder.format( "(" + src + ")", this.getType( builder ), output );
return builder.format( '( ' + src + ' )', this.getType( builder ), output );
}
};
THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
FunctionNode.prototype.eval = function ( src, includes, extensions, keywords ) {
src = ( src || '' ).trim();
this.src = src || '';
this.includes = includes || [];
this.extensions = extensions || {};
......@@ -147,7 +156,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
if ( this.isMethod ) {
var match = src.match( THREE.FunctionNode.rDeclaration );
var match = this.src.match( FunctionNode.rDeclaration );
this.inputs = [];
......@@ -156,7 +165,7 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
this.type = match[ 1 ];
this.name = match[ 2 ];
var inputs = match[ 3 ].match( THREE.FunctionNode.rProperties );
var inputs = match[ 3 ].match( FunctionNode.rProperties );
if ( inputs ) {
......@@ -199,11 +208,22 @@ THREE.FunctionNode.prototype.eval = function ( src, includes, extensions, keywor
}
this.value = src;
};
FunctionNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.isMethod = source.isMethod;
this.useKeywords = source.useKeywords;
this.eval( source.src, source.includes, source.extensions, source.keywords );
if ( source.type !== undefined ) this.type = source.type;
};
THREE.FunctionNode.prototype.toJSON = function ( meta ) {
FunctionNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -211,11 +231,11 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
data = this.createJSONNode( meta );
data.src = this.value;
data.src = this.src;
data.isMethod = this.isMethod;
data.useKeywords = this.useKeywords;
if ( ! this.isMethod ) data.out = this.type;
if ( ! this.isMethod ) data.type = this.type;
data.extensions = JSON.parse( JSON.stringify( this.extensions ) );
data.keywords = {};
......@@ -243,3 +263,5 @@ THREE.FunctionNode.prototype.toJSON = function ( meta ) {
return data;
};
export { FunctionNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
function GLNode( type ) {
this.uuid = THREE.Math.generateUUID();
this.name = "";
this.type = type;
this.userData = {};
};
GLNode.prototype = {
constructor: GLNode,
isNode: true,
parse: function ( builder, settings ) {
settings = settings || {};
builder.parsing = true;
this.build( builder.addCache( settings.cache, settings.requires ).addSlot( settings.slot ), 'v4' );
builder.clearVertexNodeCode()
builder.clearFragmentNodeCode();
builder.removeCache().removeSlot();
builder.parsing = false;
},
parseAndBuildCode: function ( builder, output, settings ) {
settings = settings || {};
this.parse( builder, settings );
return this.buildCode( builder, output, settings );
},
buildCode: function ( builder, output, settings ) {
settings = settings || {};
var data = { result: this.build( builder.addCache( settings.cache, settings.context ).addSlot( settings.slot ), output ) };
data.code = builder.clearNodeCode();
builder.removeCache().removeSlot();
return data;
},
build: function ( builder, output, uuid ) {
output = output || this.getType( builder, output );
var data = builder.getNodeData( uuid || this );
if ( builder.parsing ) this.appendDepsNode( builder, data, output );
if ( builder.nodes.indexOf( this ) === - 1 ) {
builder.nodes.push( this );
}
if ( this.updateFrame !== undefined && builder.updaters.indexOf( this ) === - 1 ) {
builder.updaters.push( this );
}
return this.generate( builder, output, uuid );
},
appendDepsNode: function ( builder, data, output ) {
data.deps = ( data.deps || 0 ) + 1;
var outputLen = builder.getTypeLength( output );
if ( outputLen > ( data.outputMax || 0 ) || this.getType( builder, output ) ) {
data.outputMax = outputLen;
data.output = output;
}
},
setName: function( name ) {
this.name = name;
return this;
},
getName: function( builder ) {
return this.name;
},
getType: function ( builder, output ) {
return output === 'sampler2D' || output === 'samplerCube' ? output : this.type;
},
getJSONNode: function ( meta ) {
var isRootObject = ( meta === undefined || typeof meta === 'string' );
if ( ! isRootObject && meta.nodes[ this.uuid ] !== undefined ) {
return meta.nodes[ this.uuid ];
}
},
copy: function ( source ) {
if ( source.name !== undefined ) this.name = source.name;
if ( source.userData !== undefined ) this.userData = JSON.parse( JSON.stringify( source.userData ) );
},
createJSONNode: function ( meta ) {
var isRootObject = ( meta === undefined || typeof meta === 'string' );
var data = {};
if ( typeof this.nodeType !== "string" ) throw new Error( "Node does not allow serialization." );
data.uuid = this.uuid;
data.nodeType = this.nodeType;
if ( this.name !== "" ) data.name = this.name;
if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
if ( ! isRootObject ) {
meta.nodes[ this.uuid ] = data;
}
return data;
},
toJSON: function ( meta ) {
return this.getJSONNode( meta ) || this.createJSONNode( meta );
}
};
export { GLNode };
......@@ -2,34 +2,52 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.InputNode = function ( type, params ) {
import { TempNode } from './TempNode.js';
function InputNode( type, params ) {
params = params || {};
params.shared = params.shared !== undefined ? params.shared : false;
THREE.TempNode.call( this, type, params );
TempNode.call( this, type, params );
this.readonly = false;
};
THREE.InputNode.prototype = Object.create( THREE.TempNode.prototype );
THREE.InputNode.prototype.constructor = THREE.InputNode;
InputNode.prototype = Object.create( TempNode.prototype );
InputNode.prototype.constructor = InputNode;
THREE.InputNode.prototype.isReadonly = function ( builder ) {
InputNode.prototype.isReadonly = function ( builder ) {
return this.readonly;
};
THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
InputNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
if ( source.readonly !== undefined ) this.readonly = source.readonly;
};
InputNode.prototype.createJSONNode = function ( meta ) {
var data = TempNode.prototype.createJSONNode.call( this, meta );
if ( this.readonly === true ) data.readonly = this.readonly;
var material = builder.material;
return data;
};
InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needsUpdate ) {
uuid = builder.getUuid( uuid || this.getUuid() );
type = type || this.getType( builder );
var data = material.getDataNode( uuid ),
var data = builder.getNodeData( uuid ),
readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
if ( readonly ) {
......@@ -42,7 +60,7 @@ THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns,
if ( ! data.vertex ) {
data.vertex = material.createVertexUniform( type, this, ns, needsUpdate );
data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate );
}
......@@ -52,7 +70,7 @@ THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns,
if ( ! data.fragment ) {
data.fragment = material.createFragmentUniform( type, this, ns, needsUpdate );
data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate );
}
......@@ -63,3 +81,5 @@ THREE.InputNode.prototype.generate = function ( builder, output, uuid, type, ns,
}
};
export { InputNode };
此差异已折叠。
/**
* @author sunag / http://www.sunag.com.br/
*/
function NodeFrame( time ) {
this.time = time !== undefined ? time : 0;
this.frameId = 0;
};
NodeFrame.prototype = {
constructor: NodeFrame,
update: function ( delta ) {
++this.frameId;
this.time += delta;
this.delta = delta;
return this;
},
updateNode: function ( node ) {
if ( node.frameId === this.frameId ) return this;
node.updateFrame( this );
node.frameId = this.frameId;
return this;
}
};
export { NodeFrame };
/**
* @author sunag / http://www.sunag.com.br/
*/
var NodeLib = {
nodes: {},
keywords: {},
add: function ( node ) {
this.nodes[ node.name ] = node;
},
addKeyword: function ( name, callback, cache ) {
cache = cache !== undefined ? cache : true;
this.keywords[ name ] = { callback: callback, cache: cache };
},
remove: function ( node ) {
delete this.nodes[ node.name ];
},
removeKeyword: function ( name ) {
delete this.keywords[ name ];
},
get: function ( name ) {
return this.nodes[ name ];
},
getKeyword: function ( name, material ) {
return this.keywords[ name ].callback.call( this, material );
},
getKeywordData: function ( name ) {
return this.keywords[ name ];
},
contains: function ( name ) {
return this.nodes[ name ] != undefined;
},
containsKeyword: function ( name ) {
return this.keywords[ name ] != undefined;
}
};
export { NodeLib };
......@@ -2,7 +2,7 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.NodeUniform = function ( params ) {
function NodeUniform( params ) {
params = params || {};
......@@ -13,17 +13,24 @@ THREE.NodeUniform = function ( params ) {
};
Object.defineProperties( THREE.NodeUniform.prototype, {
Object.defineProperties( NodeUniform.prototype, {
value: {
get: function () {
return this.node.value;
},
set: function ( val ) {
this.node.value = val;
}
}
} );
export { NodeUniform };
/**
* @author sunag / http://www.sunag.com.br/
*/
var NodeUtils = {
elements: [ 'x', 'y', 'z', 'w' ],
addShortcuts: function () {
function applyShortcut( proxy, property, subProperty ) {
if ( subProperty ) {
return {
get: function () {
return this[ proxy ][ property ][ subProperty ];
},
set: function ( val ) {
this[ proxy ][ property ][ subProperty ] = val;
}
};
} else {
return {
get: function () {
return this[ proxy ][ property ];
},
set: function ( val ) {
this[ proxy ][ property ] = val;
}
};
}
}
return function addShortcuts( proto, proxy, list ) {
var shortcuts = {};
for ( var i = 0; i < list.length; ++ i ) {
var data = list[ i ].split( "." ),
property = data[0],
subProperty = data[1];
shortcuts[ property ] = applyShortcut( proxy, property, subProperty );
}
Object.defineProperties( proto, shortcuts );
};
}()
};
export { NodeUtils };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from './TempNode.js';
import { FunctionNode } from './FunctionNode.js';
function StructNode( src ) {
TempNode.call( this);
this.eval( src );
};
StructNode.rDeclaration = /^struct\s*([a-z_0-9]+)\s*{\s*((.|\n)*?)}/img;
StructNode.rProperties = /\s*(\w*?)\s*(\w*?)(\=|\;)/img;
StructNode.prototype = Object.create( TempNode.prototype );
StructNode.prototype.constructor = StructNode;
StructNode.prototype.nodeType = "Struct";
StructNode.prototype.getType = function ( builder ) {
return builder.getTypeByFormat( this.name );
};
StructNode.prototype.getInputByName = function ( name ) {
var i = this.inputs.length;
while ( i -- ) {
if ( this.inputs[ i ].name === name )
return this.inputs[ i ];
}
};
StructNode.prototype.generate = function ( builder, output ) {
if ( output === 'source' ) {
return this.src + ';';
} else {
return builder.format( "(" + src + ")", this.getType( builder ), output );
}
};
StructNode.prototype.eval = function ( src ) {
this.src = src || '';
this.inputs = [];
var declaration = StructNode.rDeclaration.exec( this.src );
if (declaration) {
var properties = declaration[2], matchType, matchName;
while ( matchType = FunctionNode.rProperties.exec( properties ) ) {
matchName = FunctionNode.rProperties.exec( properties )[0];
this.inputs.push( {
name: matchName,
type: matchType
} );
}
this.name = declaration[1];
} else {
this.name = '';
}
this.type = this.name;
};
StructNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.src = this.src;
}
return data;
};
export { StructNode };
......@@ -3,9 +3,11 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.TempNode = function ( type, params ) {
import { GLNode } from './GLNode.js';
THREE.GLNode.call( this, type );
function TempNode( type, params ) {
GLNode.call( this, type );
params = params || {};
......@@ -14,15 +16,13 @@ THREE.TempNode = function ( type, params ) {
};
THREE.TempNode.prototype = Object.create( THREE.GLNode.prototype );
THREE.TempNode.prototype.constructor = THREE.TempNode;
TempNode.prototype = Object.create( GLNode.prototype );
TempNode.prototype.constructor = TempNode;
THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
TempNode.prototype.build = function ( builder, output, uuid, ns ) {
output = output || this.getType( builder );
var material = builder.material;
if ( this.isShared( builder, output ) ) {
var isUnique = this.isUnique( builder, output );
......@@ -35,7 +35,7 @@ THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
uuid = builder.getUuid( uuid || this.getUuid(), ! isUnique );
var data = material.getDataNode( uuid );
var data = builder.getNodeData( uuid );
if ( builder.parsing ) {
......@@ -47,24 +47,24 @@ THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
}
return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
return GLNode.prototype.build.call( this, builder, output, uuid );
} else if ( isUnique ) {
data.name = data.name || THREE.GLNode.prototype.build.call( this, builder, output, uuid );
data.name = data.name || GLNode.prototype.build.call( this, builder, output, uuid );
return data.name;
} else if ( ! builder.optimize || data.deps == 1 ) {
return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
return GLNode.prototype.build.call( this, builder, output, uuid );
}
uuid = this.getUuid( false );
var name = this.getTemp( builder, uuid );
var type = data.output || this.getType( builder );
var name = this.getTemp( builder, uuid ),
type = data.output || this.getType( builder );
if ( name ) {
......@@ -72,12 +72,11 @@ THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
} else {
name = THREE.TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
name = TempNode.prototype.generate.call( this, builder, output, uuid, data.output, ns );
var code = this.generate( builder, type, uuid );
if ( builder.isShader( 'vertex' ) ) material.addVertexNode( name + '=' + code + ';' );
else material.addFragmentNode( name + '=' + code + ';' );
builder.addNodeCode( name + ' = ' + code + ';' );
return builder.format( name, type, output );
......@@ -85,23 +84,23 @@ THREE.TempNode.prototype.build = function ( builder, output, uuid, ns ) {
}
return THREE.GLNode.prototype.build.call( this, builder, output, uuid );
return GLNode.prototype.build.call( this, builder, output, uuid );
};
THREE.TempNode.prototype.isShared = function ( builder, output ) {
TempNode.prototype.isShared = function ( builder, output ) {
return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
};
THREE.TempNode.prototype.isUnique = function ( builder, output ) {
TempNode.prototype.isUnique = function ( builder, output ) {
return this.unique;
};
THREE.TempNode.prototype.getUuid = function ( unique ) {
TempNode.prototype.getUuid = function ( unique ) {
var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
......@@ -111,24 +110,24 @@ THREE.TempNode.prototype.getUuid = function ( unique ) {
};
THREE.TempNode.prototype.getTemp = function ( builder, uuid ) {
TempNode.prototype.getTemp = function ( builder, uuid ) {
uuid = uuid || this.uuid;
var material = builder.material;
if ( builder.isShader( 'vertex' ) && material.vertexTemps[ uuid ] ) return material.vertexTemps[ uuid ].name;
else if ( material.fragmentTemps[ uuid ] ) return material.fragmentTemps[ uuid ].name;
var tempVar = builder.getVars()[uuid]
return tempVar ? tempVar.name : undefined;
};
THREE.TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
uuid = uuid || this.uuid;
if ( builder.isShader( 'vertex' ) ) return builder.material.getVertexTemp( uuid, type || this.getType( builder ), ns ).name;
else return builder.material.getFragmentTemp( uuid, type || this.getType( builder ), ns ).name;
return builder.getTempVar( uuid, type || this.getType( builder ), ns ).name;
};
export { TempNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { GLNode } from './GLNode.js';
function VarNode( type, value ) {
GLNode.call( this, type );
this.value = value;
};
VarNode.prototype = Object.create( GLNode.prototype );
VarNode.prototype.constructor = VarNode;
VarNode.prototype.nodeType = "Var";
VarNode.prototype.getType = function ( builder ) {
return builder.getTypeByFormat( this.type );
};
VarNode.prototype.generate = function ( builder, output ) {
var varying = builder.getVar( this.uuid, this.type );
if ( this.value && builder.isShader( 'vertex' ) ) {
builder.addNodeCode( varying.name + ' = ' + this.value.build( builder, this.getType( builder ) ) + ';' );
}
return builder.format( varying.name, this.getType( builder ), output );
};
VarNode.prototype.copy = function ( source ) {
GLNode.prototype.copy.call( this, source );
this.type = source.type;
this.value = source.value;
};
VarNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.type = this.type;
if ( this.value ) data.value = this.value.toJSON( meta ).uuid;
}
return data;
};
export { VarNode };
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
import { FunctionNode } from '../core/FunctionNode.js';
import { FloatNode } from '../inputs/FloatNode.js';
import { Vector2Node } from '../inputs/Vector2Node.js';
import { UVNode } from '../accessors/UVNode.js';
function BlurNode( value, uv, radius, size ) {
TempNode.call( this, 'v4' );
this.value = value;
this.uv = uv || new UVNode();
this.radius = new Vector2Node( 1, 1 );
this.size = size;
this.blurX = true;
this.blurY = true;
this.horizontal = new FloatNode( 1 / 64 );
this.vertical = new FloatNode( 1 / 64 );
};
BlurNode.Nodes = (function() {
var blurX = new FunctionNode( [
"vec4 blurX( sampler2D texture, vec2 uv, float s ) {",
" vec4 sum = vec4( 0.0 );",
" sum += texture2D( texture, vec2( uv.x - 4.0 * s, uv.y ) ) * 0.051;",
" sum += texture2D( texture, vec2( uv.x - 3.0 * s, uv.y ) ) * 0.0918;",
" sum += texture2D( texture, vec2( uv.x - 2.0 * s, uv.y ) ) * 0.12245;",
" sum += texture2D( texture, vec2( uv.x - 1.0 * s, uv.y ) ) * 0.1531;",
" sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
" sum += texture2D( texture, vec2( uv.x + 1.0 * s, uv.y ) ) * 0.1531;",
" sum += texture2D( texture, vec2( uv.x + 2.0 * s, uv.y ) ) * 0.12245;",
" sum += texture2D( texture, vec2( uv.x + 3.0 * s, uv.y ) ) * 0.0918;",
" sum += texture2D( texture, vec2( uv.x + 4.0 * s, uv.y ) ) * 0.051;",
" return sum;",
"}"
].join( "\n" ) );
var blurY = new FunctionNode( [
"vec4 blurY( sampler2D texture, vec2 uv, float s ) {",
" vec4 sum = vec4( 0.0 );",
" sum += texture2D( texture, vec2( uv.x, uv.y - 4.0 * s ) ) * 0.051;",
" sum += texture2D( texture, vec2( uv.x, uv.y - 3.0 * s ) ) * 0.0918;",
" sum += texture2D( texture, vec2( uv.x, uv.y - 2.0 * s ) ) * 0.12245;",
" sum += texture2D( texture, vec2( uv.x, uv.y - 1.0 * s ) ) * 0.1531;",
" sum += texture2D( texture, vec2( uv.x, uv.y ) ) * 0.1633;",
" sum += texture2D( texture, vec2( uv.x, uv.y + 1.0 * s ) ) * 0.1531;",
" sum += texture2D( texture, vec2( uv.x, uv.y + 2.0 * s ) ) * 0.12245;",
" sum += texture2D( texture, vec2( uv.x, uv.y + 3.0 * s ) ) * 0.0918;",
" sum += texture2D( texture, vec2( uv.x, uv.y + 4.0 * s ) ) * 0.051;",
" return sum;",
"}"
].join( "\n" ) );
return {
blurX: blurX,
blurY: blurY
};
})();
BlurNode.prototype = Object.create( TempNode.prototype );
BlurNode.prototype.constructor = BlurNode;
BlurNode.prototype.nodeType = "Blur";
BlurNode.prototype.updateFrame = function ( frame ) {
if ( this.size ) {
this.horizontal.value = this.radius.x / this.size.x;
this.vertical.value = this.radius.y / this.size.y;
} else if ( this.value.value && this.value.value.image ) {
var image = this.value.value.image;
this.horizontal.value = this.radius.x / image.width;
this.vertical.value = this.radius.y / image.height;
}
};
BlurNode.prototype.generate = function ( builder, output ) {
if ( builder.isShader( 'fragment' ) ) {
var blurCode = [], code;
var blurX = builder.include( BlurNode.Nodes.blurX ),
blurY = builder.include( BlurNode.Nodes.blurY );
if ( this.blurX ) {
blurCode.push( blurX + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.horizontal.build( builder, 'f' ) + ' )' );
}
if ( this.blurY ) {
blurCode.push( blurY + '( ' + this.value.build( builder, 'sampler2D' ) + ', ' + this.uv.build( builder, 'v2' ) + ', ' + this.vertical.build( builder, 'f' ) + ' )' );
}
if ( blurCode.length == 2 ) code = '( ' + blurCode.join( ' + ' ) + '/ 2.0 )';
else if ( blurCode.length ) code = '( ' + blurCode[ 0 ] + ' )';
else code = 'vec4( 0.0 )';
return builder.format( code, this.getType( builder ), output );
} else {
console.warn( "THREE.BlurNode is not compatible with " + builder.shader + " shader." );
return builder.format( 'vec4( 0.0 )', this.getType( builder ), output );
}
};
BlurNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.value = source.value;
this.uv = source.uv;
this.radius = source.radius;
if ( source.size !== undefined ) this.size = new THREE.Vector2( source.size.x, source.size.y );
this.blurX = source.blurX;
this.blurY = source.blurY;
};
BlurNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.value = this.value.toJSON( meta ).uuid;
data.uv = this.uv.toJSON( meta ).uuid;
data.radius = this.radius.toJSON( meta ).uuid;
if ( this.size ) data.size = { x: this.size.x, y: this.size.y };
data.blurX = this.blurX;
data.blurY = this.blurY;
}
return data;
};
export { BlurNode };
\ No newline at end of file
/**
* @author sunag / http://www.sunag.com.br/
*/
import { TempNode } from '../core/TempNode.js';
import { FunctionNode } from '../core/FunctionNode.js';
import { LuminanceNode } from './LuminanceNode.js';
function ColorAdjustmentNode( rgb, adjustment, method ) {
TempNode.call( this, 'v3' );
this.rgb = rgb;
this.adjustment = adjustment;
this.method = method || ColorAdjustmentNode.SATURATION;
};
ColorAdjustmentNode.Nodes = (function() {
var hue = new FunctionNode( [
"vec3 hue(vec3 rgb, float adjustment) {",
" const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
" const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
" vec3 yiq = RGBtoYIQ * rgb;",
" float hue = atan(yiq.z, yiq.y) + adjustment;",
" float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
" return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
"}"
].join( "\n" ) );
var saturation = new FunctionNode( [
// Algorithm from Chapter 16 of OpenGL Shading Language
"vec3 saturation(vec3 rgb, float adjustment) {",
" vec3 intensity = vec3( luminance( rgb ) );",
" return mix( intensity, rgb, adjustment );",
"}"
].join( "\n" ), [ LuminanceNode.Nodes.luminance ] ); // include LuminanceNode function
var vibrance = new FunctionNode( [
// Shader by Evan Wallace adapted by @lo-th
"vec3 vibrance(vec3 rgb, float adjustment) {",
" float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
" float mx = max(rgb.r, max(rgb.g, rgb.b));",
" float amt = (mx - average) * (-3.0 * adjustment);",
" return mix(rgb.rgb, vec3(mx), amt);",
"}"
].join( "\n" ) );
return {
hue: hue,
saturation: saturation,
vibrance: vibrance
};
})();
ColorAdjustmentNode.SATURATION = 'saturation';
ColorAdjustmentNode.HUE = 'hue';
ColorAdjustmentNode.VIBRANCE = 'vibrance';
ColorAdjustmentNode.BRIGHTNESS = 'brightness';
ColorAdjustmentNode.CONTRAST = 'contrast';
ColorAdjustmentNode.prototype = Object.create( TempNode.prototype );
ColorAdjustmentNode.prototype.constructor = ColorAdjustmentNode;
ColorAdjustmentNode.prototype.nodeType = "ColorAdjustment";
ColorAdjustmentNode.prototype.generate = function ( builder, output ) {
var rgb = this.rgb.build( builder, 'v3' ),
adjustment = this.adjustment.build( builder, 'f' );
switch ( this.method ) {
case ColorAdjustmentNode.BRIGHTNESS:
return builder.format( '( ' + rgb + ' + ' + adjustment + ' )', this.getType( builder ), output );
break;
case ColorAdjustmentNode.CONTRAST:
return builder.format( '( ' + rgb + ' * ' + adjustment + ' )', this.getType( builder ), output );
break;
}
var method = builder.include( ColorAdjustmentNode.Nodes[this.method] );
return builder.format( method + '( ' + rgb + ', ' + adjustment + ' )', this.getType( builder ), output );
};
ColorAdjustmentNode.prototype.copy = function ( source ) {
TempNode.prototype.copy.call( this, source );
this.rgb = source.rgb;
this.adjustment = source.adjustment;
this.method = source.method;
};
ColorAdjustmentNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.rgb = this.rgb.toJSON( meta ).uuid;
data.adjustment = this.adjustment.toJSON( meta ).uuid;
data.method = this.method;
}
return data;
};
export { ColorAdjustmentNode };
\ No newline at end of file
此差异已折叠。
......@@ -2,27 +2,38 @@
* @author sunag / http://www.sunag.com.br/
*/
THREE.ColorNode = function ( color ) {
import { InputNode } from '../core/InputNode.js';
import { NodeUtils } from '../core/NodeUtils.js';
THREE.InputNode.call( this, 'c' );
function ColorNode( color, g, b ) {
this.value = new THREE.Color( color || 0 );
InputNode.call( this, 'c' );
this.value = color instanceof THREE.Color ? color : new THREE.Color( color || 0, g, b );
};
THREE.ColorNode.prototype = Object.create( THREE.InputNode.prototype );
THREE.ColorNode.prototype.constructor = THREE.ColorNode;
THREE.ColorNode.prototype.nodeType = "Color";
ColorNode.prototype = Object.create( InputNode.prototype );
ColorNode.prototype.constructor = ColorNode;
ColorNode.prototype.nodeType = "Color";
THREE.NodeMaterial.addShortcuts( THREE.ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
NodeUtils.addShortcuts( ColorNode.prototype, 'value', [ 'r', 'g', 'b' ] );
THREE.ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
ColorNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
return builder.format( "vec3( " + this.r + ", " + this.g + ", " + this.b + " )", type, output );
};
THREE.ColorNode.prototype.toJSON = function ( meta ) {
ColorNode.prototype.copy = function ( source ) {
InputNode.prototype.copy.call( this, source );
this.value.copy( source );
};
ColorNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
......@@ -41,3 +52,5 @@ THREE.ColorNode.prototype.toJSON = function ( meta ) {
return data;
};
export { ColorNode };
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
{"nodes":{"0C853FCD-3CB8-4144-B7A3-F49CED812B61":{"uuid":"0C853FCD-3CB8-4144-B7A3-F49CED812B61","type":"StandardNode","color":"69ACB125-2EAB-4F1C-9A30-C8A2E886BBFB","roughness":"6C740750-9287-47E1-9A13-6A5DE38EF80C","metalness":"290C6194-C8F5-4CAD-8790-098E506DA454","ambient":"E9EC29E0-A9F3-4046-BB0A-C743D5A60528"},"69ACB125-2EAB-4F1C-9A30-C8A2E886BBFB":{"uuid":"69ACB125-2EAB-4F1C-9A30-C8A2E886BBFB","type":"Math3Node","a":"C051EF5D-5269-4A12-AC20-4102377D5D57","b":"02ED8121-2961-4074-ACA7-F386EB1290A1","c":"6C7A71AD-A8CC-4E19-9F26-F9C3B2CD0B8F","method":"mix"},"C051EF5D-5269-4A12-AC20-4102377D5D57":{"uuid":"C051EF5D-5269-4A12-AC20-4102377D5D57","type":"ColorNode","r":1,"g":1,"b":1},"02ED8121-2961-4074-ACA7-F386EB1290A1":{"uuid":"02ED8121-2961-4074-ACA7-F386EB1290A1","type":"Math3Node","a":"8D184736-20DD-4EFB-8BDE-657B0B7E0374","b":"C187F032-F8B4-475F-9317-305998EDA247","c":"962F8B0A-B3DA-4789-AF1B-C47B8FE5A01B","method":"mix"},"8D184736-20DD-4EFB-8BDE-657B0B7E0374":{"uuid":"8D184736-20DD-4EFB-8BDE-657B0B7E0374","type":"ColorNode","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"C187F032-F8B4-475F-9317-305998EDA247":{"uuid":"C187F032-F8B4-475F-9317-305998EDA247","type":"ColorNode","r":1,"g":1,"b":1},"962F8B0A-B3DA-4789-AF1B-C47B8FE5A01B":{"uuid":"962F8B0A-B3DA-4789-AF1B-C47B8FE5A01B","type":"Math1Node","a":"025D9840-CC59-4345-9ECF-58F30EA1BC18","method":"saturate"},"025D9840-CC59-4345-9ECF-58F30EA1BC18":{"uuid":"025D9840-CC59-4345-9ECF-58F30EA1BC18","type":"OperatorNode","a":"F33136D1-4646-46A9-8168-B5F3A7F0E6E7","b":"C1E4ED63-76C4-454E-8042-3FEB65265365","op":"*"},"F33136D1-4646-46A9-8168-B5F3A7F0E6E7":{"uuid":"F33136D1-4646-46A9-8168-B5F3A7F0E6E7","type":"FunctionCallNode","value":"34DE7BBF-67F0-42AE-A92F-E41A88065E2C","inputs":{"p":"29DDBD3C-E348-4E25-B79A-3D75D5576E47","time":"91645353-F838-4ECB-A54F-0B0BD81EF0CE"}},"34DE7BBF-67F0-42AE-A92F-E41A88065E2C":{"uuid":"34DE7BBF-67F0-42AE-A92F-E41A88065E2C","type":"FunctionNode","name":"voronoiLayers","src":"float voronoiLayers(vec2 p, in float time) {\n\tfloat v = 0.0;\n\tfloat a = 0.4;\n\tfor (int i = 0; i < 3; i++) {\n\t\tv += voronoi(p, time) * a;\n\t\tp *= 2.0;\n\t\ta *= 0.5;\n\t}\n\treturn v;\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{},"includes":["3E1A3E00-4D57-4363-B4E8-9AC7FFFD1162"]},"3E1A3E00-4D57-4363-B4E8-9AC7FFFD1162":{"uuid":"3E1A3E00-4D57-4363-B4E8-9AC7FFFD1162","type":"FunctionNode","name":"voronoi","src":"float voronoi(vec2 p, in float time) {\n\tvec2 n = floor(p);\n\tvec2 f = fract(p);\n\tfloat md = 5.0;\n\tvec2 m = vec2(0.0);\n\tfor (int i = -1; i <= 1; i++) {\n\t\tfor (int j = -1; j <= 1; j++) {\n\t\t\tvec2 g = vec2(i, j);\n\t\t\tvec2 o = hash2(n + g);\n\t\t\to = 0.5 + 0.5 * sin(time + 5.038 * o);\n\t\t\tvec2 r = g + o - f;\n\t\t\tfloat d = dot(r, r);\n\t\t\tif (d < md) {\n\t\t\t\tmd = d;\n\t\t\t\tm = n+g+o;\n\t\t\t}\n\t\t}\n\t}\n\treturn md;\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{},"includes":["DFB9B6EF-EAD5-4CA4-B491-CED3B14BDCF3"]},"DFB9B6EF-EAD5-4CA4-B491-CED3B14BDCF3":{"uuid":"DFB9B6EF-EAD5-4CA4-B491-CED3B14BDCF3","type":"FunctionNode","name":"hash2","src":"vec2 hash2(vec2 p) {\n\treturn fract(sin(vec2(dot(p, vec2(123.4, 748.6)), dot(p, vec2(547.3, 659.3))))*5232.85324);\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{}},"29DDBD3C-E348-4E25-B79A-3D75D5576E47":{"uuid":"29DDBD3C-E348-4E25-B79A-3D75D5576E47","type":"OperatorNode","a":"37FCB5FB-D6C5-4D51-B6C9-D65CFF8E56F5","b":"C2939E11-9118-412E-8656-687BDEE7F259","op":"*"},"37FCB5FB-D6C5-4D51-B6C9-D65CFF8E56F5":{"uuid":"37FCB5FB-D6C5-4D51-B6C9-D65CFF8E56F5","type":"SwitchNode","node":"B5FE994F-6069-45C5-87D0-E5BBB5DDAA9B","components":"xz"},"B5FE994F-6069-45C5-87D0-E5BBB5DDAA9B":{"uuid":"B5FE994F-6069-45C5-87D0-E5BBB5DDAA9B","type":"PositionNode","scope":"world"},"C2939E11-9118-412E-8656-687BDEE7F259":{"uuid":"C2939E11-9118-412E-8656-687BDEE7F259","type":"FloatNode","value":0.1},"91645353-F838-4ECB-A54F-0B0BD81EF0CE":{"uuid":"91645353-F838-4ECB-A54F-0B0BD81EF0CE","type":"OperatorNode","a":"4301B6EC-D918-4C2C-A8A4-BDA39B67FC88","b":"2BD5D8FE-FA0F-4B6F-A15D-1C6341A2A49A","op":"*"},"4301B6EC-D918-4C2C-A8A4-BDA39B67FC88":{"uuid":"4301B6EC-D918-4C2C-A8A4-BDA39B67FC88","type":"TimerNode","name":"time","scale":1},"2BD5D8FE-FA0F-4B6F-A15D-1C6341A2A49A":{"uuid":"2BD5D8FE-FA0F-4B6F-A15D-1C6341A2A49A","type":"FloatNode","name":"speed","value":2},"C1E4ED63-76C4-454E-8042-3FEB65265365":{"uuid":"C1E4ED63-76C4-454E-8042-3FEB65265365","type":"FloatNode","value":1.5},"6C7A71AD-A8CC-4E19-9F26-F9C3B2CD0B8F":{"uuid":"6C7A71AD-A8CC-4E19-9F26-F9C3B2CD0B8F","type":"OperatorNode","a":"484155DB-1D71-4C53-BD67-8C7F0D39DFAF","b":"E26C242B-22E1-4CF0-8E6A-9D3EE3009DDF","op":"*"},"484155DB-1D71-4C53-BD67-8C7F0D39DFAF":{"uuid":"484155DB-1D71-4C53-BD67-8C7F0D39DFAF","type":"FloatNode","value":1},"E26C242B-22E1-4CF0-8E6A-9D3EE3009DDF":{"uuid":"E26C242B-22E1-4CF0-8E6A-9D3EE3009DDF","type":"Math1Node","a":"4E7D0932-B617-4DC8-B3EE-CB2F2D0C71D3","method":"saturate"},"4E7D0932-B617-4DC8-B3EE-CB2F2D0C71D3":{"uuid":"4E7D0932-B617-4DC8-B3EE-CB2F2D0C71D3","type":"SwitchNode","node":"121C70CA-F385-46EA-85DF-8803A8DFA94A","components":"y"},"121C70CA-F385-46EA-85DF-8803A8DFA94A":{"uuid":"121C70CA-F385-46EA-85DF-8803A8DFA94A","type":"NormalNode","scope":"world"},"6C740750-9287-47E1-9A13-6A5DE38EF80C":{"uuid":"6C740750-9287-47E1-9A13-6A5DE38EF80C","type":"FloatNode","value":0.5},"290C6194-C8F5-4CAD-8790-098E506DA454":{"uuid":"290C6194-C8F5-4CAD-8790-098E506DA454","type":"FloatNode","value":0.5},"E9EC29E0-A9F3-4046-BB0A-C743D5A60528":{"uuid":"E9EC29E0-A9F3-4046-BB0A-C743D5A60528","type":"OperatorNode","a":"025D9840-CC59-4345-9ECF-58F30EA1BC18","b":"6C7A71AD-A8CC-4E19-9F26-F9C3B2CD0B8F","op":"*"}},"materials":{"F60E153B-B020-448B-8309-FA32A7387B37":{"uuid":"F60E153B-B020-448B-8309-FA32A7387B37","type":"StandardNodeMaterial","depthFunc":3,"depthTest":true,"depthWrite":true,"fog":false,"lights":true,"vertex":"0C853FCD-3CB8-4144-B7A3-F49CED812B61","fragment":"0C853FCD-3CB8-4144-B7A3-F49CED812B61"}},"material":"F60E153B-B020-448B-8309-FA32A7387B37"}
\ No newline at end of file
{"nodes":{"2E025DBF-0C15-444E-B7B8-A6F265A303F7":{"uuid":"2E025DBF-0C15-444E-B7B8-A6F265A303F7","nodeType":"Standard","color":"870FC985-0C7C-4EB1-87F7-C10027A8983C","roughness":"B75EB152-60CF-4274-8674-C4220C3E34A9","metalness":"8C8293C6-9DA8-456B-89AB-803E3479DFBF","ambient":"BF3FBBDC-F57A-4116-B8DC-625F8821C075"},"870FC985-0C7C-4EB1-87F7-C10027A8983C":{"uuid":"870FC985-0C7C-4EB1-87F7-C10027A8983C","nodeType":"Math3","a":"085DEB3A-FD4B-48A4-BA95-7762AA286854","b":"70B5B1FE-9D8D-4E5C-89A1-7F164F2E6DDD","c":"347D0A31-9222-4D15-8B36-1485AD47289E","method":"mix"},"085DEB3A-FD4B-48A4-BA95-7762AA286854":{"uuid":"085DEB3A-FD4B-48A4-BA95-7762AA286854","nodeType":"Color","r":1,"g":1,"b":1},"70B5B1FE-9D8D-4E5C-89A1-7F164F2E6DDD":{"uuid":"70B5B1FE-9D8D-4E5C-89A1-7F164F2E6DDD","nodeType":"Math3","a":"6F0CE905-5A0B-4CBD-AC6B-519C392B45FC","b":"B45D1B51-7344-4713-BC65-B048397A0194","c":"FADA01E1-DBD7-4DC2-9BA1-8276F4DF1ACD","method":"mix"},"6F0CE905-5A0B-4CBD-AC6B-519C392B45FC":{"uuid":"6F0CE905-5A0B-4CBD-AC6B-519C392B45FC","nodeType":"Color","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"B45D1B51-7344-4713-BC65-B048397A0194":{"uuid":"B45D1B51-7344-4713-BC65-B048397A0194","nodeType":"Color","r":1,"g":1,"b":1},"FADA01E1-DBD7-4DC2-9BA1-8276F4DF1ACD":{"uuid":"FADA01E1-DBD7-4DC2-9BA1-8276F4DF1ACD","nodeType":"Math1","a":"13EA9413-2C8B-4B1C-92EE-0A334971AB77","method":"saturate"},"13EA9413-2C8B-4B1C-92EE-0A334971AB77":{"uuid":"13EA9413-2C8B-4B1C-92EE-0A334971AB77","nodeType":"Operator","a":"C5F7404C-B0FD-46DE-95F1-8361904A10B1","b":"72654FD1-36AD-4337-8BA0-B3D867EFB091","op":"*"},"C5F7404C-B0FD-46DE-95F1-8361904A10B1":{"uuid":"C5F7404C-B0FD-46DE-95F1-8361904A10B1","nodeType":"FunctionCall","value":"189E9DE8-6D4A-4763-AC9A-EA4A2608DCF3","inputs":{"p":"9A81F84F-DE02-473E-B5F6-8212D072753F","time":"BE94EED7-4A76-4350-B23E-25E52241C901"}},"189E9DE8-6D4A-4763-AC9A-EA4A2608DCF3":{"uuid":"189E9DE8-6D4A-4763-AC9A-EA4A2608DCF3","nodeType":"Function","name":"voronoiLayers","src":"float voronoiLayers(vec2 p, in float time) {\n\tfloat v = 0.0;\n\tfloat a = 0.4;\n\tfor (int i = 0; i < 3; i++) {\n\t\tv += voronoi(p, time) * a;\n\t\tp *= 2.0;\n\t\ta *= 0.5;\n\t}\n\treturn v;\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{},"includes":["36912270-771A-4D33-BB5E-373EC2E4B72E"]},"36912270-771A-4D33-BB5E-373EC2E4B72E":{"uuid":"36912270-771A-4D33-BB5E-373EC2E4B72E","nodeType":"Function","name":"voronoi","src":"float voronoi(vec2 p, in float time) {\n\tvec2 n = floor(p);\n\tvec2 f = fract(p);\n\tfloat md = 5.0;\n\tvec2 m = vec2(0.0);\n\tfor (int i = -1; i <= 1; i++) {\n\t\tfor (int j = -1; j <= 1; j++) {\n\t\t\tvec2 g = vec2(i, j);\n\t\t\tvec2 o = hash2(n + g);\n\t\t\to = 0.5 + 0.5 * sin(time + 5.038 * o);\n\t\t\tvec2 r = g + o - f;\n\t\t\tfloat d = dot(r, r);\n\t\t\tif (d < md) {\n\t\t\t\tmd = d;\n\t\t\t\tm = n+g+o;\n\t\t\t}\n\t\t}\n\t}\n\treturn md;\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{},"includes":["DEEA59B5-DB78-4936-92C2-0EEBA9E335FD"]},"DEEA59B5-DB78-4936-92C2-0EEBA9E335FD":{"uuid":"DEEA59B5-DB78-4936-92C2-0EEBA9E335FD","nodeType":"Function","name":"hash2","src":"vec2 hash2(vec2 p) {\n\treturn fract(sin(vec2(dot(p, vec2(123.4, 748.6)), dot(p, vec2(547.3, 659.3))))*5232.85324);\n}","isMethod":true,"useKeywords":true,"extensions":{},"keywords":{}},"9A81F84F-DE02-473E-B5F6-8212D072753F":{"uuid":"9A81F84F-DE02-473E-B5F6-8212D072753F","nodeType":"Operator","a":"EAEC9892-ABE1-456C-BD3C-9AB888B3ED0B","b":"1FCD9B13-EABD-47A7-8082-E6F6AA15EC7E","op":"*"},"EAEC9892-ABE1-456C-BD3C-9AB888B3ED0B":{"uuid":"EAEC9892-ABE1-456C-BD3C-9AB888B3ED0B","nodeType":"Switch","node":"DDBEB2EC-65A8-40DF-BB1F-F6EBC4E73107","components":"xz"},"DDBEB2EC-65A8-40DF-BB1F-F6EBC4E73107":{"uuid":"DDBEB2EC-65A8-40DF-BB1F-F6EBC4E73107","nodeType":"Position","scope":"world"},"1FCD9B13-EABD-47A7-8082-E6F6AA15EC7E":{"uuid":"1FCD9B13-EABD-47A7-8082-E6F6AA15EC7E","nodeType":"Float","value":0.1},"BE94EED7-4A76-4350-B23E-25E52241C901":{"uuid":"BE94EED7-4A76-4350-B23E-25E52241C901","nodeType":"Operator","a":"0F6183F0-9601-4208-BFC1-C4D39A524F74","b":"3A74C273-243B-4C6F-AC6F-FD20D6D5DABB","op":"*"},"0F6183F0-9601-4208-BFC1-C4D39A524F74":{"uuid":"0F6183F0-9601-4208-BFC1-C4D39A524F74","nodeType":"Timer","name":"time","scope":"global","scale":1,"useTimeScale":false},"3A74C273-243B-4C6F-AC6F-FD20D6D5DABB":{"uuid":"3A74C273-243B-4C6F-AC6F-FD20D6D5DABB","nodeType":"Float","name":"speed","value":2},"72654FD1-36AD-4337-8BA0-B3D867EFB091":{"uuid":"72654FD1-36AD-4337-8BA0-B3D867EFB091","nodeType":"Float","value":1.5},"347D0A31-9222-4D15-8B36-1485AD47289E":{"uuid":"347D0A31-9222-4D15-8B36-1485AD47289E","nodeType":"Operator","a":"14A35D0F-7E5A-4415-9C8A-73111B070390","b":"13325E4A-A4EE-4D3F-86DF-0EB77BB56DB3","op":"*"},"14A35D0F-7E5A-4415-9C8A-73111B070390":{"uuid":"14A35D0F-7E5A-4415-9C8A-73111B070390","nodeType":"Float","value":1},"13325E4A-A4EE-4D3F-86DF-0EB77BB56DB3":{"uuid":"13325E4A-A4EE-4D3F-86DF-0EB77BB56DB3","nodeType":"Math1","a":"9B0DF80C-F8CE-4122-B63F-E370CFDA47D4","method":"saturate"},"9B0DF80C-F8CE-4122-B63F-E370CFDA47D4":{"uuid":"9B0DF80C-F8CE-4122-B63F-E370CFDA47D4","nodeType":"Switch","node":"481D32AF-83D9-4AE2-954C-6C887FD4B964","components":"y"},"481D32AF-83D9-4AE2-954C-6C887FD4B964":{"uuid":"481D32AF-83D9-4AE2-954C-6C887FD4B964","nodeType":"Normal","scope":"world"},"B75EB152-60CF-4274-8674-C4220C3E34A9":{"uuid":"B75EB152-60CF-4274-8674-C4220C3E34A9","nodeType":"Float","value":0.5},"8C8293C6-9DA8-456B-89AB-803E3479DFBF":{"uuid":"8C8293C6-9DA8-456B-89AB-803E3479DFBF","nodeType":"Float","value":0.5},"BF3FBBDC-F57A-4116-B8DC-625F8821C075":{"uuid":"BF3FBBDC-F57A-4116-B8DC-625F8821C075","nodeType":"Operator","a":"13EA9413-2C8B-4B1C-92EE-0A334971AB77","b":"347D0A31-9222-4D15-8B36-1485AD47289E","op":"*"}},"materials":{"03756E07-B6B1-436D-A28B-1EB9043B2CD2":{"uuid":"03756E07-B6B1-436D-A28B-1EB9043B2CD2","type":"StandardNodeMaterial","fog":false,"lights":true,"vertex":"2E025DBF-0C15-444E-B7B8-A6F265A303F7","fragment":"2E025DBF-0C15-444E-B7B8-A6F265A303F7"}},"material":"03756E07-B6B1-436D-A28B-1EB9043B2CD2"}
\ No newline at end of file
{"nodes":{"159F7363-B727-4F3E-AF62-BE65DFF91C79":{"uuid":"159F7363-B727-4F3E-AF62-BE65DFF91C79","type":"PhongNode","transform":"5C02A7EF-E3B5-45F1-A51D-30FE5FDC7AD5","color":"C2D6FC53-4F88-4C10-9381-922F370FA2E9","specular":"C2D6FC53-4F88-4C10-9381-922F370FA2E9","shininess":"9E2B0686-3575-468B-A490-29AF12C00E18","emissive":"7F1D8D17-7EFB-4C01-A394-B273EE8DE569"},"5C02A7EF-E3B5-45F1-A51D-30FE5FDC7AD5":{"uuid":"5C02A7EF-E3B5-45F1-A51D-30FE5FDC7AD5","type":"OperatorNode","a":"2C5D1792-66CE-4357-BE14-781E4C84DAEB","b":"A7759D0E-31BA-48DB-BF71-9BAACF2D93E4","op":"+"},"2C5D1792-66CE-4357-BE14-781E4C84DAEB":{"uuid":"2C5D1792-66CE-4357-BE14-781E4C84DAEB","type":"PositionNode","scope":"local"},"A7759D0E-31BA-48DB-BF71-9BAACF2D93E4":{"uuid":"A7759D0E-31BA-48DB-BF71-9BAACF2D93E4","type":"OperatorNode","a":"506BDB3C-153F-47A8-89BA-88516F94021B","b":"2DF083C9-1D7F-4366-B2F0-6AB7EDE61F06","op":"*"},"506BDB3C-153F-47A8-89BA-88516F94021B":{"uuid":"506BDB3C-153F-47A8-89BA-88516F94021B","type":"OperatorNode","a":"10F05EC7-E04C-4237-BA21-7F83824C2C0F","b":"CA0D7D12-8386-49B1-AB77-5C8E8A1F7119","op":"*"},"10F05EC7-E04C-4237-BA21-7F83824C2C0F":{"uuid":"10F05EC7-E04C-4237-BA21-7F83824C2C0F","type":"NormalNode","scope":"local"},"CA0D7D12-8386-49B1-AB77-5C8E8A1F7119":{"uuid":"CA0D7D12-8386-49B1-AB77-5C8E8A1F7119","type":"SwitchNode","node":"63E59FC4-8B59-41F5-AD42-46E6DAA7AE22","components":"w"},"63E59FC4-8B59-41F5-AD42-46E6DAA7AE22":{"uuid":"63E59FC4-8B59-41F5-AD42-46E6DAA7AE22","type":"TextureNode","value":"cloud","coord":"BD7395C2-2C5D-42A4-BBED-2CC216067727","project":false},"BD7395C2-2C5D-42A4-BBED-2CC216067727":{"uuid":"BD7395C2-2C5D-42A4-BBED-2CC216067727","type":"OperatorNode","a":"C4DD00B6-A40C-48E2-AA8E-2760F18C3606","b":"65A19E19-D02F-4025-843B-D646F83E5A9D","op":"+"},"C4DD00B6-A40C-48E2-AA8E-2760F18C3606":{"uuid":"C4DD00B6-A40C-48E2-AA8E-2760F18C3606","type":"OperatorNode","a":"1F9A12DF-7D69-41C6-90D5-042E2E53E6CE","b":"D838BBDF-50BF-4572-B8DB-54F7FCB77680","op":"*"},"1F9A12DF-7D69-41C6-90D5-042E2E53E6CE":{"uuid":"1F9A12DF-7D69-41C6-90D5-042E2E53E6CE","type":"TimerNode","name":"time","scale":1},"D838BBDF-50BF-4572-B8DB-54F7FCB77680":{"uuid":"D838BBDF-50BF-4572-B8DB-54F7FCB77680","type":"FloatNode","name":"speed","value":0.2},"65A19E19-D02F-4025-843B-D646F83E5A9D":{"uuid":"65A19E19-D02F-4025-843B-D646F83E5A9D","type":"UVNode","index":0},"2DF083C9-1D7F-4366-B2F0-6AB7EDE61F06":{"uuid":"2DF083C9-1D7F-4366-B2F0-6AB7EDE61F06","type":"FloatNode","value":2},"C2D6FC53-4F88-4C10-9381-922F370FA2E9":{"uuid":"C2D6FC53-4F88-4C10-9381-922F370FA2E9","type":"ColorNode","r":0,"g":0,"b":0},"9E2B0686-3575-468B-A490-29AF12C00E18":{"uuid":"9E2B0686-3575-468B-A490-29AF12C00E18","type":"FloatNode","value":30},"7F1D8D17-7EFB-4C01-A394-B273EE8DE569":{"uuid":"7F1D8D17-7EFB-4C01-A394-B273EE8DE569","type":"Math3Node","a":"769EDCC2-F6E9-424F-AE93-7517F343CFE0","b":"F24EB80D-E7AC-4CFE-83B3-8E6EFA270470","c":"CA0D7D12-8386-49B1-AB77-5C8E8A1F7119","method":"mix"},"769EDCC2-F6E9-424F-AE93-7517F343CFE0":{"uuid":"769EDCC2-F6E9-424F-AE93-7517F343CFE0","type":"ColorNode","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"F24EB80D-E7AC-4CFE-83B3-8E6EFA270470":{"uuid":"F24EB80D-E7AC-4CFE-83B3-8E6EFA270470","type":"ColorNode","r":1,"g":1,"b":1}},"materials":{"A6680195-B61F-4159-903A-8D2C09E56F59":{"uuid":"A6680195-B61F-4159-903A-8D2C09E56F59","type":"PhongNodeMaterial","depthFunc":3,"depthTest":true,"depthWrite":true,"fog":false,"lights":true,"vertex":"159F7363-B727-4F3E-AF62-BE65DFF91C79","fragment":"159F7363-B727-4F3E-AF62-BE65DFF91C79"}},"material":"A6680195-B61F-4159-903A-8D2C09E56F59"}
\ No newline at end of file
{"nodes":{"A9543A4D-4036-4AB3-AEF1-0AE10CFDD4A6":{"uuid":"A9543A4D-4036-4AB3-AEF1-0AE10CFDD4A6","nodeType":"Phong","transform":"A298C150-1E98-425D-8552-CF4690C3238E","color":"DCD2B815-345D-4600-BAFD-BE26925C60E6","specular":"DCD2B815-345D-4600-BAFD-BE26925C60E6","shininess":"5E1EEAA6-F057-4D5F-8607-E9F8265D2B0A","emissive":"BF320EA1-F523-4314-9B87-07E33F39CC6C"},"A298C150-1E98-425D-8552-CF4690C3238E":{"uuid":"A298C150-1E98-425D-8552-CF4690C3238E","nodeType":"Operator","a":"6449FE7E-56E7-490E-9CA9-9F5E9A540AFD","b":"09ECA9C2-8B78-422B-B3DA-2194BCBC5FCA","op":"+"},"6449FE7E-56E7-490E-9CA9-9F5E9A540AFD":{"uuid":"6449FE7E-56E7-490E-9CA9-9F5E9A540AFD","nodeType":"Position","scope":"local"},"09ECA9C2-8B78-422B-B3DA-2194BCBC5FCA":{"uuid":"09ECA9C2-8B78-422B-B3DA-2194BCBC5FCA","nodeType":"Operator","a":"C4573235-0C78-460A-BB35-E41470304BD5","b":"1FF6B149-BCA7-4F37-91E9-8AFA8770F084","op":"*"},"C4573235-0C78-460A-BB35-E41470304BD5":{"uuid":"C4573235-0C78-460A-BB35-E41470304BD5","nodeType":"Operator","a":"0E355E3B-23AB-4225-9477-312295B18436","b":"ABD03824-B7F8-46A4-9006-03FBA06618A9","op":"*"},"0E355E3B-23AB-4225-9477-312295B18436":{"uuid":"0E355E3B-23AB-4225-9477-312295B18436","nodeType":"Normal","scope":"local"},"ABD03824-B7F8-46A4-9006-03FBA06618A9":{"uuid":"ABD03824-B7F8-46A4-9006-03FBA06618A9","nodeType":"Switch","node":"43D31AB8-1DD6-46BE-8969-0668FAB513E2","components":"w"},"43D31AB8-1DD6-46BE-8969-0668FAB513E2":{"uuid":"43D31AB8-1DD6-46BE-8969-0668FAB513E2","nodeType":"Texture","value":"cloud","uv":"273D729E-E18D-47AE-8299-F069FDB6C43A","project":false},"273D729E-E18D-47AE-8299-F069FDB6C43A":{"uuid":"273D729E-E18D-47AE-8299-F069FDB6C43A","nodeType":"Operator","a":"C46D2A54-57A8-4649-AF9B-09D011AF3BFD","b":"C43B8DA9-AFF5-4690-B2EA-3EED061C0662","op":"+"},"C46D2A54-57A8-4649-AF9B-09D011AF3BFD":{"uuid":"C46D2A54-57A8-4649-AF9B-09D011AF3BFD","nodeType":"Operator","a":"F81EC887-A160-455B-B1DE-A0FA2B7FAC36","b":"801913CD-EC7A-47BE-A54C-3D86020B0847","op":"*"},"F81EC887-A160-455B-B1DE-A0FA2B7FAC36":{"uuid":"F81EC887-A160-455B-B1DE-A0FA2B7FAC36","nodeType":"Timer","name":"time","scope":"global","scale":1,"useTimeScale":false},"801913CD-EC7A-47BE-A54C-3D86020B0847":{"uuid":"801913CD-EC7A-47BE-A54C-3D86020B0847","nodeType":"Float","name":"speed","value":0.2},"C43B8DA9-AFF5-4690-B2EA-3EED061C0662":{"uuid":"C43B8DA9-AFF5-4690-B2EA-3EED061C0662","nodeType":"UV","index":0},"1FF6B149-BCA7-4F37-91E9-8AFA8770F084":{"uuid":"1FF6B149-BCA7-4F37-91E9-8AFA8770F084","nodeType":"Float","value":2},"DCD2B815-345D-4600-BAFD-BE26925C60E6":{"uuid":"DCD2B815-345D-4600-BAFD-BE26925C60E6","nodeType":"Color","r":0,"g":0,"b":0},"5E1EEAA6-F057-4D5F-8607-E9F8265D2B0A":{"uuid":"5E1EEAA6-F057-4D5F-8607-E9F8265D2B0A","nodeType":"Float","value":30},"BF320EA1-F523-4314-9B87-07E33F39CC6C":{"uuid":"BF320EA1-F523-4314-9B87-07E33F39CC6C","nodeType":"Math3","a":"F9EA5DC0-2BC8-4C38-A480-1DA3D0680AAE","b":"65010573-EE24-42A3-B32C-3945F3CF2E93","c":"ABD03824-B7F8-46A4-9006-03FBA06618A9","method":"mix"},"F9EA5DC0-2BC8-4C38-A480-1DA3D0680AAE":{"uuid":"F9EA5DC0-2BC8-4C38-A480-1DA3D0680AAE","nodeType":"Color","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"65010573-EE24-42A3-B32C-3945F3CF2E93":{"uuid":"65010573-EE24-42A3-B32C-3945F3CF2E93","nodeType":"Color","r":1,"g":1,"b":1}},"materials":{"BCB86F69-822F-4F9C-838B-70F657904D05":{"uuid":"BCB86F69-822F-4F9C-838B-70F657904D05","type":"PhongNodeMaterial","fog":false,"lights":true,"vertex":"A9543A4D-4036-4AB3-AEF1-0AE10CFDD4A6","fragment":"A9543A4D-4036-4AB3-AEF1-0AE10CFDD4A6"}},"material":"BCB86F69-822F-4F9C-838B-70F657904D05"}
\ No newline at end of file
{"nodes":{"3EE87473-C714-4386-8F5C-B500C9AA1D1A":{"uuid":"3EE87473-C714-4386-8F5C-B500C9AA1D1A","type":"PhongNode","transform":"6FB5A984-1B5D-453E-8840-A7543930894C","color":"81AD4AB3-680C-48A0-978F-3EFB95F86605","specular":"2CCE835E-048F-4338-B634-E2139469B32F","shininess":"5EC6AACA-7A31-4D60-9159-DFAA089D22C9"},"6FB5A984-1B5D-453E-8840-A7543930894C":{"uuid":"6FB5A984-1B5D-453E-8840-A7543930894C","type":"OperatorNode","a":"05C8BE9A-F710-4224-BA9E-CEA5BB40F9B4","b":"1EEC92B8-2C62-4AFF-8069-E9854B0BE4D8","op":"+"},"05C8BE9A-F710-4224-BA9E-CEA5BB40F9B4":{"uuid":"05C8BE9A-F710-4224-BA9E-CEA5BB40F9B4","type":"PositionNode","scope":"local"},"1EEC92B8-2C62-4AFF-8069-E9854B0BE4D8":{"uuid":"1EEC92B8-2C62-4AFF-8069-E9854B0BE4D8","type":"JoinNode","inputs":{"x":"6B70F504-DC84-4C7B-90B2-803F8090A207","y":"B0FA37D3-3719-440D-8483-D0D9B6E84720","z":"03769BCB-952D-4D88-BCA5-2BD5B47746A3"}},"6B70F504-DC84-4C7B-90B2-803F8090A207":{"uuid":"6B70F504-DC84-4C7B-90B2-803F8090A207","type":"FloatNode","value":0},"B0FA37D3-3719-440D-8483-D0D9B6E84720":{"uuid":"B0FA37D3-3719-440D-8483-D0D9B6E84720","type":"OperatorNode","a":"9500D1CB-5406-4045-A243-4247983DBCD1","b":"98D9C3B8-E78E-4DA8-B2FD-0284BCC1D4FC","op":"*"},"9500D1CB-5406-4045-A243-4247983DBCD1":{"uuid":"9500D1CB-5406-4045-A243-4247983DBCD1","type":"SwitchNode","node":"3F4C7A4F-04DC-4545-992B-F08941C80C1F","components":"x"},"3F4C7A4F-04DC-4545-992B-F08941C80C1F":{"uuid":"3F4C7A4F-04DC-4545-992B-F08941C80C1F","type":"Math1Node","a":"CF0B79AB-CCA9-407A-9224-FB94CB21BE05","method":"sin"},"CF0B79AB-CCA9-407A-9224-FB94CB21BE05":{"uuid":"CF0B79AB-CCA9-407A-9224-FB94CB21BE05","type":"OperatorNode","a":"E76CF5B1-1491-4825-8AC1-0794D1B29415","b":"4568D710-E298-4D99-9C20-0A8C05A236F8","op":"+"},"E76CF5B1-1491-4825-8AC1-0794D1B29415":{"uuid":"E76CF5B1-1491-4825-8AC1-0794D1B29415","type":"OperatorNode","a":"99F6A1F9-D304-4A6B-83A3-66D14EBA8218","b":"0D75A0EB-8497-432F-AAAF-08EB1206B9A8","op":"*"},"99F6A1F9-D304-4A6B-83A3-66D14EBA8218":{"uuid":"99F6A1F9-D304-4A6B-83A3-66D14EBA8218","type":"PositionNode","scope":"local"},"0D75A0EB-8497-432F-AAAF-08EB1206B9A8":{"uuid":"0D75A0EB-8497-432F-AAAF-08EB1206B9A8","type":"FloatNode","value":0.4},"4568D710-E298-4D99-9C20-0A8C05A236F8":{"uuid":"4568D710-E298-4D99-9C20-0A8C05A236F8","type":"OperatorNode","a":"0B71AD7A-4526-4178-850A-D8DF269CA68C","b":"EF53D89A-0511-4E8A-A344-241D77B66B9B","op":"*"},"0B71AD7A-4526-4178-850A-D8DF269CA68C":{"uuid":"0B71AD7A-4526-4178-850A-D8DF269CA68C","type":"TimerNode","name":"time","scale":1},"EF53D89A-0511-4E8A-A344-241D77B66B9B":{"uuid":"EF53D89A-0511-4E8A-A344-241D77B66B9B","type":"FloatNode","name":"speed","value":5},"98D9C3B8-E78E-4DA8-B2FD-0284BCC1D4FC":{"uuid":"98D9C3B8-E78E-4DA8-B2FD-0284BCC1D4FC","type":"FloatNode","value":1},"03769BCB-952D-4D88-BCA5-2BD5B47746A3":{"uuid":"03769BCB-952D-4D88-BCA5-2BD5B47746A3","type":"FloatNode","value":0},"81AD4AB3-680C-48A0-978F-3EFB95F86605":{"uuid":"81AD4AB3-680C-48A0-978F-3EFB95F86605","type":"Math3Node","a":"BA150D88-7DFE-4637-A3AE-2A9DFA06E8E7","b":"986A69F3-890D-4AA5-920B-0DE8D583BF09","c":"9500D1CB-5406-4045-A243-4247983DBCD1","method":"mix"},"BA150D88-7DFE-4637-A3AE-2A9DFA06E8E7":{"uuid":"BA150D88-7DFE-4637-A3AE-2A9DFA06E8E7","type":"ColorNode","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"986A69F3-890D-4AA5-920B-0DE8D583BF09":{"uuid":"986A69F3-890D-4AA5-920B-0DE8D583BF09","type":"ColorNode","r":1,"g":1,"b":1},"2CCE835E-048F-4338-B634-E2139469B32F":{"uuid":"2CCE835E-048F-4338-B634-E2139469B32F","type":"ColorNode","r":0.06666666666666667,"g":0.06666666666666667,"b":0.06666666666666667},"5EC6AACA-7A31-4D60-9159-DFAA089D22C9":{"uuid":"5EC6AACA-7A31-4D60-9159-DFAA089D22C9","type":"FloatNode","value":30}},"materials":{"B13AD55D-3685-4737-B4BF-88DEA97128E0":{"uuid":"B13AD55D-3685-4737-B4BF-88DEA97128E0","type":"PhongNodeMaterial","depthFunc":3,"depthTest":true,"depthWrite":true,"fog":false,"lights":true,"vertex":"3EE87473-C714-4386-8F5C-B500C9AA1D1A","fragment":"3EE87473-C714-4386-8F5C-B500C9AA1D1A"}},"material":"B13AD55D-3685-4737-B4BF-88DEA97128E0"}
\ No newline at end of file
{"nodes":{"6BB91CE5-93BA-41BF-88C6-8D03721D4790":{"uuid":"6BB91CE5-93BA-41BF-88C6-8D03721D4790","nodeType":"Phong","transform":"39ED31F8-337B-49A4-9DBE-B43B1F5D180B","color":"1628C697-A4FC-4F02-9746-1CFAC6C6E85B","specular":"D730CA9D-A641-4289-BEF8-348CDD7218B6","shininess":"73E26FEC-C8C2-4E9E-8A4A-209A88156348"},"39ED31F8-337B-49A4-9DBE-B43B1F5D180B":{"uuid":"39ED31F8-337B-49A4-9DBE-B43B1F5D180B","nodeType":"Operator","a":"28F9F474-E77F-4373-BA46-D39F8588A56B","b":"B792813E-FC18-4440-8256-E4030E9D7E3A","op":"+"},"28F9F474-E77F-4373-BA46-D39F8588A56B":{"uuid":"28F9F474-E77F-4373-BA46-D39F8588A56B","nodeType":"Position","scope":"local"},"B792813E-FC18-4440-8256-E4030E9D7E3A":{"uuid":"B792813E-FC18-4440-8256-E4030E9D7E3A","nodeType":"Join","inputs":{"x":"F84376EF-6595-4A0F-AE1C-C183AE4D6392","y":"B7A4178E-D407-4444-9633-741A8C2DAD09","z":"F5785794-4DB6-47F6-AAB6-78DFC896B782"}},"F84376EF-6595-4A0F-AE1C-C183AE4D6392":{"uuid":"F84376EF-6595-4A0F-AE1C-C183AE4D6392","nodeType":"Float","value":0},"B7A4178E-D407-4444-9633-741A8C2DAD09":{"uuid":"B7A4178E-D407-4444-9633-741A8C2DAD09","nodeType":"Operator","a":"526B9B70-CBA1-47E4-9CEF-0CE5A9C4F041","b":"0A80D285-164D-4857-B8B9-30CE5CEC6931","op":"*"},"526B9B70-CBA1-47E4-9CEF-0CE5A9C4F041":{"uuid":"526B9B70-CBA1-47E4-9CEF-0CE5A9C4F041","nodeType":"Switch","node":"575F9E64-5B6D-4A95-9522-3A27919165BF","components":"x"},"575F9E64-5B6D-4A95-9522-3A27919165BF":{"uuid":"575F9E64-5B6D-4A95-9522-3A27919165BF","nodeType":"Math1","a":"4EF09677-828F-4164-BE18-2E8E87A3E969","method":"sin"},"4EF09677-828F-4164-BE18-2E8E87A3E969":{"uuid":"4EF09677-828F-4164-BE18-2E8E87A3E969","nodeType":"Operator","a":"DA817C54-9793-4850-9B90-A087050C6335","b":"CE06CC57-FAFF-4EF7-A0E3-1D71ED0A4EFD","op":"+"},"DA817C54-9793-4850-9B90-A087050C6335":{"uuid":"DA817C54-9793-4850-9B90-A087050C6335","nodeType":"Operator","a":"87304A41-2F18-4A98-92F1-9869F01786D3","b":"ECE889D2-A244-49EF-9ECF-BB685CD84828","op":"*"},"87304A41-2F18-4A98-92F1-9869F01786D3":{"uuid":"87304A41-2F18-4A98-92F1-9869F01786D3","nodeType":"Position","scope":"local"},"ECE889D2-A244-49EF-9ECF-BB685CD84828":{"uuid":"ECE889D2-A244-49EF-9ECF-BB685CD84828","nodeType":"Float","value":0.4},"CE06CC57-FAFF-4EF7-A0E3-1D71ED0A4EFD":{"uuid":"CE06CC57-FAFF-4EF7-A0E3-1D71ED0A4EFD","nodeType":"Operator","a":"D035D8DE-7C30-4372-A5E5-9A03169CFA96","b":"2090FF81-9723-4F1F-BF10-2F223F879DA5","op":"*"},"D035D8DE-7C30-4372-A5E5-9A03169CFA96":{"uuid":"D035D8DE-7C30-4372-A5E5-9A03169CFA96","nodeType":"Timer","name":"time","scope":"global","scale":1,"useTimeScale":false},"2090FF81-9723-4F1F-BF10-2F223F879DA5":{"uuid":"2090FF81-9723-4F1F-BF10-2F223F879DA5","nodeType":"Float","name":"speed","value":5},"0A80D285-164D-4857-B8B9-30CE5CEC6931":{"uuid":"0A80D285-164D-4857-B8B9-30CE5CEC6931","nodeType":"Float","value":1},"F5785794-4DB6-47F6-AAB6-78DFC896B782":{"uuid":"F5785794-4DB6-47F6-AAB6-78DFC896B782","nodeType":"Float","value":0},"1628C697-A4FC-4F02-9746-1CFAC6C6E85B":{"uuid":"1628C697-A4FC-4F02-9746-1CFAC6C6E85B","nodeType":"Math3","a":"48DEB7D7-83ED-4679-BB0B-45A11052AA5F","b":"8C0EACD5-DEA2-431B-B083-06FB93DB7D2A","c":"526B9B70-CBA1-47E4-9CEF-0CE5A9C4F041","method":"mix"},"48DEB7D7-83ED-4679-BB0B-45A11052AA5F":{"uuid":"48DEB7D7-83ED-4679-BB0B-45A11052AA5F","nodeType":"Color","r":0,"g":0.32941176470588235,"b":0.8745098039215686},"8C0EACD5-DEA2-431B-B083-06FB93DB7D2A":{"uuid":"8C0EACD5-DEA2-431B-B083-06FB93DB7D2A","nodeType":"Color","r":1,"g":1,"b":1},"D730CA9D-A641-4289-BEF8-348CDD7218B6":{"uuid":"D730CA9D-A641-4289-BEF8-348CDD7218B6","nodeType":"Color","r":0.06666666666666667,"g":0.06666666666666667,"b":0.06666666666666667},"73E26FEC-C8C2-4E9E-8A4A-209A88156348":{"uuid":"73E26FEC-C8C2-4E9E-8A4A-209A88156348","nodeType":"Float","value":30}},"materials":{"7DCC94F3-82FE-4A67-B5DB-8ACE85789BAA":{"uuid":"7DCC94F3-82FE-4A67-B5DB-8ACE85789BAA","type":"PhongNodeMaterial","fog":false,"lights":true,"vertex":"6BB91CE5-93BA-41BF-88C6-8D03721D4790","fragment":"6BB91CE5-93BA-41BF-88C6-8D03721D4790"}},"material":"7DCC94F3-82FE-4A67-B5DB-8ACE85789BAA"}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册