1
0

update three-vrm-3

This commit is contained in:
2024-08-04 17:56:35 +09:00
parent 2fb62a68ac
commit f5fa7a9a0c
58 changed files with 12078 additions and 6 deletions

1
min-ts/dist/CNAME vendored Normal file
View File

@ -0,0 +1 @@
vrm.syui.ai

94
min-ts/dist/css/style.css vendored Normal file
View File

@ -0,0 +1,94 @@
body {
margin: 0;
overflow: hidden;
}
progress {
width: 100%;
height:8px;
position: absolute;
border-radius: 0px;
}
::-webkit-progress-bar {
border-radius: 0px;
background-color: #e6e6fa;
}
::-webkit-progress-value {
background-color: #4682b4;
}
::-moz-progress-bar {
border-radius: 0px;
background-color: #e6e6fa;
}
::-moz-progress-value {
background-color: #4682b4;
}
::-ms-progress-bar {
border-radius: 0px;
background-color: #e6e6fa;
}
::-ms-progress-value {
background-color: #4682b4;
}
div#menu {
padding: 20px;
border-bottom:solid 1px #ccc;
}
button {
border: none;
margin: 0;
padding: 0 20px 0 20px;
width: auto;
overflow: visible;
background: transparent;
color: inherit;
font: inherit;
line-height: normal;
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
appearance: none;
-webkit-appearance: none;
cursor: pointer;
user-select: none;
}
a {
text-decoration: none;
color: #000;
}
a:hover{
/* color: #fff700; */
color: #847e00;
}
footer {
border-top:solid 1px #ccc;
padding: 20px 0 20px 0;
font-size:20px;
text-align: center;
}
span.menu-nav button#nav {
display: none;
}
@media screen and (max-width:1000px) {
span#nav-mobile {
display: none;
}
span.menu-nav button#nav {
right:0;
display: block;
position: absolute;
top:20px;
}
}

BIN
min-ts/dist/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
min-ts/dist/img/0.hdr vendored Normal file

Binary file not shown.

10744
min-ts/dist/img/1.hdr vendored Normal file

File diff suppressed because one or more lines are too long

BIN
min-ts/dist/img/2.hdr vendored Normal file

Binary file not shown.

BIN
min-ts/dist/img/og.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

21
min-ts/dist/index.html vendored Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>ai</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta property="og:url" content="https://vrm.syui.ai">
<meta property="og:title" content="ai/vrm">
<meta property="og:description" content="ai[vrm] model viewer">
<meta property="og:image" content="/img/og.png">
<link rel="icon" href="/favicon.ico"/>
<link rel="stylesheet" href="/css/style.css"/>
<link rel="stylesheet" href="https://syui.ai/bower_components/icomoon/style.css" />
<link rel="stylesheet" href="https://syui.ai/bower_components/font-awesome/css/all.min.css" />
<script src="main.js"></script>
</head>
<body>
<progress value="0" max="100" id="progressBar"></progress>
<div id="canvas"></div>
<footer>© syui</footer>
</body>
</html>

120
min-ts/docs/wiki.md Normal file
View File

@ -0,0 +1,120 @@
## example three-vrm
- vrm : [download](https://hub.vroid.com/characters/675572020956181239/models/7175071267176594918)
- vrma : [download](https://vroid.booth.pm/items/5512385)
> ./dist/vrma
```js
load("/vrma/model.vrm");
load("/vrma/VRMA_01.vrma");
```
## iframe
```html
<div class="vrm-model">
<iframe src="https://vrm.syui.ai" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen scrolling="no"></iframe>
</div>
<style>
.vrm-model iframe {
margin:30px 0 30px 0;
width: 100%;
height: 640px;
}
</style>
```
## head
```js
let head = currentVrm.humanoid.getRawBoneNode("head");
```
## blink
```js
currentVrm.expressionManager.setValue('blink', 0);
```
## bloom
```js
//import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
//import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
//import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
// https://github.com/pmndrs/postprocessing
import { BloomEffect, EffectComposer, EffectPass, RenderPass } from "postprocessing";
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new EffectPass(camera, new BloomEffect()));
requestAnimationFrame(function render() {
requestAnimationFrame(render);
composer.render();
});
```
## progress
```js
// https://sbcode.net/threejs/progress-indicator
let manager = new THREE.LoadingManager();
let progressBar = document.getElementById('progressBar') as HTMLProgressElement
// https://threejs.org/docs/#api/en/loaders/managers/LoadingManager
manager.onStart = function ( url, itemsLoaded, itemsTotal ) {
//console.log( 'Started loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
progressBar.style.display = 'block'
let percentComplete = (itemsLoaded / itemsTotal) * 100
progressBar.value = percentComplete === Infinity ? 100 : percentComplete
};
manager.onLoad = function ( ) {
//console.log( 'Loading complete!');
progressBar.style.display = 'none'
};
manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
let percentComplete = (itemsLoaded / itemsTotal) * 100
progressBar.value = percentComplete === Infinity ? 100 : percentComplete
//console.log( 'Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
};
manager.onError = function ( url ) {
//console.log( 'There was an error loading ' + url );
progressBar.style.display = 'block'
};
```
```html
<progress value="0" max="100" id="progressBar"></progress>
```
```css
progress {
width: 100%;
height:8px;
position: absolute;
border-radius: 0px;
}
::-webkit-progress-bar {
border-radius: 0px;
background-color: #e6e6fa;
}
::-webkit-progress-value {
background-color: #4682b4;
}
```
## link
- https://vrm.dev/
- https://threejs.org/docs/
- https://github.com/pixiv/three-vrm
- https://github.com/vrm-c/vrm-specification/blob/master/specification/
- https://github.com/pmndrs/postprocessing

23
min-ts/package.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "vrm",
"version": "0.0.1",
"private": true,
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open"
},
"devDependencies": {
"ts-loader": "^9.5.1",
"typescript": "^5.4.2",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.3"
},
"dependencies": {
"@pixiv/three-vrm": "^3.0.0",
"@pixiv/three-vrm-animation": "^3.0.0",
"@pixiv/three-vrm-springbone": "^3.0.0",
"postprocessing": "^6.35.2",
"three": "^0.167.1"
}
}

