11import { NgIf } from '@angular/common' ;
2- import { Component , CUSTOM_ELEMENTS_SCHEMA , ElementRef , inject , ViewChild } from '@angular/core' ;
2+ import { ChangeDetectorRef , Component , CUSTOM_ELEMENTS_SCHEMA , ElementRef , inject , ViewChild } from '@angular/core' ;
33import {
4+ applyProps ,
45 extend ,
6+ injectBeforeRender ,
57 injectNgtLoader ,
68 NgtArgs ,
7- NgtBeforeRenderEvent ,
89 NgtCanvas ,
910 NgtPush ,
1011 NgtState ,
1112 NgtStore ,
1213} from 'angular-three' ;
1314import { map } from 'rxjs' ;
1415import * as THREE from 'three' ;
15- import { CCDIKHelper , DRACOLoader , GLTFLoader , TransformControls } from 'three-stdlib' ;
16+ import { CCDIKHelper , CCDIKSolver , DRACOLoader , GLTFLoader , IKS , OrbitControls , TransformControls } from 'three-stdlib' ;
1617import { DemoOrbitControls } from '../ui-orbit-controls/orbit-controls.component' ;
17- import { AnimationSkinningIKStore } from './animation-skinning-ik.store' ;
1818
1919extend ( { TransformControls, CCDIKHelper } ) ;
2020
2121@Component ( {
22- selector : 'demo-ik-helper' ,
2322 standalone : true ,
2423 template : `
25- <ng-container *ngIf="(ooi$ | ngtPush).kira as kira">
26- <ngt-cCDIK-helper *args="[kira, iks, 0.01]" (beforeRender)="onBeforeRender()" />
27- </ng-container>
28- ` ,
29- imports : [ NgtArgs , NgIf , NgtPush ] ,
30- schemas : [ CUSTOM_ELEMENTS_SCHEMA ] ,
31- } )
32- export class IKHelper {
33- private readonly ikStore = inject ( AnimationSkinningIKStore ) ;
34- readonly iks = this . ikStore . iks ;
35- readonly ooi$ = this . ikStore . select ( 'OOI' ) ;
24+ <ngt-color *args="['#dddddd']" attach="background" />
25+ <ngt-fog-exp2 *args="['#ffffff', 0.17]" attach="fog" />
3626
37- onBeforeRender ( ) {
38- this . ikStore . solver . update ( ) ;
39- }
40- }
27+ <ngt-ambient-light [intensity]="8" color="#ffffff" />
4128
42- @Component ( {
43- selector : 'demo-sphere-camera' ,
44- standalone : true ,
45- template : `
46- <ngt-cube-camera *args="[0.05, 50, cubeRenderTarget]" (beforeRender)="onBeforeRender($any($event))" />
47- ` ,
48- imports : [ NgtArgs ] ,
49- schemas : [ CUSTOM_ELEMENTS_SCHEMA ] ,
50- } )
51- export class SphereCamera {
52- private readonly ikStore = inject ( AnimationSkinningIKStore ) ;
53- readonly cubeRenderTarget = this . ikStore . get ( 'cubeRenderTarget' ) ;
54-
55- onBeforeRender ( { object, state : { gl, scene } } : NgtBeforeRenderEvent < THREE . CubeCamera > ) {
56- const sphere = this . ikStore . OOI . sphere ;
57- if ( sphere ) {
58- sphere . visible = false ;
59- sphere . getWorldPosition ( object . position ) ;
60- object . update ( gl , scene ) ;
61- sphere . visible = true ;
62- }
63- }
64- }
29+ <ngt-primitive *args="[model$ | ngtPush : null]" (afterAttach)="onAfterModelAttach()" />
6530
66- @Component ( {
67- selector : 'demo-kira' ,
68- standalone : true ,
69- template : `
70- <ngt-primitive
71- *args="[model$ | ngtPush : null]"
72- (afterAttach)="onAfterAttach()"
73- (beforeRender)="onBeforeRender()"
31+ <ngt-cube-camera #cubeCamera *args="[0.05, 50, cubeRenderTarget]" />
32+
33+ <ng-container *ngIf="ooi['kira']">
34+ <ngt-cCDIK-helper *args="[ooi['kira'], iks, 0.01]" />
35+ </ng-container>
36+
37+ <demo-orbit-controls [minDistance]="0.2" [maxDistance]="1.5" (ready)="orbitControls = $any($event)" />
38+
39+ <ngt-transform-controls
40+ #transformControls
41+ *args="[camera, glDom]"
42+ [size]="0.75"
43+ [showX]="false"
44+ space="world"
7445 />
7546 ` ,
76- imports : [ NgtArgs , NgtPush ] ,
47+ imports : [ NgtArgs , NgIf , DemoOrbitControls , NgtPush ] ,
7748 schemas : [ CUSTOM_ELEMENTS_SCHEMA ] ,
7849} )
79- export class Kira {
80- private readonly ikStore = inject ( AnimationSkinningIKStore ) ;
81- readonly v0 = new THREE . Vector3 ( ) ;
50+ export class Scene {
51+ readonly iks = [
52+ {
53+ target : 22 , // "target_hand_l"
54+ effector : 6 , // "hand_l"
55+ links : [
56+ {
57+ index : 5 , // "lowerarm_l"
58+ enabled : true ,
59+ rotationMin : new THREE . Vector3 ( 1.2 , - 1.8 , - 0.4 ) ,
60+ rotationMax : new THREE . Vector3 ( 1.7 , - 1.1 , 0.3 ) ,
61+ } ,
62+ {
63+ index : 4 , // "Upperarm_l"
64+ enabled : true ,
65+ rotationMin : new THREE . Vector3 ( 0.1 , - 0.7 , - 1.8 ) ,
66+ rotationMax : new THREE . Vector3 ( 1.1 , 0 , - 1.4 ) ,
67+ } ,
68+ ] ,
69+ } ,
70+ ] ;
71+
72+ readonly cubeRenderTarget = new THREE . WebGLCubeRenderTarget ( 1024 ) ;
73+ readonly material = new THREE . MeshBasicMaterial ( { envMap : this . cubeRenderTarget . texture } ) ;
74+
75+ private readonly store = inject ( NgtStore ) ;
76+ readonly camera = this . store . get ( 'camera' ) ;
77+ readonly glDom = this . store . get ( 'gl' , 'domElement' ) ;
78+
79+ private readonly cdr = inject ( ChangeDetectorRef ) ;
80+
81+ @ViewChild ( 'transformControls' ) transformControls ?: ElementRef < TransformControls > ;
82+ @ViewChild ( 'cubeCamera' ) cubeCamera ?: ElementRef < THREE . CubeCamera > ;
83+ orbitControls ?: OrbitControls ;
84+ solver ?: CCDIKSolver ;
85+
86+ private readonly v0 = new THREE . Vector3 ( ) ;
87+ readonly ooi : Record < string , THREE . Object3D > = { } ;
8288
8389 readonly model$ = injectNgtLoader (
8490 ( ) => GLTFLoader ,
@@ -90,79 +96,66 @@ export class Kira {
9096 }
9197 ) . pipe (
9298 map ( ( gltf ) => {
93- const ooi : Record < string , THREE . Object3D > = { } ;
9499 gltf . scene . traverse ( ( n ) => {
95- if ( n . name === 'head' ) ooi [ 'head' ] = n ;
96- if ( n . name === 'lowerarm_l' ) ooi [ 'lowerarm_l' ] = n ;
97- if ( n . name === 'Upperarm_l' ) ooi [ 'Upperarm_l' ] = n ;
98- if ( n . name === 'hand_l' ) ooi [ 'hand_l' ] = n ;
99- if ( n . name === 'target_hand_l' ) ooi [ 'target_hand_l' ] = n ;
100- if ( n . name === 'boule' ) ooi [ 'sphere' ] = n ;
101- if ( n . name === 'Kira_Shirt_left' ) ooi [ 'kira' ] = n ;
100+ if ( n . name === 'head' ) this . ooi [ 'head' ] = n ;
101+ if ( n . name === 'lowerarm_l' ) this . ooi [ 'lowerarm_l' ] = n ;
102+ if ( n . name === 'Upperarm_l' ) this . ooi [ 'Upperarm_l' ] = n ;
103+ if ( n . name === 'hand_l' ) this . ooi [ 'hand_l' ] = n ;
104+ if ( n . name === 'target_hand_l' ) this . ooi [ 'target_hand_l' ] = n ;
105+ if ( n . name === 'boule' ) this . ooi [ 'sphere' ] = n ;
106+ if ( n . name === 'Kira_Shirt_left' ) this . ooi [ 'kira' ] = n ;
102107 if ( ( n as THREE . Mesh ) . isMesh ) n . frustumCulled = false ;
103108 } ) ;
104- this . ikStore . set ( { OOI : ooi } ) ;
109+ this . cdr . detectChanges ( ) ;
105110 return gltf . scene ;
106111 } )
107112 ) ;
108113
109- onAfterAttach ( ) {
110- this . ikStore . kiraReady ( ) ;
114+ constructor ( ) {
115+ injectBeforeRender ( ( { gl, scene } ) => {
116+ if ( this . ooi [ 'sphere' ] && this . cubeCamera ) {
117+ this . ooi [ 'sphere' ] . visible = false ;
118+ this . ooi [ 'sphere' ] . getWorldPosition ( this . cubeCamera . nativeElement . position ) ;
119+ this . cubeCamera . nativeElement . update ( gl , scene ) ;
120+ this . ooi [ 'sphere' ] . visible = true ;
121+ }
122+
123+ if ( this . solver ) {
124+ this . solver . update ( ) ;
125+ }
126+
127+ const head = this . ooi [ 'head' ] ;
128+ const sphere = this . ooi [ 'sphere' ] ;
129+ if ( head && sphere ) {
130+ sphere . getWorldPosition ( this . v0 ) ;
131+ head . lookAt ( this . v0 ) ;
132+ head . rotation . set ( head . rotation . x , head . rotation . y + Math . PI , head . rotation . z ) ;
133+ }
134+ } ) ;
111135 }
112136
113- onBeforeRender ( ) {
114- const head = this . ikStore . OOI . head ;
115- const sphere = this . ikStore . OOI . sphere ;
116- if ( head && sphere ) {
117- sphere . getWorldPosition ( this . v0 ) ;
118- head . lookAt ( this . v0 ) ;
119- head . rotation . set ( head . rotation . x , head . rotation . y + Math . PI , head . rotation . z ) ;
137+ onAfterModelAttach ( ) {
138+ this . orbitControls ?. target . copy ( this . ooi [ 'sphere' ] . position ) ;
139+ this . ooi [ 'hand_l' ] . attach ( this . ooi [ 'sphere' ] ) ;
140+ applyProps ( this . ooi [ 'sphere' ] , { material : this . material } ) ;
141+
142+ this . transformControls ?. nativeElement . attach ( this . ooi [ 'target_hand_l' ] ) ;
143+ this . ooi [ 'kira' ] . add ( ( this . ooi [ 'kira' ] as THREE . SkinnedMesh ) . skeleton . bones [ 0 ] ) ;
144+ this . solver = new CCDIKSolver ( this . ooi [ 'kira' ] as THREE . SkinnedMesh , this . iks as unknown as IKS [ ] ) ;
145+
146+ if ( this . transformControls && this . orbitControls ) {
147+ this . transformControls . nativeElement . addEventListener (
148+ 'mouseDown' ,
149+ ( ) => ( this . orbitControls ! . enabled = false )
150+ ) ;
151+ this . transformControls . nativeElement . addEventListener (
152+ 'mouseUp' ,
153+ ( ) => ( this . orbitControls ! . enabled = true )
154+ ) ;
120155 }
121156 }
122157}
123158
124- @Component ( {
125- standalone : true ,
126- template : `
127- <ngt-color *args="['#dddddd']" attach="background" />
128- <ngt-fog-exp2 *args="['#ffffff', 0.17]" attach="fog" />
129-
130- <ngt-ambient-light [intensity]="8" color="#ffffff" />
131-
132- <demo-kira />
133- <demo-sphere-camera />
134- <demo-ik-helper />
135-
136- <demo-orbit-controls
137- [minDistance]="0.2"
138- [maxDistance]="1.5"
139- (ready)="ikStore.set({ orbitControls: $any($event) })"
140- />
141-
142- <ngt-transform-controls
143- #transformControls
144- *args="[camera, glDom]"
145- [size]="0.75"
146- [showX]="false"
147- space="world"
148- />
149- ` ,
150- imports : [ NgtArgs , DemoOrbitControls , Kira , SphereCamera , IKHelper ] ,
151- schemas : [ CUSTOM_ELEMENTS_SCHEMA ] ,
152- } )
153- export class Scene {
154- readonly ikStore = inject ( AnimationSkinningIKStore ) ;
155- private readonly store = inject ( NgtStore ) ;
156- readonly camera = this . store . get ( 'camera' ) ;
157- readonly glDom = this . store . get ( 'gl' , 'domElement' ) ;
158-
159- @ViewChild ( 'transformControls' ) set transformControls ( { nativeElement } : ElementRef < TransformControls > ) {
160- this . ikStore . set ( { transformControls : nativeElement } ) ;
161- nativeElement . addEventListener ( 'mouseDown' , ( ) => ( this . ikStore . orbitControls . enabled = false ) ) ;
162- nativeElement . addEventListener ( 'mouseUp' , ( ) => ( this . ikStore . orbitControls . enabled = true ) ) ;
163- }
164- }
165-
166159@Component ( {
167160 standalone : true ,
168161 template : `
@@ -178,7 +171,6 @@ export class Scene {
178171 (created)="onCreated($event)"
179172 />
180173 ` ,
181- providers : [ AnimationSkinningIKStore ] ,
182174 imports : [ NgtCanvas ] ,
183175} )
184176export default class DemoAnimationSkinningIK {
0 commit comments