提交 9ac27dae 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #10859 from donmccurdy/test-parsetrackname

[PropertyBinding] Support for '.' in node names, and unit tests.
{
"accessors": {
"IBM_Armature_Cylinder-skin": {
"bufferView": "bufferView_43",
"byteOffset": 0,
"componentType": 5126,
"count": 2,
"type": "MAT4"
},
"accessor_16": {
"bufferView": "bufferView_44",
"byteOffset": 0,
"byteStride": 0,
"componentType": 5123,
"count": 564,
"type": "SCALAR"
},
"accessor_18": {
"bufferView": "bufferView_45",
"byteOffset": 0,
"byteStride": 12,
"componentType": 5126,
"count": 96,
"max": [
1,
1,
4.57508
],
"min": [
-1,
-1,
-4.57508
],
"type": "VEC3"
},
"accessor_20": {
"bufferView": "bufferView_45",
"byteOffset": 1152,
"byteStride": 12,
"componentType": 5126,
"count": 96,
"max": [
0.998198,
0.998198,
0.688838
],
"min": [
-0.998198,
-0.998198,
-0.644473
],
"type": "VEC3"
},
"accessor_37": {
"bufferView": "bufferView_45",
"byteOffset": 3840,
"byteStride": 16,
"componentType": 5126,
"count": 96,
"max": [
1,
0.261398,
0,
0
],
"min": [
0.738602,
0,
0,
0
],
"type": "VEC4"
},
"accessor_40": {
"bufferView": "bufferView_45",
"byteOffset": 2304,
"byteStride": 16,
"componentType": 5126,
"count": 96,
"max": [
1,
1,
0,
0
],
"min": [
0,
0,
0,
0
],
"type": "VEC4"
},
"animAccessor_0": {
"bufferView": "bufferView_43",
"byteOffset": 128,
"componentType": 5126,
"count": 3,
"type": "SCALAR"
},
"animAccessor_1": {
"bufferView": "bufferView_43",
"byteOffset": 140,
"componentType": 5126,
"count": 3,
"type": "VEC3"
},
"animAccessor_2": {
"bufferView": "bufferView_43",
"byteOffset": 176,
"componentType": 5126,
"count": 3,
"type": "VEC3"
},
"animAccessor_3": {
"bufferView": "bufferView_43",
"byteOffset": 212,
"componentType": 5126,
"count": 3,
"type": "VEC4"
},
"animAccessor_4": {
"bufferView": "bufferView_43",
"byteOffset": 260,
"componentType": 5126,
"count": 3,
"type": "VEC3"
},
"animAccessor_5": {
"bufferView": "bufferView_43",
"byteOffset": 296,
"componentType": 5126,
"count": 3,
"type": "VEC3"
},
"animAccessor_6": {
"bufferView": "bufferView_43",
"byteOffset": 332,
"componentType": 5126,
"count": 3,
"type": "VEC4"
}
},
"animations": {
"animation_0": {
"channels": [
{
"sampler": "animation_0_scale_sampler",
"target": {
"id": "Bone",
"path": "scale"
}
},
{
"sampler": "animation_0_translation_sampler",
"target": {
"id": "Bone",
"path": "translation"
}
},
{
"sampler": "animation_0_rotation_sampler",
"target": {
"id": "Bone",
"path": "rotation"
}
}
],
"parameters": {
"TIME": "animAccessor_0",
"rotation": "animAccessor_3",
"scale": "animAccessor_1",
"translation": "animAccessor_2"
},
"samplers": {
"animation_0_rotation_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "rotation"
},
"animation_0_scale_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "scale"
},
"animation_0_translation_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "translation"
}
}
},
"animation_1": {
"channels": [
{
"sampler": "animation_1_scale_sampler",
"target": {
"id": "Bone_001",
"path": "scale"
}
},
{
"sampler": "animation_1_translation_sampler",
"target": {
"id": "Bone_001",
"path": "translation"
}
},
{
"sampler": "animation_1_rotation_sampler",
"target": {
"id": "Bone_001",
"path": "rotation"
}
}
],
"parameters": {
"TIME": "animAccessor_0",
"rotation": "animAccessor_6",
"scale": "animAccessor_4",
"translation": "animAccessor_5"
},
"samplers": {
"animation_1_rotation_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "rotation"
},
"animation_1_scale_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "scale"
},
"animation_1_translation_sampler": {
"input": "TIME",
"interpolation": "LINEAR",
"output": "translation"
}
}
}
},
"asset": {
"generator": "collada2gltf@027f74366341d569dea42e9a68b7104cc3892054",
"premultipliedAlpha": true,
"profile": {
"api": "WebGL",
"version": "1.0.2"
},
"version": "1.0"
},
"bufferViews": {
"bufferView_43": {
"buffer": "RiggedSimple",
"byteLength": 380,
"byteOffset": 0
},
"bufferView_44": {
"buffer": "RiggedSimple",
"byteLength": 1128,
"byteOffset": 380,
"target": 34963
},
"bufferView_45": {
"buffer": "RiggedSimple",
"byteLength": 5376,
"byteOffset": 1508,
"target": 34962
}
},
"buffers": {
"RiggedSimple": {
"byteLength": 6884,
"type": "arraybuffer",
"uri": "RiggedSimple.bin"
}
},
"materials": {
"Material_001-effect": {
"name": "Material_001",
"technique": "technique0",
"values": {
"ambient": [
0,
0,
0,
1
],
"diffuse": [
0.279635,
0.64,
0.210944,
1
],
"emission": [
0,
0,
0,
1
],
"shininess": 50,
"specular": [
0.5,
0.5,
0.5,
1
]
}
}
},
"meshes": {
"Cylinder-mesh": {
"name": "Cylinder",
"primitives": [
{
"attributes": {
"JOINT": "accessor_40",
"NORMAL": "accessor_20",
"POSITION": "accessor_18",
"WEIGHT": "accessor_37"
},
"indices": "accessor_16",
"material": "Material_001-effect",
"mode": 4
}
]
}
},
"nodes": {
"Armature": {
"children": [
"Bone"
],
"matrix": [
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1
],
"name": "Armature"
},
"Bone": {
"children": [
"Bone_001"
],
"jointName": "Bone",
"name": "Bone",
"rotation": [
0.70474,
0,
0,
0.709465
],
"scale": [
1,
1,
1
],
"translation": [
0,
-3.15606e-007,
-4.18033
]
},
"Bone_001": {
"children": [],
"jointName": "Bone_001",
"name": "Bone.001",
"rotation": [
0.00205211,
9.94789e-008,
0.000291371,
0.999998
],
"scale": [
1,
1,
1
],
"translation": [
0,
4.18717,
0
]
},
"Cylinder": {
"children": [],
"matrix": [
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1
],
"meshes": [
"Cylinder-mesh"
],
"name": "Cylinder",
"skeletons": [
"Bone"
],
"skin": "Armature_Cylinder-skin"
},
"node_4": {
"children": [
"Armature",
"Cylinder"
],
"matrix": [
1,
0,
0,
0,
0,
0,
-1,
0,
0,
1,
0,
0,
0,
0,
0,
1
],
"name": "Y_UP_Transform"
}
},
"programs": {
"program_0": {
"attributes": [
"a_joint",
"a_normal",
"a_position",
"a_weight"
],
"fragmentShader": "RiggedSimple0FS",
"vertexShader": "RiggedSimple0VS"
}
},
"scene": "defaultScene",
"scenes": {
"defaultScene": {
"nodes": [
"node_4"
]
}
},
"shaders": {
"RiggedSimple0FS": {
"type": 35632,
"uri": "RiggedSimple0FS.glsl"
},
"RiggedSimple0VS": {
"type": 35633,
"uri": "RiggedSimple0VS.glsl"
}
},
"skins": {
"Armature_Cylinder-skin": {
"bindShapeMatrix": [
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1
],
"inverseBindMatrices": "IBM_Armature_Cylinder-skin",
"jointNames": [
"Bone",
"Bone_001"
],
"name": "Armature"
}
},
"techniques": {
"technique0": {
"attributes": {
"a_joint": "joint",
"a_normal": "normal",
"a_position": "position",
"a_weight": "weight"
},
"parameters": {
"ambient": {
"type": 35666
},
"diffuse": {
"type": 35666
},
"emission": {
"type": 35666
},
"joint": {
"semantic": "JOINT",
"type": 35666
},
"jointMat": {
"count": 2,
"semantic": "JOINTMATRIX",
"type": 35676
},
"modelViewMatrix": {
"semantic": "MODELVIEW",
"type": 35676
},
"normal": {
"semantic": "NORMAL",
"type": 35665
},
"normalMatrix": {
"semantic": "MODELVIEWINVERSETRANSPOSE",
"type": 35675
},
"position": {
"semantic": "POSITION",
"type": 35665
},
"projectionMatrix": {
"semantic": "PROJECTION",
"type": 35676
},
"shininess": {
"type": 5126
},
"specular": {
"type": 35666
},
"weight": {
"semantic": "WEIGHT",
"type": 35666
}
},
"program": "program_0",
"states": {
"enable": [
2929,
2884
]
},
"uniforms": {
"u_ambient": "ambient",
"u_diffuse": "diffuse",
"u_emission": "emission",
"u_jointMat": "jointMat",
"u_modelViewMatrix": "modelViewMatrix",
"u_normalMatrix": "normalMatrix",
"u_projectionMatrix": "projectionMatrix",
"u_shininess": "shininess",
"u_specular": "specular"
}
}
}
}
\ No newline at end of file
precision highp float;
varying vec3 v_normal;
uniform vec4 u_ambient;
uniform vec4 u_diffuse;
uniform vec4 u_emission;
uniform vec4 u_specular;
uniform float u_shininess;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = u_diffuse;
emission = u_emission;
specular = u_specular;
diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.);
color.xyz += diffuse.xyz;
color.xyz += emission.xyz;
color = vec4(color.rgb * diffuse.a, diffuse.a);
gl_FragColor = color;
}
precision highp float;
attribute vec3 a_position;
attribute vec3 a_normal;
varying vec3 v_normal;
attribute vec4 a_joint;
attribute vec4 a_weight;
uniform mat4 u_jointMat[2];
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
void main(void) {
mat4 skinMat = a_weight.x * u_jointMat[int(a_joint.x)];
skinMat += a_weight.y * u_jointMat[int(a_joint.y)];
skinMat += a_weight.z * u_jointMat[int(a_joint.z)];
skinMat += a_weight.w * u_jointMat[int(a_joint.w)];
vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);
v_normal = u_normalMatrix * mat3(skinMat)* a_normal;
gl_Position = u_projectionMatrix * pos;
}
......@@ -407,6 +407,15 @@
shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
},
{
name : "Rigged Simple",
url : "./models/gltf/RiggedSimple/%s/RiggedSimple.gltf",
cameraPos: new THREE.Vector3(0, 5, 15),
objectRotation: new THREE.Euler(0, 90, 0),
addLights:true,
shadows:true,
extensions: ["glTF"]
},
{
name : "Snowflake",
url : "./models/gltf/snowflake/snowFlake.gltf",
......
......@@ -102,47 +102,83 @@ Object.assign( PropertyBinding, {
},
parseTrackName: function ( trackName ) {
parseTrackName: function () {
// matches strings in the form of:
// nodeName.property
// nodeName.property[accessor]
// nodeName.material.property[accessor]
// uuid.property[accessor]
// uuid.objectName[objectIndex].propertyName[propertyIndex]
// parentName/nodeName.property
// parentName/parentName/nodeName.property[index]
// .bone[Armature.DEF_cog].position
// scene:helium_balloon_model:helium_balloon_model.position
// created and tested via https://regex101.com/#javascript
// Parent directories, delimited by '/' or ':'. Currently unused, but must
// be matched to parse the rest of the track name.
var directoryRe = /((?:[\w-]+[\/:])*)/;
var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/;
var matches = re.exec( trackName );
// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
var nodeRe = /([\w-\.]+)?/;
if ( ! matches ) {
// Object on target node, and accessor. Name may contain only word
// characters. Accessor may contain any character except closing bracket.
var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/;
throw new Error( "cannot parse trackName at all: " + trackName );
// Property and accessor. May contain only word characters. Accessor may
// contain any non-bracket characters.
var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/;
}
var trackRe = new RegExp(''
+ '^'
+ directoryRe.source
+ nodeRe.source
+ objectRe.source
+ propertyRe.source
+ '$'
);
var results = {
// directoryName: matches[ 1 ], // (tschw) currently unused
nodeName: matches[ 2 ], // allowed to be null, specified root node.
objectName: matches[ 3 ],
objectIndex: matches[ 4 ],
propertyName: matches[ 5 ],
propertyIndex: matches[ 6 ] // allowed to be null, specifies that the whole property is set.
};
var supportedObjectNames = [ 'material', 'materials', 'bones' ];
if ( results.propertyName === null || results.propertyName.length === 0 ) {
return function ( trackName ) {
throw new Error( "can not parse propertyName from trackName: " + trackName );
var matches = trackRe.exec( trackName );
}
if ( ! matches ) {
return results;
throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
},
}
var results = {
// directoryName: matches[ 1 ], // (tschw) currently unused
nodeName: matches[ 2 ],
objectName: matches[ 3 ],
objectIndex: matches[ 4 ],
propertyName: matches[ 5 ], // required
propertyIndex: matches[ 6 ]
};
var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
if ( lastDot !== undefined && lastDot !== -1 ) {
var objectName = results.nodeName.substring( lastDot + 1 );
// Object names must be checked against a whitelist. Otherwise, there
// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
// 'bar' could be the objectName, or part of a nodeName (which can
// include '.' characters).
if ( supportedObjectNames.indexOf( objectName ) !== -1 ) {
results.nodeName = results.nodeName.substring( 0, lastDot );
results.objectName = objectName;
}
}
if ( results.propertyName === null || results.propertyName.length === 0 ) {
throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
}
return results;
};
}(),
findNode: function ( root, nodeName ) {
......
......@@ -2,5 +2,199 @@
* @author TristanVALCKE / https://github.com/TristanVALCKE
*/
//Todo
console.warn("Todo: Unit tests of PropertyBinding")
QUnit.module( 'PropertyBinding' );
QUnit.test( 'parseTrackName' , function( assert ) {
var paths = [
[
'.property',
{
nodeName: undefined,
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'nodeName.property',
{
nodeName: 'nodeName',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'a.property',
{
nodeName: 'a',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'no.de.Name.property',
{
nodeName: 'no.de.Name',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'no.d-e.Name.property',
{
nodeName: 'no.d-e.Name',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'nodeName.property[accessor]',
{
nodeName: 'nodeName',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: 'accessor'
}
],
[
'nodeName.material.property[accessor]',
{
nodeName: 'nodeName',
objectName: 'material',
objectIndex: undefined,
propertyName: 'property',
propertyIndex: 'accessor'
}
],
[
'no.de.Name.material.property',
{
nodeName: 'no.de.Name',
objectName: 'material',
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'no.de.Name.material[materialIndex].property',
{
nodeName: 'no.de.Name',
objectName: 'material',
objectIndex: 'materialIndex',
propertyName: 'property',
propertyIndex: undefined
}
],
[
'uuid.property[accessor]',
{
nodeName: 'uuid',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: 'accessor'
}
],
[
'uuid.objectName[objectIndex].propertyName[propertyIndex]',
{
nodeName: 'uuid',
objectName: 'objectName',
objectIndex: 'objectIndex',
propertyName: 'propertyName',
propertyIndex: 'propertyIndex'
}
],
[
'parentName/nodeName.property',
{
// directoryName is currently unused.
nodeName: 'nodeName',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'parentName/no.de.Name.property',
{
// directoryName is currently unused.
nodeName: 'no.de.Name',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: undefined
}
],
[
'parentName/parentName/nodeName.property[index]',
{
// directoryName is currently unused.
nodeName: 'nodeName',
objectName: undefined,
objectIndex: undefined,
propertyName: 'property',
propertyIndex: 'index'
}
],
[
'.bone[Armature.DEF_cog].position',
{
nodeName: undefined,
objectName: 'bone',
objectIndex: 'Armature.DEF_cog',
propertyName: 'position',
propertyIndex: undefined
}
],
[
'scene:helium_balloon_model:helium_balloon_model.position',
{
nodeName: 'helium_balloon_model',
objectName: undefined,
objectIndex: undefined,
propertyName: 'position',
propertyIndex: undefined
}
]
];
paths.forEach( function ( path, i ) {
assert.smartEqual(
THREE.PropertyBinding.parseTrackName( path[ 0 ] ),
path[ 1 ],
'Parses track name: ' + path[ 0 ]
);
} );
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册