123
min-ts/src/index.ts Normal file
View File

@ -0,0 +1,123 @@
import * as THREE from "three"
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { VRMLoaderPlugin } from "@pixiv/three-vrm";
import { createVRMAnimationClip, VRMAnimationLoaderPlugin } from "@pixiv/three-vrm-animation";
import { GridHelper, Mesh, MeshLambertMaterial, BoxGeometry, Vector3, Vector2, Color, DirectionalLight, Fog, HemisphereLight, HalfFloatType } from 'three';
import { BloomEffect, EffectComposer, EffectPass, RenderPass } from "postprocessing";
window.addEventListener("DOMContentLoaded", () => {
let manager = new THREE.LoadingManager();
const canvas = document.getElementById("canvas");
if (canvas == null) return;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 70, canvas.clientWidth/canvas.clientHeight, 0.1, 2000);
camera.position.set(0, 1.5, -1.5)
camera.rotation.set(0.0, Math.PI, 0.0)
camera.lookAt(new THREE.Vector3(0, 0, 0));
const renderer = new THREE.WebGLRenderer({
alpha: true,
powerPreference: "high-performance",
antialias: true,
stencil: false,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(canvas.clientWidth, canvas.clientHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ReinhardToneMapping;
renderer.toneMapping = THREE.NeutralToneMapping;
canvas.appendChild(renderer.domElement);
renderer.toneMappingExposure = 1.5;
renderer.setClearColor(0xffffff, 1.0);
const light = new THREE.DirectionalLight(0xffffff, Math.PI);
light.position.set(1.0, 1.0, 1.0);
scene.add(light);
let currentVrm: any = undefined;
let currentVrmAnimation: any = undefined;
let currentMixer:any = undefined;
let percentComplete = null;
function load(url: string) {
loader.load(
url,
(gltf) => {
tryInitVRM(gltf);
tryInitVRMA(gltf);
},
(xhr) => {
percentComplete = (xhr.loaded / xhr.total) * 100
},
(error) => console.error(error)
);
}
function tryInitVRM(gltf: any) {
const vrm = gltf.userData.vrm;
if ( vrm == null ) {
return;
}
currentVrm = vrm;
scene.add(vrm.scene);
initAnimationClip();
}
function tryInitVRMA(gltf: any) {
const vrmAnimations = gltf.userData.vrmAnimations;
if (vrmAnimations == null) {
return;
}
currentVrmAnimation = vrmAnimations[0] ?? null;
initAnimationClip();
}
function initAnimationClip() {
if (currentVrm && currentVrmAnimation) {
currentMixer = new THREE.AnimationMixer(currentVrm.scene);
const clip = createVRMAnimationClip(currentVrmAnimation, currentVrm);
currentMixer.clipAction(clip).play();
}
}
const loader = new GLTFLoader(manager);
loader.register((parser) => {
return new VRMLoaderPlugin(parser);
});
loader.register((parser) => {
return new VRMAnimationLoaderPlugin(parser);
});
load("/models/default.vrm");
load("/models/default.vrma");
const clock = new THREE.Clock();
clock.start();
onResize();
window.addEventListener('resize', onResize);
function onResize() {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
animate();
function animate() {
const delta = clock.getDelta();
if (currentMixer) {
currentMixer.update(delta);
}
if (currentVrm) {
currentVrm.update(delta);
}
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
})

7
min-ts/tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"skipLibCheck": true
}
}

26
min-ts/webpack.config.js Normal file
View File

@ -0,0 +1,26 @@
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.ts',
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader'
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
output: {
filename: 'main.js',
path: path.join(__dirname, "dist")
},
devServer: {
static: {
directory: path.join(__dirname, "dist"),
}
}
}