@naruya/gaussian-vrm 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@naruya/gaussian-vrm",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "3D Gaussian Splatting with VRM character animation",
5
- "main": "lib/gaussian-vrm.min.js",
6
- "module": "lib/gaussian-vrm.min.js",
5
+ "main": "lib/gaussian-vrm.bundled.js",
6
+ "module": "lib/gaussian-vrm.bundled.js",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": {
10
- "import": "./lib/gaussian-vrm.min.js"
10
+ "import": "./lib/gaussian-vrm.bundled.js"
11
11
  }
12
12
  },
13
13
  "files": [
14
- "lib/gaussian-vrm.min.js"
14
+ "lib/gaussian-vrm.bundled.js"
15
15
  ],
16
16
  "peerDependencies": {
17
17
  "three": "^0.170.0",
@@ -39,6 +39,12 @@
39
39
  ],
40
40
  "author": "naruya",
41
41
  "license": "MIT",
42
+ "scripts": {
43
+ "build": "node build.js"
44
+ },
45
+ "devDependencies": {
46
+ "esbuild": "^0.24.0"
47
+ },
42
48
  "publishConfig": {
43
49
  "access": "public"
44
50
  }
@@ -1,161 +0,0 @@
1
- var ae=Object.defineProperty;var le=(a,e)=>{for(var t in e)ae(a,t,{get:e[t],enumerable:!0})};import*as f from"three";var Q={};le(Q,{BONE_CONFIG:()=>$,addChannels:()=>C,addPMC:()=>J,applyBoneOperations:()=>X,colors:()=>j,createDataTexture:()=>P,getPointsMeshCapsules:()=>O,removePMC:()=>N,resetPose:()=>ce,setPose:()=>F,simpleAnim:()=>de,visualizeBoneAxes:()=>me,visualizePMC:()=>G,visualizeVRM:()=>W});import*as x from"three";var j=[[255,222,62],[138,119,199],[243,82,82],[16,157,123],[43,247,242],[120,84,254],[157,238,149],[80,105,17],[39,121,232],[88,149,76],[22,60,188],[243,67,171],[94,62,2],[162,192,4]];function X(a,e){for(let t of e){let i=t.boneName,s=a.humanoid.getRawBoneNode(i),n=a.humanoid.getNormalizedBoneNode(i);t.position&&(s.position.x+=t.position.x,s.position.y+=t.position.y,s.position.z+=t.position.z),t.rotation&&(n.rotation.x=t.rotation.x*Math.PI/180,n.rotation.y=t.rotation.y*Math.PI/180,n.rotation.z=t.rotation.z*Math.PI/180),t.scale&&s.scale.set(t.scale.x,t.scale.y,t.scale.z)}}function F(a,e){X(a.currentVrm,e),a.currentVrm.humanoid.update()}function ce(a,e){a.currentVrm.humanoid.resetRawPose(),a.currentVrm.humanoid.resetNormalizedPose(),F(a,e)}function W(a,e){let t=a.currentVrm.scene.children[a.skinnedMeshIndex],i=a.faceIndex?a.currentVrm.scene.children[a.faceIndex]:null;e===null?(t.material.forEach(s=>{s.colorWrite=!s.colorWrite,s.depthWrite=!s.depthWrite}),i&&(i.visible=!i.visible)):(t.material.forEach(s=>{s.colorWrite=e,s.depthWrite=e}),i&&(i.visible=e))}function G(a,e){let{points:t,mesh:i,capsules:s}=a;e===null?(t.visible=!t.visible,i.visible=!i.visible,s.children.forEach(n=>{n.visible=!n.visible})):(t.visible=e,i.visible=e,s.children.forEach(n=>{n.visible=e}))}function me(a,e){if(!a||!a.debugAxes||a.debugAxes.size===0)return;let t=a.debugAxes.values().next().value.visible;a.debugAxes.forEach(i=>{i.visible=!t})}function N(a,e){let{points:t,mesh:i,capsules:s}=e;t&&(a.remove(t),t.geometry.dispose(),t.material.dispose()),i&&(a.remove(i),i.geometry.dispose(),i.material.dispose()),s&&(a.remove(s),s.children.forEach(n=>{n.geometry.dispose(),n.material.dispose()}))}function J(a,e){let{points:t,mesh:i,capsules:s}=e;t&&a.add(t),i&&a.add(i),s&&a.add(s)}function C(a,e,t,i=1){for(let s=0;s<t;s++)e[s*4+0]=i>3?1:a[s*(4-i)+0],e[s*4+1]=i>2?1:a[s*(4-i)+1],e[s*4+2]=i>1?1:a[s*(4-i)+2],e[s*4+3]=i>0?1:a[s*(4-i)+3]}function P(...a){let e=new x.DataTexture(...a);return e.needsUpdate=!0,e}function de(a,e){let t=Math.PI*65/180*Math.sin(Math.PI*(e/60+.5)),i=.4*Math.PI*Math.sin(Math.PI*(e/60));a.currentVrm.humanoid.getNormalizedBoneNode("leftUpperArm").rotation.z=t,a.currentVrm.humanoid.getNormalizedBoneNode("leftUpperLeg").rotation.x=i,a.currentVrm.humanoid.getNormalizedBoneNode("leftLowerLeg").rotation.x=-Math.max(i,0),a.currentVrm.humanoid.getNormalizedBoneNode("rightLowerLeg").rotation.y=i}var $={arm:{names:["J_Bip_L_Hand","J_Bip_L_LowerArm","J_Bip_R_Hand","J_Bip_R_LowerArm"],radius:.06,scale:{x:1,z:1}},leg:{names:["J_Bip_L_LowerLeg","J_Bip_L_Foot","J_Bip_R_LowerLeg","J_Bip_R_Foot"],radius:.08,scale:{x:1,z:1}},torso:{names:["J_Bip_C_Neck","J_Bip_C_Spine","J_Bip_C_Chest","J_Bip_C_UpperChest"],radius:.03,scale:{x:6,z:4}},headTop:{names:["J_Bip_C_HeadTop_End"],radius:.06,scale:{x:1.5,z:2}},head:{names:["J_Bip_C_Head"],radius:.03,scale:{x:2,z:2}}};function O(a){let e=a.currentVrm.scene.children[a.skinnedMeshIndex],t=new x.PointsMaterial({color:16711680,size:.02,opacity:.3,transparent:!0}),i=new x.MeshBasicMaterial({color:65280,wireframe:!0,opacity:.2,transparent:!0}),s=new x.MeshBasicMaterial({wireframe:!0,opacity:.5,transparent:!0}),n=new x.BufferGeometry,l=[],o=e.geometry.getAttribute("position"),m=new x.Vector3,d=new x.Vector3;for(let h=0;h<o.count;h++)m.fromBufferAttribute(o,h),d=e.applyBoneTransform(h,m),d.applyMatrix4(a.currentVrm.scene.matrixWorld),l.push(d.x,d.y,d.z);n.setAttribute("position",new x.Float32BufferAttribute(l,3));let y=new x.Points(n,t),g=new x.BufferGeometry;g.setAttribute("position",new x.Float32BufferAttribute(l,3));let M=e.geometry.getIndex();g.setIndex(M);let p=new x.Mesh(g,i),R=new x.Group,T=[],E=0;function B(h,w=0){E++;let r=new x.Vector3().setFromMatrixPosition(h.matrixWorld);h.children.forEach(function(V){if(V.isBone){let I=new x.Vector3().setFromMatrixPosition(V.matrixWorld),b=r.distanceTo(I),L=new x.Vector3().addVectors(r,I).multiplyScalar(.5),H=null;for(let U of Object.values($))if(U.names.includes(V.name)){H=U;break}if(H){let[U,ee,te]=j[R.children.length],ie=U<<16|ee<<8|te,ne=new x.CapsuleGeometry(H.radius,b-H.radius*2,1,6),z=new x.Mesh(ne,s.clone());z.material.color.setHex(ie),z.scale.set(H.scale.x,1,H.scale.z),z.position.copy(L);let se=new x.Vector3().subVectors(I,r).normalize(),re=new x.Quaternion().setFromUnitVectors(new x.Vector3(0,1,0),se);z.setRotationFromQuaternion(re),z.updateMatrixWorld();let oe=e.skeleton.bones.indexOf(V);R.add(z),T.push(oe)}B(V,w+1)}})}let _=a.currentVrm.scene.children[0].children[0];return B(_,1),{pmc:{points:y,mesh:p,capsules:R},capsuleBoneIndex:T}}import*as v from"three";import{GLTFLoader as pe}from"three/addons/loaders/GLTFLoader.js";import{VRMLoaderPlugin as ue,VRMUtils as S}from"@pixiv/three-vrm";import{FBXLoader as he}from"three/addons/loaders/FBXLoader.js";var A=class{constructor(e,t=null,i=null,s=1,n=!1){this.modelUrl=t,this.animationUrl=i,this.currentVrm=void 0,this.currentMixer=void 0,this.currentAction=void 0,this.previousAction=null,this.transitionDuration=.5,this.scene=e,this.scale=s,this.center=n,this._isLoading=!0,this.clock=new v.Clock,this.loadVRM(this.modelUrl,this.animationUrl),this.place()}loadVRM(e=null,t=null,i=null){this._isLoading=!0,e&&(this.modelUrl=e),t&&(this.animationUrl=t),i&&(this.scale=i);let s=new pe;s.crossOrigin="anonymous";let n=new v.Group;n.renderOrder=1e4,n.clear(),s.register(l=>new ue(l,{helperRoot:n,autoUpdateHumanBones:!0})),this.loadingPromise=new Promise((l,c)=>{s.load(this.modelUrl,async o=>{let m=o.userData.vrm;S.removeUnnecessaryVertices(o.scene),S.removeUnnecessaryJoints(o.scene),this.currentVrm=m,m.scene.traverse(g=>{g.frustumCulled=!1});let d=new v.Vector3;new v.Box3().setFromObject(m.scene).getSize(d),this.ground=-d.y*.5*this.scale,this.animationUrl&&this.animationUrl!==""&&await this.loadFBX(this.animationUrl),m.scene.position.y+=this.ground,m.scene.scale.setScalar(this.scale);for(let g of m.springBoneManager.joints)g.settings.stiffness*=this.scale,g.settings.hitRadius*=this.scale;for(let g of m.springBoneManager.colliders){let M=g.shape;M.radius*=this.scale,M.tail&&M.tail.multiplyScalar(this.scale)}S.rotateVRM0(m),m.scene.updateMatrix(),m.scene.position0=m.scene.position.clone(),m.scene.rotation0=m.scene.rotation.clone(),m.scene.quaternion0=m.scene.quaternion.clone(),m.scene.matrix0=m.scene.matrix.clone(),m.hipPos0=m.humanoid.getNormalizedBoneNode("hips").position.clone(),this._isLoading=!1,l(o)},o=>{let m=parseFloat((100*(o.loaded/o.total)).toPrecision(3)),d=document.getElementById("loaddisplay");d&&(d.innerHTML=m+"%")},o=>c(o))})}async loadFBX(e=null){this._isLoading=!0,e&&(this.animationUrl=e),this.currentMixer||(this.currentMixer=new v.AnimationMixer(this.currentVrm.scene));let t=await xe(this.animationUrl,this.currentVrm,this.scale);this.previousAction=this.action,this.action=this.currentMixer.clipAction(t),this.currentAction=this.action,this.previousAction?(this.previousAction.fadeOut(this.transitionDuration),this.action.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(this.transitionDuration).play()):(this.action.play(),this.currentMixer.update(0),this.currentVrm.update(0)),this._isLoading=!1}async place(){await this.loadingPromise,this.scene.add(this.currentVrm.scene),this.center||this.currentVrm.scene.position.set(0,0,0)}async leave(e){e.remove(this.currentVrm.scene),S.deepDispose(this.currentVrm.scene),this.currentVrm=void 0,this.currentMixer=void 0}async changeVRM(e,t,i=null){let s=this.currentVrm.scene.position.clone(),n=this.currentVrm.scene.rotation.clone(),l=this.currentVrm.scene.rotation0.clone();s.y=0,await this.leave(e),await this.loadVRM(t,null,i),await this.place();let c=this.currentVrm.scene.rotation0.clone(),o=m=>new v.Quaternion().setFromEuler(m);n=o(n).multiply(o(l).clone().invert()),n=o(c).multiply(n),n=new v.Euler().setFromQuaternion(n,"YZX"),this.currentVrm.scene.position.copy(s),this.currentVrm.scene.rotation.copy(n),this.center&&(this.currentVrm.scene.position.y+=this.ground)}async changeFBX(e){await this.loadFBX(e)}isLoading(){return this._isLoading}update(){if(this._isLoading)return;let e=this.clock.getDelta();this.currentVrm&&this.currentVrm.update(e),this.currentMixer&&this.currentMixer.update(e)}};function xe(a,e,t){return new he().loadAsync(a).then(s=>{let n=v.AnimationClip.findByName(s.animations,"mixamo.com"),l=[],c=new v.Quaternion,o=new v.Quaternion,m=new v.Quaternion,d=new v.Vector3,y=s.getObjectByName("mixamorigHips").position.y,M=Math.abs(e.hipPos0.y)*t/y;return n.tracks.forEach(p=>{let R=p.name.split("."),T=R[0],E=fe[T],B=e.humanoid?.getNormalizedBoneNode(E)?.name,_=s.getObjectByName(T);if(B!=null){let u=R[1];if(_.getWorldQuaternion(c).invert(),_.parent.getWorldQuaternion(o),p instanceof v.QuaternionKeyframeTrack){for(let h=0;h<p.values.length;h+=4){let w=p.values.slice(h,h+4);m.fromArray(w),m.premultiply(o).multiply(c),m.toArray(w),w.forEach((r,V)=>{p.values[V+h]=r})}l.push(new v.QuaternionKeyframeTrack(`${B}.${u}`,p.times,p.values.map((h,w)=>e.meta?.metaVersion==="0"&&w%2===0?-h:h)))}else if(p instanceof v.VectorKeyframeTrack){let h=p.values.map((w,r)=>(e.meta?.metaVersion==="0"&&r%3!==1?-w:w)*M);l.push(new v.VectorKeyframeTrack(`${B}.${u}`,p.times,h))}}}),new v.AnimationClip("vrmAnimation",n.duration,l)})}var fe={mixamorigHips:"hips",mixamorigSpine:"spine",mixamorigSpine1:"chest",mixamorigSpine2:"upperChest",mixamorigNeck:"neck",mixamorigHead:"head",mixamorigLeftShoulder:"leftShoulder",mixamorigLeftArm:"leftUpperArm",mixamorigLeftForeArm:"leftLowerArm",mixamorigLeftHand:"leftHand",mixamorigLeftHandThumb1:"leftThumbMetacarpal",mixamorigLeftHandThumb2:"leftThumbProximal",mixamorigLeftHandThumb3:"leftThumbDistal",mixamorigLeftHandIndex1:"leftIndexProximal",mixamorigLeftHandIndex2:"leftIndexIntermediate",mixamorigLeftHandIndex3:"leftIndexDistal",mixamorigLeftHandMiddle1:"leftMiddleProximal",mixamorigLeftHandMiddle2:"leftMiddleIntermediate",mixamorigLeftHandMiddle3:"leftMiddleDistal",mixamorigLeftHandRing1:"leftRingProximal",mixamorigLeftHandRing2:"leftRingIntermediate",mixamorigLeftHandRing3:"leftRingDistal",mixamorigLeftHandPinky1:"leftLittleProximal",mixamorigLeftHandPinky2:"leftLittleIntermediate",mixamorigLeftHandPinky3:"leftLittleDistal",mixamorigRightShoulder:"rightShoulder",mixamorigRightArm:"rightUpperArm",mixamorigRightForeArm:"rightLowerArm",mixamorigRightHand:"rightHand",mixamorigRightHandPinky1:"rightLittleProximal",mixamorigRightHandPinky2:"rightLittleIntermediate",mixamorigRightHandPinky3:"rightLittleDistal",mixamorigRightHandRing1:"rightRingProximal",mixamorigRightHandRing2:"rightRingIntermediate",mixamorigRightHandRing3:"rightRingDistal",mixamorigRightHandMiddle1:"rightMiddleProximal",mixamorigRightHandMiddle2:"rightMiddleIntermediate",mixamorigRightHandMiddle3:"rightMiddleDistal",mixamorigRightHandIndex1:"rightIndexProximal",mixamorigRightHandIndex2:"rightIndexIntermediate",mixamorigRightHandIndex3:"rightIndexDistal",mixamorigRightHandThumb1:"rightThumbMetacarpal",mixamorigRightHandThumb2:"rightThumbProximal",mixamorigRightHandThumb3:"rightThumbDistal",mixamorigLeftUpLeg:"leftUpperLeg",mixamorigLeftLeg:"leftLowerLeg",mixamorigLeftFoot:"leftFoot",mixamorigLeftToeBase:"leftToes",mixamorigRightUpLeg:"rightUpperLeg",mixamorigRightLeg:"rightLowerLeg",mixamorigRightFoot:"rightFoot",mixamorigRightToeBase:"rightToes"};import*as k from"three";import*as Y from"gaussian-splats-3d";var D=class extends k.Group{constructor(e,t,i,s){super(),this.loadGS(e,t,i,s)}loadGS(e,t,i=[0,0,0],s=[0,0,1,0]){Array.isArray(e)||(e=[e]),this.loadingPromise=new Promise(async(n,l)=>{let c=new Y.DropInViewer({sharedMemoryForWorkers:!1,dynamicScene:!0,sceneRevealMode:2,sphericalHarmonicsDegree:2}),o=e.map(m=>({path:m,scale:[t,t,t],position:i,rotation:s,splatAlphaRemovalThreshold:0}));await c.addSplatScenes(o,!1),this.add(c),this.viewer=c,this.position0=new k.Vector3(...i),this.quaternion0=new k.Quaternion(...s),this.rotation0=new k.Euler().setFromQuaternion(this.quaternion0),this.matrix0=new k.Matrix4().compose(this.position0,this.quaternion0,new k.Vector3(1,1,1)),n(this)},void 0,function(n){console.error(n)})}};var q=class{constructor(){this.header=null,this.vertexCount=0,this.properties=[],this.propertyTypes=new Map([["char",1],["uchar",1],["short",2],["ushort",2],["int",4],["uint",4],["float",4],["double",8]])}async parsePLY(e,t){let i;if(e.endsWith(".ply")||(t=!1),t)try{let u=await fetch(e,{method:"HEAD"});i=Number(u.headers.get("content-length"))}catch{let h=await fetch(e);i=Number(h.headers.get("content-length"))}else{let u=await fetch(e);i=Number(u.headers.get("content-length"))}let n=(await fetch(e)).body.getReader(),l=[],c=0;for(;;){let{done:u,value:h}=await n.read();if(u)break;l.push(h),c+=h.length;let w=document.getElementById("loaddisplay");if(w)if(i){let r=c/i*100;w.innerHTML=`${r.toFixed(1)}% (1/2)`}else w.innerHTML=`${c} bytes loaded (1/2)`}let o=document.getElementById("loaddisplay");o&&(o.innerHTML=`${100 .toFixed(1)}% (1/2)`);let m=new ArrayBuffer(c),d=new Uint8Array(m),y=0;for(let u of l)d.set(u,y),y+=u.length;let g=new DataView(m);y=0;let M="";for(;;){let u=g.getUint8(y++);if(M+=String.fromCharCode(u),M.includes(`end_header
2
- `))break}let p=M.split(`
3
- `);this.header=p.filter(u=>u.trim()!=="");let R="binary_little_endian";for(let u of this.header)if(u.startsWith("format"))R=u.split(" ")[1];else if(u.startsWith("element vertex"))this.vertexCount=parseInt(u.split(" ")[2]);else if(u.startsWith("property")){let h=u.split(" ");this.properties.push({type:h[1],name:h[2]})}let T=this.properties.reduce((u,h)=>u+this.propertyTypes.get(h.type),0),E=[],B=new Uint8Array(m.slice(y));for(let u=0;u<this.vertexCount;u++){let h={rawData:B.slice(u*T,(u+1)*T)},w=0;for(let r of this.properties){let V=this.propertyTypes.get(r.type),I;switch(r.type){case"float":I=g.getFloat32(y+w,!0);break}h[r.name]=I,w+=V}if(E.push(h),y+=T,u%1e4===0){let r=u/this.vertexCount*100,V=document.getElementById("loaddisplay");V&&await new Promise(I=>{requestAnimationFrame(()=>{V.innerHTML=`${r.toFixed(1)}% (2/2)`,I()})})}}let _=document.getElementById("loaddisplay");return _&&(_.innerHTML=`${100 .toFixed(1)}% (2/2)`),{header:this.header,vertices:E,vertexCount:this.vertexCount,vertexSize:T}}createPLYFile(e,t,i){let s=e.join(`
4
- `)+`
5
- `,l=new TextEncoder().encode(s),c=new Uint8Array(t.length*i);t.forEach((m,d)=>{c.set(m.rawData,d*i)});let o=new Uint8Array(l.length+c.length);return o.set(l,0),o.set(c,l.length),o}async splitPLY(e,t){let i=await this.parsePLY(e,!1),s=l=>i.header.map(c=>c.startsWith("element vertex")?`element vertex ${l}`:c),n=[];for(let[l,c]of Object.entries(t)){let o=c.map(y=>i.vertices[y]),m=this.createPLYFile(s(o.length),o,i.vertexSize),d=new Blob([m],{type:"application/octet-stream"});n.push(URL.createObjectURL(d))}return n}};import K from"jszip";var Z=class a extends f.Group{constructor(e,t){super(),this.character=e,this.gs=t,this.debugAxes=new Map,this.isReady=!1,this.t=0}static async initVRM(e,t,i,s,n,l){l||(l=(await(await fetch("./assets/default.json")).json()).boneOperations),n||(n=1);let c=new A(t,e,"",n,!0);await c.loadingPromise,c.skinnedMeshIndex=1,c.faceIndex=void 0,c.currentVrm.scene.children.length>4&&(c.skinnedMeshIndex=2,c.faceIndex=1);let o=c.currentVrm.scene.children[c.skinnedMeshIndex];if(W(c,!1),F(c,l),o.skeleton.update(),o.skeleton.computeBoneTexture(),o.geometry.computeVertexNormals(),c.skinnedMeshIndex===2){let p=c.currentVrm.humanoid.getRawBoneNode("head"),R=new f.Bone;R.name="J_Bip_C_HeadTop_End",R.position.set(0,.2,-.05),R.updateMatrixWorld(!0),p.add(R),o.skeleton.bones.push(R),o.bind(new f.Skeleton(o.skeleton.bones),o.matrixWorld)}s.render(t,i),o.bindMatrix0=o.bindMatrix.clone(),o.bindMatrixInverse0=o.bindMatrixInverse.clone();let m=o.skeleton.boneTexture.image.width,d=o.skeleton.boneTexture.image.height,y=o.skeleton.boneTexture.format,g=o.skeleton.boneTexture.type,M=o.skeleton.boneTexture.image.data.slice();return o.boneTexture0=new f.DataTexture(M,m,d,y,g),o.boneTexture0.needsUpdate=!0,c}static async initGS(e,t,i,s){let n=await new D(e,1,t,i);return await n.loadingPromise,s.add(n),n.splatMesh=n.viewer.splatMesh,n.centers=n.splatMesh.splatDataTextures.baseData.centers,n.colors=n.splatMesh.splatDataTextures.baseData.colors,n.covariances=n.splatMesh.splatDataTextures.baseData.covariances,n.splatCount=n.splatMesh.geometry.attributes.splatIndex.array.length,n.centers0=new Float32Array(n.centers),n.colors0=new Float32Array(n.colors),n.covariances0=new Float32Array(n.covariances),n.splatMesh.updateDataTexturesFromBaseData(0,n.splatCount-1),n}static async load(e,t,i,s,n){console.log("Loading GVRM:",e);let l=await fetch(e),c=await K.loadAsync(l.arrayBuffer()),o=await c.file("model.vrm").async("arraybuffer"),m=await c.file("model.ply").async("arraybuffer"),d=JSON.parse(await c.file("data.json").async("text")),y=new Blob([o],{type:"application/octet-stream"}),g=URL.createObjectURL(y),M=new Blob([m],{type:"application/octet-stream"}),p=URL.createObjectURL(M),R=d.modelScale,T=d.boneOperations;d.splatRelativePoses===void 0&&(d.splatRelativePoses=d.relativePoses);let E=await a.initVRM(g,t,i,s,R,T),{sceneSplatIndices:B,boneSceneMap:_}=a.sortSplatsByBones(d),h=await new q().splitPLY(p,B),w=await a.initGS(h,d.gsPosition,d.gsQuaternion,t),r=new a(E,w);r.modelScale=R,r.boneOperations=T,r.boneSceneMap=_,r.fileName=n,r.updatePMC(),J(t,r.pmc),G(r.pmc,!1),s.render(t,i),r.gs.splatVertexIndices=d.splatVertexIndices,r.gs.splatBoneIndices=d.splatBoneIndices,r.gs.splatRelativePoses=d.splatRelativePoses,a.gsCustomizeMaterial(E,w);for(let b=0;b<r.gs.splatCount;b++){let L=Math.sqrt(r.gs.splatRelativePoses[b*3+0]**2+r.gs.splatRelativePoses[b*3+1]**2+r.gs.splatRelativePoses[b*3+2]**2);(r.gs.splatBoneIndices[b]!==57&&L>.2||r.gs.splatBoneIndices[b]==21&&L>.1||r.gs.splatBoneIndices[b]==19&&L>.1||r.gs.splatBoneIndices[b]===57&&L>.3)&&(r.gs.colors[b*4+3]=0)}r.gs.splatMesh.updateDataTexturesFromBaseData(0,r.gs.splatCount-1);function V(b,L=0){b.children.forEach(function(H){H.isBone&&(["J_Bip_L_Hand","J_Bip_L_LowerArm","J_Bip_R_Hand","J_Bip_R_LowerArm","J_Bip_L_LowerLeg","J_Bip_L_Foot","J_Bip_R_LowerLeg","J_Bip_R_Foot","J_Bip_C_Neck","J_Bip_C_Spine","J_Bip_C_Chest","J_Bip_C_UpperChest","J_Bip_C_HeadTop_End","J_Bip_C_Head"].includes(H.name)&&(H.updateMatrix(),H.matrixWorld0=H.matrixWorld.clone()),V(H,L+1))})}let I=E.currentVrm.scene.children[0].children[0];return V(I,1),r.isReady=!0,r}static async save(e,t,i,s,n,l,c=!1){let o=await fetch(t).then(p=>p.arrayBuffer()),m=await fetch(i).then(p=>p.arrayBuffer()),d={modelScale:n,boneOperations:s,gsQuaternion:e.gs.viewer.splatMesh.scenes[0].quaternion.toArray(),gsPosition:e.gs.viewer.splatMesh.scenes[0].position.toArray(),splatVertexIndices:e.gs.splatVertexIndices,splatBoneIndices:e.gs.splatBoneIndices,splatRelativePoses:e.gs.splatRelativePoses},y=new K;y.file("model.vrm",o),y.file("model.ply",m),y.file("data.json",JSON.stringify(d,null,2));let g=await y.generateAsync({type:"blob"});if(!l&&i.endsWith(".ply")?l=i.split("/").pop().replace(".ply",".gvrm"):l||(l=i.split("/").pop()+".gvrm"),M(g,l),c){console.log("savePly!");let p=new Blob([m],{type:"application/octet-stream"}),R=l.replace(".gvrm","_processed.ply");M(p,R)}function M(p,R){let T=URL.createObjectURL(p),E=document.createElement("a");E.href=T,E.download=R,E.click(),p===g&&e.url&&URL.revokeObjectURL(e.url),p===g?e.url=T:URL.revokeObjectURL(T)}}static async remove(e,t){e.character&&(await e.character.leave(t),e.character=null),e.gs&&(await e.gs.viewer.dispose(),e.gs=null),e.pmc&&N(t,e.pmc)}async load(e,t,i,s,n=null){let l=await a.load(e,t,i,s,n);this.character=l.character,this.gs=l.gs,this.modelScale=l.modelScale,this.boneOperations=l.boneOperations,this.boneSceneMap=l.boneSceneMap,this.vertexSceneMap=l.vertexSceneMap,this.fileName=l.fileName,this.isReady=!0}async save(e,t,i,s,n,l=!1){await a.save(this,e,t,i,s,n,l)}async remove(e){this.isReady=!1,await a.remove(this,e)}async changeFBX(e){await this.character.changeFBX(e)}updatePMC(){let{pmc:e}=O(this.character);this.pmc=e}updateByBones(){let e=new f.Vector3,t=new f.Vector3,i=new f.Vector3,s=new f.Matrix4,n=new f.Quaternion,l=["J_Bip_C_Neck","J_Bip_C_Spine","J_Bip_C_Chest","J_Bip_C_UpperChest","J_Bip_C_HeadTop_End","J_Bip_C_Head"],c=this.character.currentVrm.scene.children[2].skeleton;c.bones.forEach(o=>{let m=o.children;m.length!==0&&m.forEach(d=>{let y=c.bones.indexOf(d),g=this.boneSceneMap[y];if(g===void 0)return;o.updateMatrixWorld(!0),d.updateMatrixWorld(!0),e.setFromMatrixPosition(o.matrixWorld),t.setFromMatrixPosition(d.matrixWorld),i.addVectors(e,t).multiplyScalar(.5),i.sub(this.character.currentVrm.scene.position).add(this.character.currentVrm.scene.position0),i.applyQuaternion(this.gs.viewer.quaternion.clone().invert()),s.extractRotation(d.matrixWorld.multiply(d.matrixWorld0.clone().invert())),n.setFromRotationMatrix(s),n.premultiply(this.gs.viewer.quaternion.clone().invert()),n.multiply(this.gs.quaternion0);let M=this.gs.viewer.getSplatScene(g);if(M){l.includes(d.name)||(M.position.copy(i),M.quaternion.copy(n));let p=this.debugAxes.get(g);p||(p=this.createDebugAxes(g)),p.position.copy(i),p.quaternion.copy(n)}})})}createDebugAxes(e){let t=new f.AxesHelper(.3);return t.visible=!1,this.gs.add(t),this.debugAxes.set(e,t),t}update(){if(!this.isReady)return;let e=this.character.currentVrm.scene.quaternion.clone(),t=this.character.currentVrm.scene.quaternion0.clone(),i=this.character.currentVrm.scene.position.clone(),s=this.character.currentVrm.scene.position0.clone();this.gs.viewer.quaternion.copy(e.multiply(t.invert())),this.gs.viewer.position.copy(i.sub(s)),this.updateByBones(),this.character.update()}static sortSplatsByBones(e){let t={},i=0,s={};for(let n=0;n<e.splatBoneIndices.length;n++){let l=e.splatBoneIndices[n];s[l]===void 0&&(s[l]=i,i++,t[s[l]]=[]),t[s[l]].push(n)}return a.updateExtraData(e,t),{sceneSplatIndices:t,boneSceneMap:s}}static updateExtraData(e,t){let i=[];for(let c=0;c<Object.keys(t).length;c++)i=i.concat(t[c]);let s=[],n=[],l=[];for(let c of Object.keys(t))for(let o of t[c])s.push(e.splatVertexIndices[o]),n.push(e.splatBoneIndices[o]),l.push(e.splatRelativePoses[o*3],e.splatRelativePoses[o*3+1],e.splatRelativePoses[o*3+2]);e.splatVertexIndices=s,e.splatBoneIndices=n,e.splatRelativePoses=l}static gsCustomizeMaterial(e,t){t.splatMesh.material=t.splatMesh.material.clone(),t.splatMesh.material.needsUpdate=!0;let i=e.currentVrm.scene.children[e.skinnedMeshIndex],s=i.geometry.attributes.position.count,n=i.geometry.attributes.position.array,l=i.geometry.attributes.normal.array,c=i.geometry.attributes.skinIndex.array,o=i.geometry.attributes.skinWeight.array,m=t.splatVertexIndices,d=t.splatRelativePoses,y=new Float32Array(4096*1024*4),g=new Float32Array(4096*1024*4),M=new Float32Array(4096*1024*4),p=new Float32Array(4096*1024*4),R=new Float32Array(4096*1024*4),T=new Float32Array(4096*1024*4);C(n,y,s,1),C(l,g,s,1),M.set(c),p.set(o),C(m,R,t.splatCount,3),C(d,T,t.splatCount,1);let E=P(y,4096,1024,f.RGBAFormat,f.FloatType),B=P(g,4096,1024,f.RGBAFormat,f.FloatType),_=P(M,4096,1024,f.RGBAFormat,f.FloatType),u=P(p,4096,1024,f.RGBAFormat,f.FloatType),h=P(R,4096,1024,f.RGBAFormat,f.FloatType),w=P(T,4096,1024,f.RGBAFormat,f.FloatType);t.splatMesh.material.onBeforeCompile=function(r){r.uniforms.meshPositionTexture={value:E},r.uniforms.meshNormalTexture={value:B},r.uniforms.meshSkinIndexTexture={value:_},r.uniforms.meshSkinWeightTexture={value:u},r.uniforms.gsMeshVertexIndexTexture={value:h},r.uniforms.gsMeshRelativePosTexture={value:w},r.uniforms.bindMatrix0={value:i.bindMatrix0},r.uniforms.bindMatrix={value:i.bindMatrix},r.uniforms.bindMatrixInverse0={value:i.bindMatrixInverse0},r.uniforms.bindMatrixInverse={value:i.bindMatrixInverse},r.uniforms.boneTexture0={value:i.boneTexture0},r.uniforms.boneTexture={value:i.skeleton.boneTexture},r.uniforms.meshMatrixWorld={value:e.currentVrm.scene.matrixWorld},r.uniforms.gsMatrix0={value:t.matrix0},r.uniforms.gsMatrix={value:t.viewer.matrixWorld},r.vertexShader=r.vertexShader.replace("#include <common>",`
6
- #define USE_SKINNING
7
-
8
- #include <common>
9
- #include <skinning_pars_vertex> // boneTexture
10
-
11
- uniform sampler2D meshPositionTexture;
12
- uniform sampler2D meshNormalTexture;
13
- uniform sampler2D meshSkinIndexTexture;
14
- uniform sampler2D meshSkinWeightTexture;
15
- uniform sampler2D gsMeshVertexIndexTexture;
16
- uniform sampler2D gsMeshRelativePosTexture;
17
- uniform mat4 meshMatrixWorld;
18
- uniform mat4 gsMatrix0;
19
- uniform mat4 gsMatrix;
20
-
21
- uniform mat4 bindMatrix0;
22
- uniform mat4 bindMatrixInverse0;
23
- uniform highp sampler2D boneTexture0;
24
-
25
- mat4 getBoneMatrix0( const in float i ) {
26
- int size = textureSize( boneTexture0, 0 ).x;
27
- int j = int( i ) * 4;
28
- int x = j % size;
29
- int y = j / size;
30
- vec4 v1 = texelFetch( boneTexture0, ivec2( x, y ), 0 );
31
- vec4 v2 = texelFetch( boneTexture0, ivec2( x + 1, y ), 0 );
32
- vec4 v3 = texelFetch( boneTexture0, ivec2( x + 2, y ), 0 );
33
- vec4 v4 = texelFetch( boneTexture0, ivec2( x + 3, y ), 0 );
34
- return mat4( v1, v2, v3, v4 );
35
- }
36
-
37
- // TODO: check this
38
- vec4 quatFromMat3(mat3 m) {
39
- float trace = m[0][0] + m[1][1] + m[2][2];
40
- vec4 q;
41
-
42
- if (trace > 0.0) {
43
- float s = 0.5 / sqrt(trace + 1.0);
44
- q.w = 0.25 / s;
45
- q.x = (m[2][1] - m[1][2]) * s;
46
- q.y = (m[0][2] - m[2][0]) * s;
47
- q.z = (m[1][0] - m[0][1]) * s;
48
- } else if (m[0][0] > m[1][1] && m[0][0] > m[2][2]) {
49
- float s = 2.0 * sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]);
50
- q.w = (m[2][1] - m[1][2]) / s;
51
- q.x = 0.25 * s;
52
- q.y = (m[0][1] + m[1][0]) / s;
53
- q.z = (m[0][2] + m[2][0]) / s;
54
- } else if (m[1][1] > m[2][2]) {
55
- float s = 2.0 * sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]);
56
- q.w = (m[0][2] - m[2][0]) / s;
57
- q.x = (m[0][1] + m[1][0]) / s;
58
- q.y = 0.25 * s;
59
- q.z = (m[1][2] + m[2][1]) / s;
60
- } else {
61
- float s = 2.0 * sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]);
62
- q.w = (m[1][0] - m[0][1]) / s;
63
- q.x = (m[0][2] + m[2][0]) / s;
64
- q.y = (m[1][2] + m[2][1]) / s;
65
- q.z = 0.25 * s;
66
- }
67
- return q;
68
- }
69
-
70
- vec4 quatInverse(vec4 q) {
71
- return vec4(-q.x, -q.y, -q.z, q.w) / dot(q, q);
72
- }
73
-
74
- vec4 quatMultiply(vec4 a, vec4 b) {
75
- return vec4(
76
- a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
77
- a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
78
- a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
79
- a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
80
- );
81
- }
82
-
83
- mat3 mat3FromQuat(vec4 q) {
84
- float x = q.x, y = q.y, z = q.z, w = q.w;
85
- float x2 = x + x, y2 = y + y, z2 = z + z;
86
- float xx = x * x2, xy = x * y2, xz = x * z2;
87
- float yy = y * y2, yz = y * z2, zz = z * z2;
88
- float wx = w * x2, wy = w * y2, wz = w * z2;
89
-
90
- return mat3(
91
- 1.0 - (yy + zz), xy - wz, xz + wy,
92
- xy + wz, 1.0 - (xx + zz), yz - wx,
93
- xz - wy, yz + wx, 1.0 - (xx + yy)
94
- );
95
- }
96
- `),r.vertexShader=r.vertexShader.replace("mat4 transform = transforms[sceneIndex]","mat4 transform = gsMatrix * gsMatrix0;"),r.vertexShader=r.vertexShader.replace("vec3 splatCenter = uintBitsToFloat(uvec3(sampledCenterColor.gba));",`
97
- vec2 samplerUV2 = vec2(0.0, 0.0);
98
- float d2 = float(splatIndex) / 4096.0;
99
- samplerUV2.y = float(floor(d2)) / 1024.0;
100
- samplerUV2.x = fract(d2);
101
- float meshVertexIndex = texture2D(gsMeshVertexIndexTexture, samplerUV2).r;
102
- vec3 relativePos = texture2D(gsMeshRelativePosTexture, samplerUV2).rgb;
103
-
104
- vec2 samplerUV3 = vec2(0.0, 0.0);
105
- float d3 = float(meshVertexIndex) / 4096.0;
106
- samplerUV3.y = float(floor(d3)) / 1024.0;
107
- samplerUV3.x = fract(d3);
108
- vec3 transformed = texture2D(meshPositionTexture, samplerUV3).rgb;
109
- vec3 objectNormal = texture2D(meshNormalTexture, samplerUV3).rgb;
110
- vec4 skinIndex = texture2D(meshSkinIndexTexture, samplerUV3);
111
- vec4 skinWeight = texture2D(meshSkinWeightTexture, samplerUV3);
112
-
113
- mat4 boneMatX0 = getBoneMatrix0( skinIndex.x );
114
- mat4 boneMatY0 = getBoneMatrix0( skinIndex.y );
115
- mat4 boneMatZ0 = getBoneMatrix0( skinIndex.z );
116
- mat4 boneMatW0 = getBoneMatrix0( skinIndex.w );
117
- mat4 skinMatrix0 = mat4( 0.0 );
118
- skinMatrix0 += skinWeight.x * boneMatX0;
119
- skinMatrix0 += skinWeight.y * boneMatY0;
120
- skinMatrix0 += skinWeight.z * boneMatZ0;
121
- skinMatrix0 += skinWeight.w * boneMatW0;
122
- skinMatrix0 = bindMatrixInverse0 * skinMatrix0 * bindMatrix0;
123
-
124
- #include <skinbase_vertex> // boneMat
125
- #include <skinnormal_vertex> // skinMatrix, using normal
126
- #include <defaultnormal_vertex> // ?
127
- #include <skinning_vertex>
128
-
129
- // vec3 splatCenter = ( vec4(transformed, 1.0) ).xyz;
130
- // vec3 splatCenter = ( meshMatrixWorld * vec4(transformed, 1.0) ).xyz;
131
- // vec3 splatCenter = ( meshMatrixWorld * vec4(transformed + relativePos, 1.0) ).xyz; // GOOD
132
-
133
- vec3 skinnedRelativePos = vec4( skinMatrix * inverse(skinMatrix0) * vec4( relativePos, 0.0 ) ).xyz;
134
- vec3 splatCenter = ( meshMatrixWorld * vec4(transformed + skinnedRelativePos, 1.0) ).xyz;
135
- `),r.vertexShader=r.vertexShader.replace("vec4 viewCenter = transformModelViewMatrix * vec4(splatCenter, 1.0);",`
136
- // The splatCenter is the coordinate system for inverse(transform).
137
- splatCenter = (inverse(transform) * vec4(splatCenter, 1.0)).xyz;
138
- vec4 viewCenter = transformModelViewMatrix * vec4(splatCenter, 1.0);
139
- `),r.vertexShader=r.vertexShader.replace("mat3 cov2Dm = transpose(T) * Vrk * T;",`
140
- // for debug
141
- // Vrk[0][0] *= 25.0; Vrk[1][1] *= 0.1; Vrk[2][2] *= 0.1;
142
- // Vrk[1][1] *= 25.0; Vrk[0][0] *= 0.1; Vrk[2][2] *= 0.1;
143
- // Vrk[2][2] *= 25.0; Vrk[0][0] *= 0.1; Vrk[1][1] *= 0.1;
144
-
145
- // via quat
146
- mat3 gsRotation0 = mat3(gsMatrix0);
147
- mat3 skinRotationMatrix = mat3(skinMatrix * inverse(skinMatrix0));
148
- mat3 relativeRotation = transpose(gsRotation0) * skinRotationMatrix * gsRotation0;
149
- vec4 tempQuat = quatFromMat3(relativeRotation);
150
- tempQuat.y = -tempQuat.y; // Hardcode, maybe bug in quatFromMat3?
151
- relativeRotation = mat3FromQuat(tempQuat);
152
- mat3 rotatedVrk = transpose(relativeRotation) * Vrk * relativeRotation;
153
- mat3 cov2Dm = transpose(T) * rotatedVrk * T;
154
-
155
- // TODO: via mat
156
- // mat3 gsRotation0 = mat3(gsMatrix0);
157
- // mat3 skinRotationMatrix = mat3(skinMatrix * inverse(skinMatrix0));
158
- // mat3 relativeRotation = transpose(gsRotation0) * skinRotationMatrix * gsRotation0;
159
- // mat3 rotatedVrk = transpose(relativeRotation) * Vrk * relativeRotation;
160
- // mat3 cov2Dm = transpose(T) * rotatedVrk * T;
161
- `)},t.splatMesh.material.needsUpdate=!0}};export{Z as GVRM,Q as GVRMUtils};