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

Merge pull request #15663 from sunag/dev-mask

NodeMaterial - Intro to boolean, mask and dissolve example
......@@ -20,6 +20,7 @@ export { NodeBuilder } from './core/NodeBuilder.js';
// inputs
export { BoolNode } from './inputs/BoolNode.js';
export { IntNode } from './inputs/IntNode.js';
export { FloatNode } from './inputs/FloatNode.js';
export { Vector2Node } from './inputs/Vector2Node.js';
......
......@@ -20,6 +20,7 @@ import {
// inputs
BoolNode,
IntNode,
FloatNode,
Vector2Node,
......@@ -132,6 +133,7 @@ THREE.NodeBuilder = NodeBuilder;
// inputs
THREE.BoolNode = BoolNode;
THREE.IntNode = IntNode;
THREE.FloatNode = FloatNode;
THREE.Vector2Node = Vector2Node;
......
......@@ -22,7 +22,8 @@ var elements = NodeUtils.elements,
vec3: 'v3',
vec4: 'v4',
mat4: 'v4',
int: 'i'
int: 'i',
bool: 'b'
},
convertTypeToFormat = {
t: 'sampler2D',
......@@ -821,28 +822,39 @@ NodeBuilder.prototype = {
case 'f <- v2' : return code + '.x';
case 'f <- v3' : return code + '.x';
case 'f <- v4' : return code + '.x';
case 'f <- i' : return 'float( ' + code + ' )';
case 'f <- i' :
case 'f <- b' : return 'float( ' + code + ' )';
case 'v2 <- f' : return 'vec2( ' + code + ' )';
case 'v2 <- v3': return code + '.xy';
case 'v2 <- v4': return code + '.xy';
case 'v2 <- i' : return 'vec2( float( ' + code + ' ) )';
case 'v2 <- i' :
case 'v2 <- b' : return 'vec2( float( ' + code + ' ) )';
case 'v3 <- f' : 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 'v3 <- i' :
case 'v3 <- b' : return 'vec2( float( ' + code + ' ) )';
case 'v4 <- f' : 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 'v4 <- i' :
case 'v4 <- b' : return 'vec4( float( ' + code + ' ) )';
case 'i <- f' : return 'int( ' + code + ' )';
case 'i <- f' :
case 'i <- b' : return 'int( ' + code + ' )';
case 'i <- v2' : return 'int( ' + code + '.x )';
case 'i <- v3' : return 'int( ' + code + '.x )';
case 'i <- v4' : return 'int( ' + code + '.x )';
case 'b <- f' : return '( ' + code + ' != 0.0 )';
case 'b <- v2' : return '( ' + code + ' != vec2( 0.0 ) )';
case 'b <- v3' : return '( ' + code + ' != vec3( 0.0 ) )';
case 'b <- v4' : return '( ' + code + ' != vec4( 0.0 ) )';
case 'b <- i' : return '( ' + code + ' != 0 )';
}
return code;
......
/**
* @author sunag / http://www.sunag.com.br/
*/
import { InputNode } from '../core/InputNode.js';
function BoolNode( value ) {
InputNode.call( this, 'b' );
this.value = Boolean( value );
}
BoolNode.prototype = Object.create( InputNode.prototype );
BoolNode.prototype.constructor = BoolNode;
BoolNode.prototype.nodeType = "Bool";
BoolNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
return builder.format( this.value, type, output );
};
BoolNode.prototype.copy = function ( source ) {
InputNode.prototype.copy.call( this, source );
this.value = source.value;
};
BoolNode.prototype.toJSON = function ( meta ) {
var data = this.getJSONNode( meta );
if ( ! data ) {
data = this.createJSONNode( meta );
data.value = this.value;
if ( this.readonly === true ) data.readonly = true;
}
return data;
};
export { BoolNode };
......@@ -32,6 +32,7 @@ NodeUtils.addShortcuts( PhongNodeMaterial.prototype, 'fragment', [
'ao',
'environment',
'environmentAlpha',
'mask',
'position'
] );
......
......@@ -22,6 +22,7 @@ SpriteNodeMaterial.prototype.constructor = SpriteNodeMaterial;
NodeUtils.addShortcuts( SpriteNodeMaterial.prototype, 'fragment', [
'color',
'alpha',
'mask',
'position',
'spherical'
] );
......
......@@ -34,6 +34,7 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
'shadow',
'ao',
'environment',
'mask',
'position'
] );
......
......@@ -103,6 +103,8 @@ PhongNode.prototype.build = function ( builder ) {
// parse all nodes to reuse generate codes
if ( this.mask ) this.mask.parse( builder );
this.color.parse( builder, { slot: 'color' } );
this.specular.parse( builder );
this.shininess.parse( builder );
......@@ -123,6 +125,8 @@ PhongNode.prototype.build = function ( builder ) {
// build code
var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined;
var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
var specular = this.specular.buildCode( builder, 'c' );
var shininess = this.shininess.buildCode( builder, 'f' );
......@@ -157,8 +161,19 @@ PhongNode.prototype.build = function ( builder ) {
"#include <normal_fragment_begin>",
// prevent undeclared material
" BlinnPhongMaterial material;",
" BlinnPhongMaterial material;"
];
if ( mask ) {
output.push(
mask.code,
'if ( ! ' + mask.result + ' ) discard;'
);
}
output.push(
color.code,
" vec3 diffuseColor = " + color.result + ";",
" ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
......@@ -172,7 +187,7 @@ PhongNode.prototype.build = function ( builder ) {
" float shininess = max( 0.0001, " + shininess.result + " );",
" float specularStrength = 1.0;" // Ignored in MaterialNode ( replace to specular )
];
);
if ( alpha ) {
......@@ -335,6 +350,8 @@ PhongNode.prototype.copy = function ( source ) {
this.specular = source.specular;
this.shininess = source.shininess;
if ( source.mask ) this.mask = source.mask;
if ( source.alpha ) this.alpha = source.alpha;
if ( source.normal ) this.normal = source.normal;
......@@ -370,6 +387,8 @@ PhongNode.prototype.toJSON = function ( meta ) {
data.specular = this.specular.toJSON( meta ).uuid;
data.shininess = this.shininess.toJSON( meta ).uuid;
if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
......
......@@ -123,18 +123,31 @@ SpriteNode.prototype.build = function ( builder ) {
// parse all nodes to reuse generate codes
if ( this.mask ) this.mask.parse( builder );
if ( this.alpha ) this.alpha.parse( builder );
this.color.parse( builder, { slot: 'color' } );
// build code
var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined,
color = this.color.buildCode( builder, 'c', { slot: 'color' } );
var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined,
alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined,
color = this.color.buildCode( builder, 'c', { slot: 'color' } ),
output = [];
if ( mask ) {
output.push(
mask.code,
'if ( ! ' + mask.result + ' ) discard;'
);
}
if ( alpha ) {
output = [
output.push(
alpha.code,
'#ifdef ALPHATEST',
......@@ -143,14 +156,14 @@ SpriteNode.prototype.build = function ( builder ) {
'#endif',
color.code,
"gl_FragColor = vec4( " + color.result + ", " + alpha.result + " );"
];
);
} else {
output = [
output.push(
color.code,
"gl_FragColor = vec4( " + color.result + ", 1.0 );"
];
);
}
......@@ -180,6 +193,8 @@ SpriteNode.prototype.copy = function ( source ) {
if ( source.spherical !== undefined ) this.spherical = source.spherical;
if ( source.mask ) this.mask = source.mask;
if ( source.alpha ) this.alpha = source.alpha;
};
......@@ -202,6 +217,8 @@ SpriteNode.prototype.toJSON = function ( meta ) {
if ( this.spherical === false ) data.spherical = false;
if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
}
......
......@@ -117,6 +117,8 @@ StandardNode.prototype.build = function ( builder ) {
// parse all nodes to reuse generate codes
if ( this.mask ) this.mask.parse( builder );
this.color.parse( builder, { slot: 'color', context: contextGammaOnly } );
this.roughness.parse( builder );
this.metalness.parse( builder );
......@@ -141,6 +143,8 @@ StandardNode.prototype.build = function ( builder ) {
// build code
var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined;
var color = this.color.buildCode( builder, 'c', { slot: 'color', context: contextGammaOnly } );
var roughness = this.roughness.buildCode( builder, 'f' );
var metalness = this.metalness.buildCode( builder, 'f' );
......@@ -194,8 +198,19 @@ StandardNode.prototype.build = function ( builder ) {
// add before: prevent undeclared material
" PhysicalMaterial material;",
" material.diffuseColor = vec3( 1.0 );",
" material.diffuseColor = vec3( 1.0 );"
];
if ( mask ) {
output.push(
mask.code,
'if ( ! ' + mask.result + ' ) discard;'
);
}
output.push(
color.code,
" vec3 diffuseColor = " + color.result + ";",
" ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
......@@ -207,7 +222,7 @@ StandardNode.prototype.build = function ( builder ) {
metalness.code,
" float metalnessFactor = " + metalness.result + ";"
];
);
if ( alpha ) {
......@@ -215,7 +230,7 @@ StandardNode.prototype.build = function ( builder ) {
alpha.code,
'#ifdef ALPHATEST',
'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
' if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
'#endif'
);
......@@ -403,6 +418,8 @@ StandardNode.prototype.copy = function ( source ) {
this.roughness = source.roughness;
this.metalness = source.metalness;
if ( source.mask ) this.mask = source.mask;
if ( source.alpha ) this.alpha = source.alpha;
if ( source.normal ) this.normal = source.normal;
......@@ -442,6 +459,8 @@ StandardNode.prototype.toJSON = function ( meta ) {
data.roughness = this.roughness.toJSON( meta ).uuid;
data.metalness = this.metalness.toJSON( meta ).uuid;
if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
......
......@@ -4,18 +4,18 @@
import { TempNode } from '../core/TempNode.js';
function CondNode( a, b, ifNode, elseNode, op ) {
function CondNode( a, b, op, ifNode, elseNode ) {
TempNode.call( this );
this.a = a;
this.b = b;
this.op = op;
this.ifNode = ifNode;
this.elseNode = elseNode;
this.op = op;
}
CondNode.EQUAL = '==';
......@@ -31,13 +31,22 @@ CondNode.prototype.nodeType = "Cond";
CondNode.prototype.getType = function ( builder ) {
if ( builder.getTypeLength( this.elseNode.getType( builder ) ) > builder.getTypeLength( this.ifNode.getType( builder ) ) ) {
if (this.ifNode) {
var ifType = this.ifNode.getType( builder );
var elseType = this.elseNode.getType( builder );
if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) {
return this.elseNode.getType( builder );
return elseType;
}
}
return this.ifNode.getType( builder );
return ifType;
}
return 'b';
};
......@@ -59,10 +68,20 @@ CondNode.prototype.generate = function ( builder, output ) {
condType = this.getCondType( builder ),
a = this.a.build( builder, condType ),
b = this.b.build( builder, condType ),
ifNode = this.ifNode.build( builder, type ),
elseNode = this.elseNode.build( builder, type );
var code = '( ' + [ a, this.op, b, '?', ifNode, ':', elseNode ].join( ' ' ) + ' )';
code;
if (this.ifNode) {
var ifCode = this.ifNode.build( builder, type ),
elseCode = this.elseNode.build( builder, type );
code = '( ' + [ a, this.op, b, '?', ifCode, ':', elseCode ].join( ' ' ) + ' )';
} else {
code = '( ' + a + ' ' + this.op + ' ' + b + ' )';
}
return builder.format( code, this.getType( builder ), output );
......@@ -75,11 +94,11 @@ CondNode.prototype.copy = function ( source ) {
this.a = source.a;
this.b = source.b;
this.op = source.op;
this.ifNode = source.ifNode;
this.elseNode = source.elseNode;
this.op = source.op;
};
CondNode.prototype.toJSON = function ( meta ) {
......@@ -93,11 +112,11 @@ CondNode.prototype.toJSON = function ( meta ) {
data.a = this.a.toJSON( meta ).uuid;
data.b = this.b.toJSON( meta ).uuid;
data.ifNode = this.ifNode.toJSON( meta ).uuid;
data.elseNode = this.elseNode.toJSON( meta ).uuid;
data.op = this.op;
if ( data.ifNode ) data.ifNode = this.ifNode.toJSON( meta ).uuid;
if ( data.elseNode ) data.elseNode = this.elseNode.toJSON( meta ).uuid;
}
return data;
......
......@@ -12,7 +12,7 @@ function TimerNode( scale, scope, timeScale ) {
this.scale = scale !== undefined ? scale : 1;
this.scope = scope || TimerNode.GLOBAL;
this.timeScale = timeScale !== undefined ? timeScale : this.scale !== 1;
this.timeScale = timeScale !== undefined ? timeScale : scale !== undefined;
}
......
......@@ -180,6 +180,8 @@
'adv / skin-phong': 'skin-phong',
'adv / caustic': 'caustic',
'adv / displace': 'displace',
'adv / dissolve': 'dissolve',
'adv / dissolve-fire': 'dissolve-fire',
'adv / plush': 'plush',
'adv / toon': 'toon',
'adv / camera-depth': 'camera-depth',
......@@ -1321,6 +1323,214 @@
break;
case 'dissolve':
// MATERIAL
mtl = new THREE.StandardNodeMaterial();
var color = new THREE.ColorNode( 0xEEEEEE );
var borderColor = new THREE.ColorNode( 0x0054df );
var threshold = new THREE.FloatNode( .1 );
var borderSize = new THREE.FloatNode( .2 );
var tex = new THREE.TextureNode( getTexture( "cloud" ) );
var texArea = new THREE.SwitchNode( tex, 'w' );
var thresholdBorder = new THREE.Math3Node(
new THREE.OperatorNode( threshold, borderSize, THREE.OperatorNode.ADD ),
threshold,
texArea,
THREE.Math3Node.SMOOTHSTEP
);
var thresholdEmissive = new THREE.OperatorNode(
borderColor,
thresholdBorder,
THREE.OperatorNode.MUL
);
// APPLY
mtl.color = color;
mtl.emissive = thresholdEmissive;
mtl.mask = new THREE.CondNode(
texArea, // a: value
threshold, // b: value
THREE.CondNode.GREATER // condition
);
// GUI
addGui( 'threshold', threshold.value, function ( val ) {
threshold.value = val;
}, false, -.3, 1.3 );
addGui( 'borderSize', borderSize.value, function ( val ) {
borderSize.value = val;
}, false, 0, .5 );
addGui( 'color', color.value.getHex(), function ( val ) {
color.value.setHex( val );
}, true );
addGui( 'borderColor', borderColor.value.getHex(), function ( val ) {
borderColor.value.setHex( val );
}, true );
break;
case 'dissolve-fire':
// MATERIAL
mtl = new THREE.StandardNodeMaterial();
var color = new THREE.ColorNode( 0xEEEEEE );
var fireStartColor = new THREE.ColorNode( 0xF7CA78 );
var fireEndColor = new THREE.ColorNode( 0xFF0000 );
var burnedColor = new THREE.ColorNode( 0x000000 );
var burnedFinalColor = new THREE.ColorNode( 0x000000 );
var threshold = new THREE.FloatNode( .1 );
var fireSize = new THREE.FloatNode( .16 );
var burnedSize = new THREE.FloatNode( .5 );
var timer = new THREE.TimerNode( 0.8 );
var sinCycleInSecs = new THREE.OperatorNode(
timer,
new THREE.ConstNode( THREE.ConstNode.PI2 ),
THREE.OperatorNode.MUL
);
var cycle = new THREE.Math1Node( sinCycleInSecs, THREE.Math1Node.SIN );
// round sin to 0 at 1
cycle = new THREE.OperatorNode( cycle, new THREE.FloatNode( 1 ), THREE.OperatorNode.ADD );
cycle = new THREE.OperatorNode( cycle, new THREE.FloatNode( 2 ), THREE.OperatorNode.DIV );
// offset to +.9
cycle = new THREE.OperatorNode( cycle, new THREE.FloatNode( .9 ), THREE.OperatorNode.ADD );
var tex = new THREE.TextureNode( getTexture( "cloud" ) );
var texArea = new THREE.SwitchNode( tex, 'w' );
var thresholdBorder = new THREE.Math3Node(
new THREE.OperatorNode( threshold, fireSize, THREE.OperatorNode.ADD ),
threshold,
texArea,
THREE.Math3Node.SMOOTHSTEP
);
var fireStartAnimatedColor = new THREE.ColorAdjustmentNode(
fireStartColor,
cycle,
THREE.ColorAdjustmentNode.SATURATION
);
var fireEndAnimatedColor = new THREE.ColorAdjustmentNode(
fireEndColor,
cycle,
THREE.ColorAdjustmentNode.SATURATION
);
var fireColor = new THREE.Math3Node(
fireEndAnimatedColor,
fireStartAnimatedColor,
thresholdBorder,
THREE.Math3Node.MIX
);
var thresholdBurnedBorder = new THREE.Math3Node(
new THREE.OperatorNode( threshold, burnedSize, THREE.OperatorNode.ADD ),
threshold,
texArea,
THREE.Math3Node.SMOOTHSTEP
);
var fireEmissive = new THREE.OperatorNode(
fireColor,
thresholdBorder,
THREE.OperatorNode.MUL
);
var burnedResultColor = new THREE.Math3Node(
color,
burnedColor,
thresholdBurnedBorder,
THREE.Math3Node.MIX
);
// APPLY
mtl.color = burnedResultColor;
mtl.emissive = fireEmissive;
mtl.mask = new THREE.CondNode(
texArea, // a: value
threshold, // b: value
THREE.CondNode.GREATER // condition
);
// GUI
addGui( 'threshold', threshold.value, function ( val ) {
threshold.value = val;
}, false, -.5, 1.5 );
addGui( 'fireSize', fireSize.value, function ( val ) {
fireSize.value = val;
}, false, 0, .5 );
addGui( 'burnedSize', burnedSize.value, function ( val ) {
burnedSize.value = val;
}, false, 0, 1 );
addGui( 'color', color.value.getHex(), function ( val ) {
color.value.setHex( val );
}, true );
addGui( 'fireStartColor', fireStartColor.value.getHex(), function ( val ) {
fireStartColor.value.setHex( val );
}, true );
addGui( 'fireEndColor', fireEndColor.value.getHex(), function ( val ) {
fireEndColor.value.setHex( val );
}, true );
addGui( 'burnedColor', burnedColor.value.getHex(), function ( val ) {
burnedColor.value.setHex( val );
}, true );
addGui( 'timeScale', timer.scale, function ( val ) {
timer.scale = val;
}, false, 0, 2 );
break;
case 'smoke':
// MATERIAL
......@@ -2172,7 +2382,7 @@
ifNode = new THREE.ColorNode( 0x0000FF ),
elseNode = new THREE.ColorNode( 0xFF0000 );
var cond = new THREE.CondNode( a, b, ifNode, elseNode, THREE.CondNode.EQUAL );
var cond = new THREE.CondNode( a, b, THREE.CondNode.EQUAL, ifNode, elseNode );
mtl.color = cond;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册