first update
This commit is contained in:
228
src/index.ts
Normal file
228
src/index.ts
Normal file
@ -0,0 +1,228 @@
|
||||
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 { Color, DirectionalLight, Fog, HemisphereLight } from 'three';
|
||||
import { GridHelper, Mesh, MeshLambertMaterial, BoxGeometry, Vector3 } from 'three';
|
||||
|
||||
import { VRMSpringBoneManager, VRMSpringBoneJoint, VRMSpringBoneJointHelper } from '@pixiv/three-vrm-springbone';
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
const canvas = document.getElementById("canvas");
|
||||
if (canvas == null) return;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
30, canvas.clientWidth/canvas.clientHeight, 0.1, 20);
|
||||
camera.position.set(0.0, 0.9, -4.0)
|
||||
camera.rotation.set(0.0, Math.PI, 0.0)
|
||||
camera.lookAt(new THREE.Vector3(0, 0, 0));
|
||||
|
||||
// https://threejs.org/docs/#api/en/constants/Renderer
|
||||
const renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(canvas.clientWidth, canvas.clientHeight);
|
||||
renderer.setClearColor(0x7fbfff, 1.0);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
renderer.toneMapping = THREE.ReinhardToneMapping;
|
||||
renderer.toneMapping = THREE.NeutralToneMapping;
|
||||
canvas.appendChild(renderer.domElement);
|
||||
renderer.toneMappingExposure = 1.5;
|
||||
|
||||
//renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
|
||||
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;
|
||||
|
||||
function load(url: string) {
|
||||
loader.load(
|
||||
url,
|
||||
(gltf) => {
|
||||
tryInitVRM(gltf);
|
||||
tryInitVRMA(gltf);
|
||||
},
|
||||
(progress) => console.log(
|
||||
"Loading model...",
|
||||
100.0 * (progress.loaded / progress.total), "%"
|
||||
),
|
||||
(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();
|
||||
loader.register((parser) => {
|
||||
return new VRMLoaderPlugin(parser);
|
||||
});
|
||||
loader.register((parser) => {
|
||||
return new VRMAnimationLoaderPlugin(parser);
|
||||
});
|
||||
|
||||
load("/vrma/ai.vrm");
|
||||
load("/vrma/fly_c.vrma");
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
clock.start();
|
||||
|
||||
scene.background = new THREE.Color( 0xffffff );
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff);
|
||||
directionalLight.position.set(1, 1, 1);
|
||||
scene.add(directionalLight);
|
||||
|
||||
const ambientLight = new THREE.AmbientLight(0x333333);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.2;
|
||||
controls.enableRotate = true;
|
||||
controls.target.set( 0.0, 1.0, 0.0 );
|
||||
|
||||
function floor_default(){
|
||||
const floor = new Mesh(
|
||||
new BoxGeometry(50, 100),
|
||||
new MeshLambertMaterial({
|
||||
color: 0xffffff,
|
||||
depthWrite: true,
|
||||
})
|
||||
);
|
||||
floor.position.y = -1.0;
|
||||
floor.rotation.x = -Math.PI / 2;
|
||||
floor.name = "floor";
|
||||
scene.add(floor);
|
||||
|
||||
}
|
||||
|
||||
function floor_grid(){
|
||||
const grid = new GridHelper(50, 100, 0xffffff, 0xffffff);
|
||||
scene.add(grid);
|
||||
grid.position.set(Math.round(0), 0, Math.round(0));
|
||||
}
|
||||
function floor_bg(){
|
||||
scene.fog = new Fog(0xffffff, 3, 20);
|
||||
scene.fog?.color.set(0xffffff);
|
||||
}
|
||||
|
||||
floor_default();
|
||||
floor_grid();
|
||||
floor_bg();
|
||||
|
||||
function animate() {
|
||||
controls.update();
|
||||
const delta = clock.getDelta();
|
||||
if (currentMixer) {
|
||||
currentMixer.update(delta);
|
||||
}
|
||||
if (currentVrm) {
|
||||
currentVrm.update(delta);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
scene.rotation.y += 0.005;
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
|
||||
function random_happy() {
|
||||
// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.ja.md
|
||||
currentVrm.expressionManager.setValue('relaxed', 0.5);
|
||||
}
|
||||
|
||||
function random_head() {
|
||||
// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/lookAt.ja.md
|
||||
currentVrm.lookAt.target = camera;
|
||||
currentVrm.VRMLookAtBoneApplier = camera;
|
||||
currentVrm.VRMLookAtExpressionApplier = camera;
|
||||
|
||||
// https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/humanoid.ja.md
|
||||
const head = currentVrm.humanoid.getRawBoneNode("head");
|
||||
head.target = camera;
|
||||
}
|
||||
|
||||
function random_blink(){
|
||||
setInterval(() => {
|
||||
currentVrm.expressionManager.setValue('relaxed', 0);
|
||||
currentVrm.expressionManager.setValue('blink', 0);
|
||||
random_head();
|
||||
const r = Math.floor(Math.random() * 3);
|
||||
if (r == 1) {
|
||||
setTimeout(() => { currentVrm.expressionManager.setValue('blink', 1); }, 5000);
|
||||
setTimeout(() => {
|
||||
currentVrm.expressionManager.setValue('blink', 0);
|
||||
}, 5500);
|
||||
};
|
||||
setTimeout(() => {
|
||||
currentVrm.expressionManager.setValue('relaxed', 0.5);
|
||||
currentVrm.expressionManager.setValue('blink', 1);
|
||||
}, 6000);
|
||||
}, 6500);
|
||||
}
|
||||
random_blink();
|
||||
|
||||
setInterval(() => {
|
||||
const r = Math.floor(Math.random() * 4 + 1);
|
||||
load("/vrma/" + r + ".vrma");
|
||||
setTimeout(() => {
|
||||
load("/vrma/fly_c.vrma");
|
||||
}, 10000);
|
||||
}, 15000);
|
||||
|
||||
const el_light = document.querySelector('#btn-moon') as HTMLInputElement | null;
|
||||
if(el_light != null) {
|
||||
el_light.addEventListener('click', function(){
|
||||
light_off();
|
||||
});
|
||||
}
|
||||
|
||||
let light_enable = true;
|
||||
function light_off(){
|
||||
if (light_enable == true) {
|
||||
light_enable = false;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
light.intensity = -0.5;
|
||||
scene.background = new THREE.Color(0x000000);
|
||||
scene.fog = new Fog(0x000000, 3, 20);
|
||||
} else {
|
||||
light_enable = true;
|
||||
renderer.toneMapping = THREE.NeutralToneMapping;
|
||||
light.intensity = 1;
|
||||
scene.background = new THREE.Color(0xffffff);
|
||||
scene.fog = new Fog(0xffffff, 3, 20);
|
||||
}
|
||||
console.log(light_enable);
|
||||
}
|
||||
})
|
Reference in New Issue
Block a user