Initial commit
|
@ -0,0 +1 @@
|
|||
assets
|
|
@ -0,0 +1,79 @@
|
|||
# TP Interaction
|
||||
|
||||
Ce TP a pour but de vous faire coder des interactions avec un modèle 3D. Pour
|
||||
cela, vous implémenterez en Javascript des interactions avec la souris et avec
|
||||
les touches du clavier qui permettent de changer de point de vue, c'est à dire,
|
||||
de mettre à jour la position et l'orientation de la caméra (Partie 1), et
|
||||
ensuite d'enregistrer de tels points de vues pour permettre une navigation plus
|
||||
haut niveau (Partie 2).
|
||||
|
||||
Ce TP sera fait pendant les séances consacrées (un TP jeudi 9, un TP jeudi 16).
|
||||
|
||||
### Cloner le repository
|
||||
|
||||
```
|
||||
git clone https://gitea.tforgione.fr/tforgione/tp-interaction
|
||||
```
|
||||
|
||||
### Lancer le server
|
||||
|
||||
```
|
||||
python -m SimpleHTTPServer
|
||||
```
|
||||
|
||||
Vous pouvez ensuite aller sur la page [localhost:8000](http://localhost:8000)
|
||||
pour lancer l'interface. Pour voir la console vous pouvez cliquer sur `F12`,
|
||||
ce qui vous permettra de debugger plus facilement.
|
||||
|
||||
### Sujet
|
||||
|
||||
#### Partie 1 : interaction clavier / souris
|
||||
|
||||
L'objectif de cette premiere partie est d'implémenter les interactions type
|
||||
*free fly camera*. Nous vous proposons de mettre à jour les interactions avec
|
||||
la souris pour tourner la caméra et avec le clavier pour la deplacer.
|
||||
|
||||
L'utilisateur peut appuyer sur les flèches du clavier pour déplacer la caméra :
|
||||
- flèche en haut (ou touche z) pour avancer
|
||||
- flèche du bas (ou touche s) pour reculer
|
||||
- flèche de gauche (ou touche q) pour se translater vers la gauche
|
||||
- flèche de droite (ou touche d) pour se translater vers la droite
|
||||
|
||||
Ces directions seront définies à partir de l'orientation de la caméra, donnée
|
||||
par 2 angles `theta` et `delta`.
|
||||
|
||||
![](https://gitea.tforgione.fr/tforgione/tp-interaction/src/branch/master/assets/scheme.svg)
|
||||
|
||||
Vous pouvez trouver des exemples de coordonnées sphériques sur
|
||||
[wikipedia](https://fr.wikipedia.org/wiki/Coordonn%C3%A9es_sph%C3%A9riques).
|
||||
|
||||
**Attention** : dans THREE.js, l'axe des y est celui qui va vers le haut.
|
||||
|
||||
Pour cette partie, vous aurez besoin de compléter les *TODO Part 1* du fichier
|
||||
`js/main.js`.
|
||||
|
||||
#### Partie 2 : interaction via point de vue
|
||||
|
||||
L'objectif de cette deuxième partie est d'utiliser les points de vue
|
||||
enregistrés pour faciliter l'interaction. Pour commencer, vous pouvez
|
||||
décommenter les lignes 236 à 239 du fichier `js/main.js` pour faire apparaitre
|
||||
un point de vue. Vous devez ensuite compléter les *TODO Part 2* pour permettre
|
||||
à un utilisateur de cliquer sur un point de vue pour s'y déplacer.
|
||||
|
||||
### Les vecteurs dans THREE.js
|
||||
|
||||
Ce TP utilise le moteur de rendu THREE.js. Puisque javascript ne permet pas la
|
||||
surcharge d'opérateurs, il est impossible d'écrire `x + y` quand `x` et `y`
|
||||
sont des vecteurs de THREE.js. Ansi, THREE.js définit des méthodes pour
|
||||
effectuer ces opérations :
|
||||
|
||||
| Avec opérateurs | En THREE.js |
|
||||
|:----:|:---:|
|
||||
| `a += b` | `a.add(b)` |
|
||||
| `a -= b` | `a.sub(b)` |
|
||||
| `a *= l` | `a.multiplyScalar(l)` |
|
||||
| `a = b` | `a.copy(b)` |
|
||||
| `a + b` | `a.clone().add(b)` |
|
||||
| `a = b + c` | `a.copy(b.clone().add(c))` |
|
||||
| ... | ... |
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="360" height="360" version="1.1">
|
||||
|
||||
<g id="Coord_LatLong" transform="translate(159.5, 195.5) scale(1,-1)">
|
||||
<path d="M -143,0 A 143,62 0 1 0 143,0" style="stroke:#808080;stroke-width:1;stroke-dasharray:6,6;fill:none;"/>
|
||||
<path d="M 0,143 A 143,60 -90 1 1 0,-143" transform="rotate(13)" style="stroke:#808080;stroke-dasharray:6,6;stroke-width:1;fill:none;"/>
|
||||
|
||||
<path d="M -125,0 H 186" transform="rotate(-135)" style="stroke:#000000;stroke-width:1;fill:none;"/>
|
||||
<path d="M 0,-2.5 L 4,-3 L 2,4 L 0,12 L -2,4 L -4,-3 L 0,-2.5 Z" transform="rotate(-225) translate(0,186)" style="stroke:none;fill:#000000;"/>
|
||||
|
||||
<path d="M -155,0 H 188" transform="rotate(-10.6)" style="stroke:#000000;stroke-width:1;fill:none;"/>
|
||||
<path d="M 0,-2.5 L 4,-3 L 2,4 L 0,12 L -2,4 L -4,-3 L 0,-2.5 Z" transform="rotate(-10.6) translate(188,0) rotate(270)" style="stroke:none;fill:#000000;"/>
|
||||
|
||||
<path d="M 0,-163 V 177" style="stroke:#000000;stroke-width:1;fill:none;"/>
|
||||
<path d="M 0,-2.5 L 4,-3 L 2,4 L 0,12 L -2,4 L -4,-3 L 0,-2.5 Z" transform="translate(0,177)" style="stroke:none;fill:#000000;"/>
|
||||
|
||||
<circle cx="0" cy="0" r="143" style="stroke:#000000;stroke-width:2;fill:none;"/>
|
||||
|
||||
<path d="M 0,-143 A 143,60 -90 1 1 0,143" transform="rotate(13)" style="stroke:#000000;stroke-width:1;fill:none;"/>
|
||||
<path d="M -143,0 A 143,62 0 1 1 143,0" style="stroke:#000000;stroke-width:1;fill:none;"/>
|
||||
|
||||
<path d="M 0,0 L -56.88,-56.88 A 143,62 0 0 1 66.73,-54.84 L 0,0 Z" style="stroke:none;fill:#204a87;opacity:0.2;"/>
|
||||
<path d="M 0,0 L 52.68,-68.44 A 143,60 -90 0 1 53.71,63.72 L 0,0 Z" transform="rotate(13)" style="stroke:none;fill:#f57900;opacity:0.3;"/>
|
||||
|
||||
<path d="M 0,0 L 38,74.17" style="stroke:#4e9a06;stroke-width:2;fill:none;"/>
|
||||
<path d="M 0,0 L -10,3 L -10,-3 L 0,0 Z" transform="translate(38, 74.17) rotate(63)" style="stroke:#4e9a06;stroke-width:2;fill:#4e9a06;"/>
|
||||
|
||||
<path d="M 52.68,-68.44 A 143,60 -90 0 1 53.71,63.72" transform="rotate(13)" style="stroke:#f57900;stroke-width:2;fill:none;"/>
|
||||
<path d="M 0,0 L -10,3 L -10,-3 L 0,0 Z" transform="translate(38, 74.17) rotate(112)" style="stroke:#f57900;stroke-width:2;fill:#f57900;"/>
|
||||
|
||||
<path d="M -56.88,-56.88 A 143,62 0 0 1 62,-55.87" style="stroke:#204a87;stroke-width:2;fill:none;"/>
|
||||
<path d="M 0,0 L -10,3 L -10,-3 L 0,0 Z" transform="translate(66.73,-54.84) rotate(11)" style="stroke:#204a87;stroke-width:2;fill:#204a87;"/>
|
||||
|
||||
<circle cx="38" cy="74.17" r="4" style="stroke:none;fill:#5c3566;"/>
|
||||
<circle cx="0" cy="0" r="2" style="stroke:none;fill:#000000;"/>
|
||||
|
||||
<text transform="scale(1,-1)" x="6" y="-44" xml:space="preserve" style="font-size:28px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="6" y="-44">ρ</tspan>
|
||||
</text>
|
||||
|
||||
<text transform="scale(1,-1)" x="64" y="-10" xml:space="preserve" style="font-size:28px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="64" y="-10">δ</tspan>
|
||||
</text>
|
||||
|
||||
<text transform="scale(1,-1)" x="-22" y="90" xml:space="preserve" style="font-size:28px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="-22" y="90">θ</tspan>
|
||||
</text>
|
||||
|
||||
<text transform="scale(1,-1)" x="45" y="-78" xml:space="preserve" style="font-size:28px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="45" y="-78">P</tspan>
|
||||
</text>
|
||||
|
||||
<g transform="translate(-127,-154) scale(1,-1)">
|
||||
<text x="0" y="0" xml:space="preserve" style="font-size:32px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="0" y="0">z</tspan>
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(167,-65) scale(1,-1)">
|
||||
<text x="0" y="0" xml:space="preserve" style="font-size:32px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="0" y="0">x</tspan>
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(10,170) scale(1,-1)">
|
||||
<text x="0" y="0" xml:space="preserve" style="font-size:32px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;stroke:none;font-family:DejaVu Serif;-inkscape-font-specification:DejaVu Serif Italic"><tspan x="0" y="0">y</tspan>
|
||||
</text>
|
||||
</g>
|
||||
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.4 KiB |
|
@ -0,0 +1,354 @@
|
|||
# Blender MTL File: 'None'
|
||||
# Material Count: 32
|
||||
|
||||
newmtl m0lambea_v_x_v_x
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd a_tuta.png
|
||||
|
||||
newmtl m10lambert12_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_siba04.png
|
||||
|
||||
newmtl m11lambert14_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd rotennuno85.png
|
||||
|
||||
newmtl m12lambert15_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd wood04.png
|
||||
|
||||
newmtl m13lambert2_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd a_kusa.png
|
||||
|
||||
newmtl m14lambert6_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_yuka10.png
|
||||
|
||||
newmtl m15lambert74_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd a_iwa.png
|
||||
|
||||
newmtl m16lambert75_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd rotennuno4.png
|
||||
|
||||
newmtl m17lambert84_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_kabe33.png
|
||||
|
||||
newmtl m18lambert85_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_ren15.png
|
||||
|
||||
newmtl m19lambert8_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_miti05.png
|
||||
|
||||
newmtl m1lambert100_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_ki12.png
|
||||
|
||||
newmtl m20lambert92_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_yane08.png
|
||||
|
||||
newmtl m21lambert94_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_ki13.png
|
||||
|
||||
newmtl m22lambert95_v_x_v_x
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd a_kusa_yane.png
|
||||
|
||||
newmtl m23lambert98_v_x_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd gakkou03.png
|
||||
|
||||
newmtl m24lambert98_v_x_v_x
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd gakkou03.png
|
||||
|
||||
newmtl m25lambert99_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_mado08.png
|
||||
|
||||
newmtl m26lambertaa_v_v_x
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd a_kysakiwa.png
|
||||
|
||||
newmtl m27lambv_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_mado02.png
|
||||
|
||||
newmtl m28test_lambert105_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_leaf01.png
|
||||
|
||||
newmtl m29test_lambert48_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd k_taru04.png
|
||||
|
||||
newmtl m2lambert101_v_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_komono11.png
|
||||
|
||||
newmtl m30test_lambert49_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd k_taru05.png
|
||||
|
||||
newmtl m31lambert12_v_v_2_
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_siba04.png
|
||||
|
||||
newmtl m3lambert102_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_ren16.png
|
||||
|
||||
newmtl m4lambert103_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_kabe38.png
|
||||
|
||||
newmtl m5lambert104_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_leaf05.png
|
||||
|
||||
newmtl m6lambert107_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd m_leaf09.png
|
||||
|
||||
newmtl m7lambert10_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd wood01.png
|
||||
|
||||
newmtl m8lambert115_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd rotennuno70.png
|
||||
|
||||
newmtl m9lambert11_v_v
|
||||
Ns 0.000000
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.640000 0.640000 0.640000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Kd wood06.png
|
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 590 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 639 B |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TP</title>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="js/three.min.js"></script>
|
||||
<script src="js/OBJLoader.js"></script>
|
||||
<script src="js/MTLLoader.js"></script>
|
||||
<script src="js/Bookmark.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,83 @@
|
|||
class Bookmark extends THREE.Object3D {
|
||||
constructor(position, target, scale = 500.0) {
|
||||
super();
|
||||
|
||||
position = new THREE.Vector3().copy(position);
|
||||
target = new THREE.Vector3().copy(target);
|
||||
|
||||
this.position.copy(position);
|
||||
this.target = new THREE.Vector3().copy(target);
|
||||
|
||||
this.t = 0;
|
||||
|
||||
let material = new THREE.LineBasicMaterial({
|
||||
color: 0xffffff,
|
||||
linewidth: 3,
|
||||
});
|
||||
let geometry = new THREE.Geometry();
|
||||
|
||||
let direction = this.target.clone().sub(position).normalize().multiplyScalar(this.length());
|
||||
|
||||
geometry.vertices.push(new THREE.Vector3(0.0, -1000000.0, 0.0));
|
||||
geometry.vertices.push(new THREE.Vector3(0.0, 0.0, 0.0));
|
||||
|
||||
this.line = new THREE.Line(geometry, material);
|
||||
this.add(this.line);
|
||||
|
||||
this.numberOfPoints = 20;
|
||||
this.createCircle();
|
||||
this._shining = false;
|
||||
|
||||
this.t = 0;
|
||||
}
|
||||
|
||||
createCircle() {
|
||||
let map = new THREE.TextureLoader().load("assets/eye.png");
|
||||
let material = new THREE.SpriteMaterial({
|
||||
map: map,
|
||||
color: 0xfffffff,
|
||||
transparent: true,
|
||||
});
|
||||
let geometry = new THREE.Geometry();
|
||||
this.circle = new THREE.Sprite(material);
|
||||
this.add(this.circle);
|
||||
}
|
||||
|
||||
length() {
|
||||
return 25 * (Math.cos(this.t) + 5);
|
||||
}
|
||||
|
||||
get shining() {
|
||||
return this._shining;
|
||||
}
|
||||
|
||||
set shining(other) {
|
||||
this._shining = other;
|
||||
if (!other) {
|
||||
this.circle.material.color = new THREE.Color(1, 1, 1);
|
||||
this.line.material.color = new THREE.Color(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
update(camera) {
|
||||
// super.update(camera);
|
||||
|
||||
/// assert(camera instanceof THREE.Camera);
|
||||
let distance = this.localToWorld(this.position.clone()).distanceTo(camera.position);
|
||||
this.t += 0.05;
|
||||
let l = this.length();
|
||||
this.circle.scale.x = l * Math.log(1 + distance);
|
||||
this.circle.scale.y = l * Math.log(1 + distance);
|
||||
this.circle.scale.z = l * Math.log(1 + distance);
|
||||
this.line.geometry.vertices[1].y = -this.circle.scale.x / 2;
|
||||
this.line.geometry.verticesNeedUpdate = true;
|
||||
|
||||
if (this.shining) {
|
||||
let value = (1 + Math.cos(Math.PI / 2 + this.t * 2)) / 2;
|
||||
this.circle.material.color = new THREE.Color(1 - value, value, 0);
|
||||
this.line.material.color = new THREE.Color(1 - value, value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,532 @@
|
|||
/**
|
||||
* Loads a Wavefront .mtl file specifying materials
|
||||
*
|
||||
* @author angelxuanchang
|
||||
*/
|
||||
|
||||
THREE.MTLLoader = function ( manager ) {
|
||||
|
||||
THREE.Loader.call( this, manager );
|
||||
|
||||
};
|
||||
|
||||
THREE.MTLLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
|
||||
|
||||
constructor: THREE.MTLLoader,
|
||||
|
||||
/**
|
||||
* Loads and parses a MTL asset from a URL.
|
||||
*
|
||||
* @param {String} url - URL to the MTL file.
|
||||
* @param {Function} [onLoad] - Callback invoked with the loaded object.
|
||||
* @param {Function} [onProgress] - Callback for download progress.
|
||||
* @param {Function} [onError] - Callback for download errors.
|
||||
*
|
||||
* @see setPath setResourcePath
|
||||
*
|
||||
* @note In order for relative texture references to resolve correctly
|
||||
* you must call setResourcePath() explicitly prior to load.
|
||||
*/
|
||||
load: function ( url, onLoad, onProgress, onError ) {
|
||||
|
||||
var scope = this;
|
||||
|
||||
var path = ( this.path === '' ) ? THREE.LoaderUtils.extractUrlBase( url ) : this.path;
|
||||
|
||||
var loader = new THREE.FileLoader( this.manager );
|
||||
loader.setPath( this.path );
|
||||
loader.load( url, function ( text ) {
|
||||
|
||||
onLoad( scope.parse( text, path ) );
|
||||
|
||||
}, onProgress, onError );
|
||||
|
||||
},
|
||||
|
||||
setMaterialOptions: function ( value ) {
|
||||
|
||||
this.materialOptions = value;
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a MTL file.
|
||||
*
|
||||
* @param {String} text - Content of MTL file
|
||||
* @return {THREE.MTLLoader.MaterialCreator}
|
||||
*
|
||||
* @see setPath setResourcePath
|
||||
*
|
||||
* @note In order for relative texture references to resolve correctly
|
||||
* you must call setResourcePath() explicitly prior to parse.
|
||||
*/
|
||||
parse: function ( text, path ) {
|
||||
|
||||
var lines = text.split( '\n' );
|
||||
var info = {};
|
||||
var delimiter_pattern = /\s+/;
|
||||
var materialsInfo = {};
|
||||
|
||||
for ( var i = 0; i < lines.length; i ++ ) {
|
||||
|
||||
var line = lines[ i ];
|
||||
line = line.trim();
|
||||
|
||||
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
|
||||
|
||||
// Blank line or comment ignore
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
var pos = line.indexOf( ' ' );
|
||||
|
||||
var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
|
||||
key = key.toLowerCase();
|
||||
|
||||
var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';
|
||||
value = value.trim();
|
||||
|
||||
if ( key === 'newmtl' ) {
|
||||
|
||||
// New material
|
||||
|
||||
info = { name: value };
|
||||
materialsInfo[ value ] = info;
|
||||
|
||||
} else {
|
||||
|
||||
if ( key === 'ka' || key === 'kd' || key === 'ks' || key === 'ke' ) {
|
||||
|
||||
var ss = value.split( delimiter_pattern, 3 );
|
||||
info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
|
||||
|
||||
} else {
|
||||
|
||||
info[ key ] = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var materialCreator = new THREE.MTLLoader.MaterialCreator( this.resourcePath || path, this.materialOptions );
|
||||
materialCreator.setCrossOrigin( this.crossOrigin );
|
||||
materialCreator.setManager( this.manager );
|
||||
materialCreator.setMaterials( materialsInfo );
|
||||
return materialCreator;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
/**
|
||||
* Create a new THREE.MTLLoader.MaterialCreator
|
||||
* @param baseUrl - Url relative to which textures are loaded
|
||||
* @param options - Set of options on how to construct the materials
|
||||
* side: Which side to apply the material
|
||||
* THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
|
||||
* wrap: What type of wrapping to apply for textures
|
||||
* THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
|
||||
* normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
|
||||
* Default: false, assumed to be already normalized
|
||||
* ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
|
||||
* Default: false
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
THREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) {
|
||||
|
||||
this.baseUrl = baseUrl || '';
|
||||
this.options = options;
|
||||
this.materialsInfo = {};
|
||||
this.materials = {};
|
||||
this.materialsArray = [];
|
||||
this.nameLookup = {};
|
||||
|
||||
this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
|
||||
this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
|
||||
|
||||
};
|
||||
|
||||
THREE.MTLLoader.MaterialCreator.prototype = {
|
||||
|
||||
constructor: THREE.MTLLoader.MaterialCreator,
|
||||
|
||||
crossOrigin: 'anonymous',
|
||||
|
||||
setCrossOrigin: function ( value ) {
|
||||
|
||||
this.crossOrigin = value;
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setManager: function ( value ) {
|
||||
|
||||
this.manager = value;
|
||||
|
||||
},
|
||||
|
||||
setMaterials: function ( materialsInfo ) {
|
||||
|
||||
this.materialsInfo = this.convert( materialsInfo );
|
||||
this.materials = {};
|
||||
this.materialsArray = [];
|
||||
this.nameLookup = {};
|
||||
|
||||
},
|
||||
|
||||
convert: function ( materialsInfo ) {
|
||||
|
||||
if ( ! this.options ) return materialsInfo;
|
||||
|
||||
var converted = {};
|
||||
|
||||
for ( var mn in materialsInfo ) {
|
||||
|
||||
// Convert materials info into normalized form based on options
|
||||
|
||||
var mat = materialsInfo[ mn ];
|
||||
|
||||
var covmat = {};
|
||||
|
||||
converted[ mn ] = covmat;
|
||||
|
||||
for ( var prop in mat ) {
|
||||
|
||||
var save = true;
|
||||
var value = mat[ prop ];
|
||||
var lprop = prop.toLowerCase();
|
||||
|
||||
switch ( lprop ) {
|
||||
|
||||
case 'kd':
|
||||
case 'ka':
|
||||
case 'ks':
|
||||
|
||||
// Diffuse color (color under white light) using RGB values
|
||||
|
||||
if ( this.options && this.options.normalizeRGB ) {
|
||||
|
||||
value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
|
||||
|
||||
}
|
||||
|
||||
if ( this.options && this.options.ignoreZeroRGBs ) {
|
||||
|
||||
if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {
|
||||
|
||||
// ignore
|
||||
|
||||
save = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ( save ) {
|
||||
|
||||
covmat[ lprop ] = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return converted;
|
||||
|
||||
},
|
||||
|
||||
preload: function () {
|
||||
|
||||
for ( var mn in this.materialsInfo ) {
|
||||
|
||||
this.create( mn );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getIndex: function ( materialName ) {
|
||||
|
||||
return this.nameLookup[ materialName ];
|
||||
|
||||
},
|
||||
|
||||
getAsArray: function () {
|
||||
|
||||
var index = 0;
|
||||
|
||||
for ( var mn in this.materialsInfo ) {
|
||||
|
||||
this.materialsArray[ index ] = this.create( mn );
|
||||
this.nameLookup[ mn ] = index;
|
||||
index ++;
|
||||
|
||||
}
|
||||
|
||||
return this.materialsArray;
|
||||
|
||||
},
|
||||
|
||||
create: function ( materialName ) {
|
||||
|
||||
if ( this.materials[ materialName ] === undefined ) {
|
||||
|
||||
this.createMaterial_( materialName );
|
||||
|
||||
}
|
||||
|
||||
return this.materials[ materialName ];
|
||||
|
||||
},
|
||||
|
||||
createMaterial_: function ( materialName ) {
|
||||
|
||||
// Create material
|
||||
|
||||
var scope = this;
|
||||
var mat = this.materialsInfo[ materialName ];
|
||||
var params = {
|
||||
|
||||
name: materialName,
|
||||
side: this.side
|
||||
|
||||
};
|
||||
|
||||
function resolveURL( baseUrl, url ) {
|
||||
|
||||
if ( typeof url !== 'string' || url === '' )
|
||||
return '';
|
||||
|
||||
// Absolute URL
|
||||
if ( /^https?:\/\//i.test( url ) ) return url;
|
||||
|
||||
return baseUrl + url;
|
||||
|
||||
}
|
||||
|
||||
function setMapForType( mapType, value ) {
|
||||
|
||||
if ( params[ mapType ] ) return; // Keep the first encountered texture
|
||||
|
||||
var texParams = scope.getTextureParams( value, params );
|
||||
var map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );
|
||||
|
||||
map.repeat.copy( texParams.scale );
|
||||
map.offset.copy( texParams.offset );
|
||||
|
||||
map.wrapS = scope.wrap;
|
||||
map.wrapT = scope.wrap;
|
||||
|
||||
params[ mapType ] = map;
|
||||
|
||||
}
|
||||
|
||||
for ( var prop in mat ) {
|
||||
|
||||
var value = mat[ prop ];
|
||||
var n;
|
||||
|
||||
if ( value === '' ) continue;
|
||||
|
||||
switch ( prop.toLowerCase() ) {
|
||||
|
||||
// Ns is material specular exponent
|
||||
|
||||
case 'kd':
|
||||
|
||||
// Diffuse color (color under white light) using RGB values
|
||||
|
||||
params.color = new THREE.Color().fromArray( value );
|
||||
|
||||
break;
|
||||
|
||||
case 'ks':
|
||||
|
||||
// Specular color (color when light is reflected from shiny surface) using RGB values
|
||||
params.specular = new THREE.Color().fromArray( value );
|
||||
|
||||
break;
|
||||
|
||||
case 'ke':
|
||||
|
||||
// Emissive using RGB values
|
||||
params.emissive = new THREE.Color().fromArray( value );
|
||||
|
||||
break;
|
||||
|
||||
case 'map_kd':
|
||||
|
||||
// Diffuse texture map
|
||||
|
||||
setMapForType( "map", value );
|
||||
|
||||
break;
|
||||
|
||||
case 'map_ks':
|
||||
|
||||
// Specular map
|
||||
|
||||
setMapForType( "specularMap", value );
|
||||
|
||||
break;
|
||||
|
||||
case 'map_ke':
|
||||
|
||||
// Emissive map
|
||||
|
||||
setMapForType( "emissiveMap", value );
|
||||
|
||||
break;
|
||||
|
||||
case 'norm':
|
||||
|
||||
setMapForType( "normalMap", value );
|
||||
|
||||
break;
|
||||
|
||||
case 'map_bump':
|
||||
case 'bump':
|
||||
|
||||
// Bump texture map
|
||||
|
||||
setMapForType( "bumpMap", value );
|
||||
|
||||
break;
|
||||
|
||||
case 'map_d':
|
||||
|
||||
// Alpha map
|
||||
|
||||
setMapForType( "alphaMap", value );
|
||||
params.transparent = true;
|
||||
|
||||
break;
|
||||
|
||||
case 'ns':
|
||||
|
||||
// The specular exponent (defines the focus of the specular highlight)
|
||||
// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
|
||||
|
||||
params.shininess = parseFloat( value );
|
||||
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
n = parseFloat( value );
|
||||
|
||||
if ( n < 1 ) {
|
||||
|
||||
params.opacity = n;
|
||||
params.transparent = true;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'tr':
|
||||
n = parseFloat( value );
|
||||
|
||||
if ( this.options && this.options.invertTrProperty ) n = 1 - n;
|
||||
|
||||
if ( n > 0 ) {
|
||||
|
||||
params.opacity = 1 - n;
|
||||
params.transparent = true;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
|
||||
return this.materials[ materialName ];
|
||||
|
||||
},
|
||||
|
||||
getTextureParams: function ( value, matParams ) {
|
||||
|
||||
var texParams = {
|
||||
|
||||
scale: new THREE.Vector2( 1, 1 ),
|
||||
offset: new THREE.Vector2( 0, 0 )
|
||||
|
||||
};
|
||||
|
||||
var items = value.split( /\s+/ );
|
||||
var pos;
|
||||
|
||||
pos = items.indexOf( '-bm' );
|
||||
|
||||
if ( pos >= 0 ) {
|
||||
|
||||
matParams.bumpScale = parseFloat( items[ pos + 1 ] );
|
||||
items.splice( pos, 2 );
|
||||
|
||||
}
|
||||
|
||||
pos = items.indexOf( '-s' );
|
||||
|
||||
if ( pos >= 0 ) {
|
||||
|
||||
texParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
|
||||
items.splice( pos, 4 ); // we expect 3 parameters here!
|
||||
|
||||
}
|
||||
|
||||
pos = items.indexOf( '-o' );
|
||||
|
||||
if ( pos >= 0 ) {
|
||||
|
||||
texParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );
|
||||
items.splice( pos, 4 ); // we expect 3 parameters here!
|
||||
|
||||
}
|
||||
|
||||
texParams.url = items.join( ' ' ).trim();
|
||||
return texParams;
|
||||
|
||||
},
|
||||
|
||||
loadTexture: function ( url, mapping, onLoad, onProgress, onError ) {
|
||||
|
||||
var texture;
|
||||
var manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;
|
||||
var loader = manager.getHandler( url );
|
||||
|
||||
if ( loader === null ) {
|
||||
|
||||
loader = new THREE.TextureLoader( manager );
|
||||
|
||||
}
|
||||
|
||||
if ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );
|
||||
texture = loader.load( url, onLoad, onProgress, onError );
|
||||
|
||||
if ( mapping !== undefined ) texture.mapping = mapping;
|
||||
|
||||
return texture;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,797 @@
|
|||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
THREE.OBJLoader = ( function () {
|
||||
|
||||
// o object_name | g group_name
|
||||
var object_pattern = /^[og]\s*(.+)?/;
|
||||
// mtllib file_reference
|
||||
var material_library_pattern = /^mtllib /;
|
||||
// usemtl material_name
|
||||
var material_use_pattern = /^usemtl /;
|
||||
// usemap map_name
|
||||
var map_use_pattern = /^usemap /;
|
||||
|
||||
function ParserState() {
|
||||
|
||||
var state = {
|
||||
objects: [],
|
||||
object: {},
|
||||
|
||||
vertices: [],
|
||||
normals: [],
|
||||
colors: [],
|
||||
uvs: [],
|
||||
|
||||
materialLibraries: [],
|
||||
|
||||
startObject: function ( name, fromDeclaration ) {
|
||||
|
||||
// If the current object (initial from reset) is not from a g/o declaration in the parsed
|
||||
// file. We need to use it for the first parsed g/o to keep things in sync.
|
||||
if ( this.object && this.object.fromDeclaration === false ) {
|
||||
|
||||
this.object.name = name;
|
||||
this.object.fromDeclaration = ( fromDeclaration !== false );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
|
||||
|
||||
if ( this.object && typeof this.object._finalize === 'function' ) {
|
||||
|
||||
this.object._finalize( true );
|
||||
|
||||
}
|
||||
|
||||
this.object = {
|
||||
name: name || '',
|
||||
fromDeclaration: ( fromDeclaration !== false ),
|
||||
|
||||
geometry: {
|
||||
vertices: [],
|
||||
normals: [],
|
||||
colors: [],
|
||||
uvs: []
|
||||
},
|
||||
materials: [],
|
||||
smooth: true,
|
||||
|
||||
startMaterial: function ( name, libraries ) {
|
||||
|
||||
var previous = this._finalize( false );
|
||||
|
||||
// New usemtl declaration overwrites an inherited material, except if faces were declared
|
||||
// after the material, then it must be preserved for proper MultiMaterial continuation.
|
||||
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
|
||||
|
||||
this.materials.splice( previous.index, 1 );
|
||||
|
||||
}
|
||||
|
||||
var material = {
|
||||
index: this.materials.length,
|
||||
name: name || '',
|
||||
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
|
||||
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
|
||||
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
|
||||
groupEnd: - 1,
|
||||
groupCount: - 1,
|
||||
inherited: false,
|
||||
|
||||
clone: function ( index ) {
|
||||
|
||||
var cloned = {
|
||||
index: ( typeof index === 'number' ? index : this.index ),
|
||||
name: this.name,
|
||||
mtllib: this.mtllib,
|
||||
smooth: this.smooth,
|
||||
groupStart: 0,
|
||||
groupEnd: - 1,
|
||||
groupCount: - 1,
|
||||
inherited: false
|
||||
};
|
||||
cloned.clone = this.clone.bind( cloned );
|
||||
return cloned;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.materials.push( material );
|
||||
|
||||
return material;
|
||||
|
||||
},
|
||||
|
||||
currentMaterial: function () {
|
||||
|
||||
if ( this.materials.length > 0 ) {
|
||||
|
||||
return this.materials[ this.materials.length - 1 ];
|
||||
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
},
|
||||
|
||||
_finalize: function ( end ) {
|
||||
|
||||
var lastMultiMaterial = this.currentMaterial();
|
||||
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
|
||||
|
||||
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
|
||||
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
|
||||
lastMultiMaterial.inherited = false;
|
||||
|
||||
}
|
||||
|
||||
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
|
||||
if ( end && this.materials.length > 1 ) {
|
||||
|
||||
for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
|
||||
|
||||
if ( this.materials[ mi ].groupCount <= 0 ) {
|
||||
|
||||
this.materials.splice( mi, 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Guarantee at least one empty material, this makes the creation later more straight forward.
|
||||
if ( end && this.materials.length === 0 ) {
|
||||
|
||||
this.materials.push( {
|
||||
name: '',
|
||||
smooth: this.smooth
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
return lastMultiMaterial;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Inherit previous objects material.
|
||||
// Spec tells us that a declared material must be set to all objects until a new material is declared.
|
||||
// If a usemtl declaration is encountered while this new object is being parsed, it will
|
||||
// overwrite the inherited material. Exception being that there was already face declarations
|
||||
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
|
||||
|
||||
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
|
||||
|
||||
var declared = previousMaterial.clone( 0 );
|
||||
declared.inherited = true;
|
||||
this.object.materials.push( declared );
|
||||
|
||||
}
|
||||
|
||||
this.objects.push( this.object );
|
||||
|
||||
},
|
||||
|
||||
finalize: function () {
|
||||
|
||||
if ( this.object && typeof this.object._finalize === 'function' ) {
|
||||
|
||||
this.object._finalize( true );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
parseVertexIndex: function ( value, len ) {
|
||||
|
||||
var index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
||||
|
||||
},
|
||||
|
||||
parseNormalIndex: function ( value, len ) {
|
||||
|
||||
var index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
||||
|
||||
},
|
||||
|
||||
parseUVIndex: function ( value, len ) {
|
||||
|
||||
var index = parseInt( value, 10 );
|
||||
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
|
||||
|
||||
},
|
||||
|
||||
addVertex: function ( a, b, c ) {
|
||||
|
||||
var src = this.vertices;
|
||||
var dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addVertexPoint: function ( a ) {
|
||||
|
||||
var src = this.vertices;
|
||||
var dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addVertexLine: function ( a ) {
|
||||
|
||||
var src = this.vertices;
|
||||
var dst = this.object.geometry.vertices;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addNormal: function ( a, b, c ) {
|
||||
|
||||
var src = this.normals;
|
||||
var dst = this.object.geometry.normals;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addColor: function ( a, b, c ) {
|
||||
|
||||
var src = this.colors;
|
||||
var dst = this.object.geometry.colors;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
||||
|
||||
},
|
||||
|
||||
addUV: function ( a, b, c ) {
|
||||
|
||||
var src = this.uvs;
|
||||
var dst = this.object.geometry.uvs;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
||||
dst.push( src[ b + 0 ], src[ b + 1 ] );
|
||||
dst.push( src[ c + 0 ], src[ c + 1 ] );
|
||||
|
||||
},
|
||||
|
||||
addUVLine: function ( a ) {
|
||||
|
||||
var src = this.uvs;
|
||||
var dst = this.object.geometry.uvs;
|
||||
|
||||
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
||||
|
||||
},
|
||||
|
||||
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
|
||||
|
||||
var vLen = this.vertices.length;
|
||||
|
||||
var ia = this.parseVertexIndex( a, vLen );
|
||||
var ib = this.parseVertexIndex( b, vLen );
|
||||
var ic = this.parseVertexIndex( c, vLen );
|
||||
|
||||
this.addVertex( ia, ib, ic );
|
||||
|
||||
if ( this.colors.length > 0 ) {
|
||||
|
||||
this.addColor( ia, ib, ic );
|
||||
|
||||
}
|
||||
|
||||
if ( ua !== undefined && ua !== '' ) {
|
||||
|
||||
var uvLen = this.uvs.length;
|
||||
ia = this.parseUVIndex( ua, uvLen );
|
||||
ib = this.parseUVIndex( ub, uvLen );
|
||||
ic = this.parseUVIndex( uc, uvLen );
|
||||
this.addUV( ia, ib, ic );
|
||||
|
||||
}
|
||||
|
||||
if ( na !== undefined && na !== '' ) {
|
||||
|
||||
// Normals are many times the same. If so, skip function call and parseInt.
|
||||
var nLen = this.normals.length;
|
||||
ia = this.parseNormalIndex( na, nLen );
|
||||
|
||||
ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
|
||||
ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
|
||||
|
||||
this.addNormal( ia, ib, ic );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
addPointGeometry: function ( vertices ) {
|
||||
|
||||
this.object.geometry.type = 'Points';
|
||||
|
||||
var vLen = this.vertices.length;
|
||||
|
||||
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
||||
|
||||
this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
addLineGeometry: function ( vertices, uvs ) {
|
||||
|
||||
this.object.geometry.type = 'Line';
|
||||
|
||||
var vLen = this.vertices.length;
|
||||
var uvLen = this.uvs.length;
|
||||
|
||||
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
||||
|
||||
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
|
||||
|
||||
}
|
||||
|
||||
for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
|
||||
|
||||
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
state.startObject( '', false );
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function OBJLoader( manager ) {
|
||||
|
||||
THREE.Loader.call( this, manager );
|
||||
|
||||
this.materials = null;
|
||||
|
||||
}
|
||||
|
||||
OBJLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
|
||||
|
||||
constructor: OBJLoader,
|
||||
|
||||
load: function ( url, onLoad, onProgress, onError ) {
|
||||
|
||||
var scope = this;
|
||||
|
||||
var loader = new THREE.FileLoader( scope.manager );
|
||||
loader.setPath( this.path );
|
||||
loader.load( url, function ( text ) {
|
||||
|
||||
onLoad( scope.parse( text ) );
|
||||
|
||||
}, onProgress, onError );
|
||||
|
||||
},
|
||||
|
||||
setMaterials: function ( materials ) {
|
||||
|
||||
this.materials = materials;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
parse: function ( text ) {
|
||||
|
||||
console.time( 'OBJLoader' );
|
||||
|
||||
var state = new ParserState();
|
||||
|
||||
if ( text.indexOf( '\r\n' ) !== - 1 ) {
|
||||
|
||||
// This is faster than String.split with regex that splits on both
|
||||
text = text.replace( /\r\n/g, '\n' );
|
||||
|
||||
}
|
||||
|
||||
if ( text.indexOf( '\\\n' ) !== - 1 ) {
|
||||
|
||||
// join lines separated by a line continuation character (\)
|
||||
text = text.replace( /\\\n/g, '' );
|
||||
|
||||
}
|
||||
|
||||
var lines = text.split( '\n' );
|
||||
var line = '', lineFirstChar = '';
|
||||
var lineLength = 0;
|
||||
var result = [];
|
||||
|
||||
// Faster to just trim left side of the line. Use if available.
|
||||
var trimLeft = ( typeof ''.trimLeft === 'function' );
|
||||
|
||||
for ( var i = 0, l = lines.length; i < l; i ++ ) {
|
||||
|
||||
line = lines[ i ];
|
||||
|
||||
line = trimLeft ? line.trimLeft() : line.trim();
|
||||
|
||||
lineLength = line.length;
|
||||
|
||||
if ( lineLength === 0 ) continue;
|
||||
|
||||
lineFirstChar = line.charAt( 0 );
|
||||
|
||||
// @todo invoke passed in handler if any
|
||||
if ( lineFirstChar === '#' ) continue;
|
||||
|
||||
if ( lineFirstChar === 'v' ) {
|
||||
|
||||
var data = line.split( /\s+/ );
|
||||
|
||||
switch ( data[ 0 ] ) {
|
||||
|
||||
case 'v':
|
||||
state.vertices.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] ),
|
||||
parseFloat( data[ 3 ] )
|
||||
);
|
||||
if ( data.length >= 7 ) {
|
||||
|
||||
state.colors.push(
|
||||
parseFloat( data[ 4 ] ),
|
||||
parseFloat( data[ 5 ] ),
|
||||
parseFloat( data[ 6 ] )
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
break;
|
||||
case 'vn':
|
||||
state.normals.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] ),
|
||||
parseFloat( data[ 3 ] )
|
||||
);
|
||||
break;
|
||||
case 'vt':
|
||||
state.uvs.push(
|
||||
parseFloat( data[ 1 ] ),
|
||||
parseFloat( data[ 2 ] )
|
||||
);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else if ( lineFirstChar === 'f' ) {
|
||||
|
||||
var lineData = line.substr( 1 ).trim();
|
||||
var vertexData = lineData.split( /\s+/ );
|
||||
var faceVertices = [];
|
||||
|
||||
// Parse the face vertex data into an easy to work with format
|
||||
|
||||
for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
|
||||
|
||||
var vertex = vertexData[ j ];
|
||||
|
||||
if ( vertex.length > 0 ) {
|
||||
|
||||
var vertexParts = vertex.split( '/' );
|
||||
faceVertices.push( vertexParts );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
|
||||
|
||||
var v1 = faceVertices[ 0 ];
|
||||
|
||||
for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
|
||||
|
||||
var v2 = faceVertices[ j ];
|
||||
var v3 = faceVertices[ j + 1 ];
|
||||
|
||||
state.addFace(
|
||||
v1[ 0 ], v2[ 0 ], v3[ 0 ],
|
||||
v1[ 1 ], v2[ 1 ], v3[ 1 ],
|
||||
v1[ 2 ], v2[ 2 ], v3[ 2 ]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
} else if ( lineFirstChar === 'l' ) {
|
||||
|
||||
var lineParts = line.substring( 1 ).trim().split( " " );
|
||||
var lineVertices = [], lineUVs = [];
|
||||
|
||||
if ( line.indexOf( "/" ) === - 1 ) {
|
||||
|
||||
lineVertices = lineParts;
|
||||
|
||||
} else {
|
||||
|
||||
for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
|
||||
|
||||
var parts = lineParts[ li ].split( "/" );
|
||||
|
||||
if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
|
||||
if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
state.addLineGeometry( lineVertices, lineUVs );
|
||||
|
||||
} else if ( lineFirstChar === 'p' ) {
|
||||
|
||||
var lineData = line.substr( 1 ).trim();
|
||||
var pointData = lineData.split( " " );
|
||||
|
||||
state.addPointGeometry( pointData );
|
||||
|
||||
} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
|
||||
|
||||
// o object_name
|
||||
// or
|
||||
// g group_name
|
||||
|
||||
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
||||
// var name = result[ 0 ].substr( 1 ).trim();
|
||||
var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
|
||||
|
||||
state.startObject( name );
|
||||
|
||||
} else if ( material_use_pattern.test( line ) ) {
|
||||
|
||||
// material
|
||||
|
||||
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
|
||||
|
||||
} else if ( material_library_pattern.test( line ) ) {
|
||||
|
||||
// mtl file
|
||||
|
||||
state.materialLibraries.push( line.substring( 7 ).trim() );
|
||||
|
||||
} else if ( map_use_pattern.test( line ) ) {
|
||||
|
||||
// the line is parsed but ignored since the loader assumes textures are defined MTL files
|
||||
// (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
|
||||
|
||||
console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
|
||||
|
||||
} else if ( lineFirstChar === 's' ) {
|
||||
|
||||
result = line.split( ' ' );
|
||||
|
||||
// smooth shading
|
||||
|
||||
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
|
||||
// but does not define a usemtl for each face set.
|
||||
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
|
||||
// This requires some care to not create extra material on each smooth value for "normal" obj files.
|
||||
// where explicit usemtl defines geometry groups.
|
||||
// Example asset: examples/models/obj/cerberus/Cerberus.obj
|
||||
|
||||
/*
|
||||
* http://paulbourke.net/dataformats/obj/
|
||||
* or
|
||||
* http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
|
||||
*
|
||||
* From chapter "Grouping" Syntax explanation "s group_number":
|
||||
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
|
||||
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
|
||||
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
|
||||
* than 0."
|
||||
*/
|
||||
if ( result.length > 1 ) {
|
||||
|
||||
var value = result[ 1 ].trim().toLowerCase();
|
||||
state.object.smooth = ( value !== '0' && value !== 'off' );
|
||||
|
||||
} else {
|
||||
|
||||
// ZBrush can produce "s" lines #11707
|
||||
state.object.smooth = true;
|
||||
|
||||
}
|
||||
var material = state.object.currentMaterial();
|
||||
if ( material ) material.smooth = state.object.smooth;
|
||||
|
||||
} else {
|
||||
|
||||
// Handle null terminated files without exception
|
||||
if ( line === '\0' ) continue;
|
||||
|
||||
throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.finalize();
|
||||
|
||||
var container = new THREE.Group();
|
||||
container.materialLibraries = [].concat( state.materialLibraries );
|
||||
|
||||
for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
|
||||
|
||||
var object = state.objects[ i ];
|
||||
var geometry = object.geometry;
|
||||
var materials = object.materials;
|
||||
var isLine = ( geometry.type === 'Line' );
|
||||
var isPoints = ( geometry.type === 'Points' );
|
||||
var hasVertexColors = false;
|
||||
|
||||
// Skip o/g line declarations that did not follow with any faces
|
||||
if ( geometry.vertices.length === 0 ) continue;
|
||||
|
||||
var buffergeometry = new THREE.BufferGeometry();
|
||||
|
||||
buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
|
||||
|
||||
if ( geometry.normals.length > 0 ) {
|
||||
|
||||
buffergeometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
|
||||
|
||||
} else {
|
||||
|
||||
buffergeometry.computeVertexNormals();
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.colors.length > 0 ) {
|
||||
|
||||
hasVertexColors = true;
|
||||
buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
|
||||
|
||||
}
|
||||
|
||||
if ( geometry.uvs.length > 0 ) {
|
||||
|
||||
buffergeometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
|
||||
|
||||
}
|
||||
|
||||
// Create materials
|
||||
|
||||
var createdMaterials = [];
|
||||
|
||||
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
||||
|
||||
var sourceMaterial = materials[ mi ];
|
||||
var material = undefined;
|
||||
|
||||
if ( this.materials !== null ) {
|
||||
|
||||
material = this.materials.create( sourceMaterial.name );
|
||||
|
||||
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
|
||||
if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
|
||||
|
||||
var materialLine = new THREE.LineBasicMaterial();
|
||||
THREE.Material.prototype.copy.call( materialLine, material );
|
||||
materialLine.color.copy( material.color );
|
||||
material = materialLine;
|
||||
|
||||
} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
|
||||
|
||||
var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
|
||||
THREE.Material.prototype.copy.call( materialPoints, material );
|
||||
materialPoints.color.copy( material.color );
|
||||
materialPoints.map = material.map;
|
||||
material = materialPoints;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( ! material ) {
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
material = new THREE.LineBasicMaterial();
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
|
||||
|
||||
} else {
|
||||
|
||||
material = new THREE.MeshPhongMaterial();
|
||||
|
||||
}
|
||||
|
||||
material.name = sourceMaterial.name;
|
||||
|
||||
}
|
||||
|
||||
material.flatShading = sourceMaterial.smooth ? false : true;
|
||||
material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
|
||||
|
||||
createdMaterials.push( material );
|
||||
|
||||
}
|
||||
|
||||
// Create mesh
|
||||
|
||||
var mesh;
|
||||
|
||||
if ( createdMaterials.length > 1 ) {
|
||||
|
||||
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
||||
|
||||
var sourceMaterial = materials[ mi ];
|
||||
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
|
||||
|
||||
}
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
mesh = new THREE.Points( buffergeometry, createdMaterials );
|
||||
|
||||
} else {
|
||||
|
||||
mesh = new THREE.Mesh( buffergeometry, createdMaterials );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( isLine ) {
|
||||
|
||||
mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
} else if ( isPoints ) {
|
||||
|
||||
mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
} else {
|
||||
|
||||
mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mesh.name = object.name;
|
||||
|
||||
container.add( mesh );
|
||||
|
||||
}
|
||||
|
||||
console.timeEnd( 'OBJLoader' );
|
||||
|
||||
return container;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return OBJLoader;
|
||||
|
||||
} )();
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
class Controls {
|
||||
constructor(object) {
|
||||
|
||||
// object is the object controlled by the controls, in our case, the camera.
|
||||
this.object = object;
|
||||
|
||||
// 3D coordinates where the camera is looking at
|
||||
this.target = new THREE.Vector3(0, 0, 0);
|
||||
|
||||
// Unit vectors of the local camera frame
|
||||
// forward is in the z-direction
|
||||
// left point towards the x-direction
|
||||
// (a vector towards y is not necessary)
|
||||
// in the direction of the angles
|
||||
this.forward = new THREE.Vector3(0,0,0);
|
||||
this.left = new THREE.Vector3(0,0,0);
|
||||
|
||||
// speed at which the camera will translate
|
||||
this.speed = 50;
|
||||
|
||||
// speed at which the camera will rotate
|
||||
this.sensitivity = 0.004;
|
||||
|
||||
// angles of the camera
|
||||
this.angles = {
|
||||
delta: 0,
|
||||
theta: 0,
|
||||
};
|
||||
|
||||
// the position of the camera is this.object.position
|
||||
|
||||
this.vectorsFromAngles();
|
||||
|
||||
// currently pressed keys
|
||||
this.keys = {
|
||||
up: false,
|
||||
down: false,
|
||||
left: false,
|
||||
right: false,
|
||||
};
|
||||
|
||||
// whether the mouse is being pressed or not
|
||||
this.mouseClicked = false;
|
||||
|
||||
// whether there is a transition running or not
|
||||
// if not, this.t is NaN
|
||||
// otherwise, this.t is in [0, 1]
|
||||
this.t = NaN;
|
||||
|
||||
// calls this.keyChange(true) when a key is pressed
|
||||
document.addEventListener('keydown', this.keyChange(true));
|
||||
|
||||
// calls this.keyChange(false) when a key is released
|
||||
document.addEventListener('keyup', this.keyChange(false));
|
||||
|
||||
// calls this.mouseDown(e) when a mouse button is pressed
|
||||
document.addEventListener('mousedown', (e) => this.mouseDown(e));
|
||||
|
||||
// sets this.mouseClicked to false when a mouse button is released
|
||||
document.addEventListener('mouseup', () => this.mouseClicked = false);
|
||||
|
||||
// calls this.mouseMove(e) when the mouse is moved
|
||||
document.addEventListener('mousemove', (e) => this.mouseMove(e));
|
||||
}
|
||||
|
||||
// rotates the camera to make it look to its target.
|
||||
look() {
|
||||
this.object.lookAt(this.target);
|
||||
}
|
||||
|
||||
// updates this.forward, this.left and this.target
|
||||
// from this.angles.delta and this.angles.theta
|
||||
|
||||
// this.forward is the vector moving direction
|
||||
// this.left is the vector moving sideways to the left
|
||||
// this.target is the point that the camera is looking
|
||||
vectorsFromAngles() {
|
||||
// TODO Part 1
|
||||
}
|
||||
|
||||
|
||||
// computes this.angles.delta and this.angles.theta from this.forward
|
||||
// (may be useless)
|
||||
anglesFromVectors() {
|
||||
// TODO Part 2
|
||||
}
|
||||
|
||||
// updates this.keys when a key is pressed or released
|
||||
keyChange(setting) {
|
||||
return (event) => {
|
||||
switch (event.keyCode) {
|
||||
case 37: case 81: this.keys.left = setting; break;
|
||||
case 38: case 90: this.keys.up = setting; break;
|
||||
case 39: case 68: this.keys.right = setting; break;
|
||||
case 40: case 83: this.keys.down = setting; break;
|
||||
case 13:
|
||||
console.log("Position:", this.object.position);
|
||||
console.log("Target:", this.target);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// sets mouseClicked to true, and searches for a bookmark being clicked
|
||||
mouseDown(event) {
|
||||
this.mouseClicked = true;
|
||||
|
||||
let mouse = {
|
||||
x: ( event.clientX / window.innerWidth ) * 2 - 1,
|
||||
y: - ( event.clientY / window.innerHeight ) * 2 + 1,
|
||||
};
|
||||
|
||||
// update the picking ray with the camera and mouse position
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
|
||||
// calculate objects intersecting the picking ray
|
||||
var intersects = raycaster.intersectObjects(scene.children, true);
|
||||
|
||||
if (this.testIntersection(intersects)) {
|
||||
this.bookmarkClicked(intersects[0].object.parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// tests that a bookmark is clicked or not
|
||||
//
|
||||
// this function filters out other objects of the scene.
|
||||
testIntersection(intersects) {
|
||||
if (intersects.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (intersects[0].object === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! (intersects[0].object.parent instanceof Bookmark)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.object.position.distanceTo(intersects[0].object.parent.position) < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bookmarkClicked(intersects[0].object.parent);
|
||||
}
|
||||
|
||||
// initializes the paramters for the transition to a bookmark.
|
||||
bookmarkClicked(bookmark) {
|
||||
// TODO Part 2
|
||||
}
|
||||
|
||||
// changes this.angles depending of event.movementX and event.movementY
|
||||
//
|
||||
// event.movementX indicates how many pixels the mouse has moved to the right
|
||||
// event.movementY indicates how many piels the mouse has moved to the bottom
|
||||
// both those values can be negative to indicate a motion in the opposite direction
|
||||
mouseMove(event) {
|
||||
// TODO Part 1
|
||||
}
|
||||
|
||||
// called at every frame
|
||||
update() {
|
||||
|
||||
// No transition : use keyboard and mouse to update the camera
|
||||
if (isNaN(this.t)) {
|
||||
|
||||
// TODO Part 1
|
||||
|
||||
if (this.keys.up) {
|
||||
// ...
|
||||
}
|
||||
|
||||
} else {
|
||||
// Transition to bookmark
|
||||
// TODO Part 2
|
||||
|
||||
}
|
||||
|
||||
// update the camera parameters
|
||||
this.look();
|
||||
}
|
||||
}
|
||||
|
||||
let container, controls;
|
||||
let camera, scene, renderer;
|
||||
let raycaster = new THREE.Raycaster();
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function init() {
|
||||
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 100, 50000);
|
||||
camera.position.y = 1000;
|
||||
camera.position.z = 1000;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
let ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
|
||||
scene.add(ambientLight);
|
||||
let pointLight = new THREE.PointLight(0xffffff, 0.8);
|
||||
camera.add(pointLight);
|
||||
scene.add(camera);
|
||||
|
||||
let geometry = new THREE.PlaneGeometry(20000, 20000);
|
||||
for (let index = 0; index < geometry.faceVertexUvs[0].length; index++) {
|
||||
geometry.faceVertexUvs[0][index][0].multiplyScalar(10);
|
||||
geometry.faceVertexUvs[0][index][1].multiplyScalar(10);
|
||||
geometry.faceVertexUvs[0][index][2].multiplyScalar(10);
|
||||
}
|
||||
let texture = new THREE.TextureLoader().load('assets/windfall/water.png');
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
let material = new THREE.MeshBasicMaterial({map: texture});
|
||||
let sea = new THREE.Mesh(geometry, material);
|
||||
sea.rotation.x = -Math.PI / 2;
|
||||
scene.add(sea);
|
||||
|
||||
// controls
|
||||
controls = new Controls(camera);
|
||||
|
||||
// model
|
||||
let directory = "assets/windfall/";
|
||||
let modelName = "Windfall";
|
||||
|
||||
let onProgress = function (xhr) {
|
||||
if (xhr.lengthComputable) {
|
||||
let percentComplete = xhr.loaded / xhr.total * 100;
|
||||
console.log(Math.round(percentComplete, 2) + '% downloaded');
|
||||
}
|
||||
};
|
||||
|
||||
let onError = function () { };
|
||||
let manager = new THREE.LoadingManager();
|
||||
|
||||
new THREE.MTLLoader(manager)
|
||||
.setPath(directory)
|
||||
.load(modelName + ".mtl", function (materials) {
|
||||
materials.preload();
|
||||
new THREE.OBJLoader(manager)
|
||||
.setMaterials(materials)
|
||||
.setPath(directory)
|
||||
.load(modelName + ".obj", function (object) {
|
||||
scene.add(object);
|
||||
}, onProgress, onError);
|
||||
});
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.setClearColor(new THREE.Color(0x87ceeb));
|
||||
container.appendChild(renderer.domElement);
|
||||
|
||||
window.addEventListener('resize', onWindowResize, false);
|
||||
|
||||
// Add a bookmark to the scene
|
||||
// let position = { x: -3089.6612461510463, y: 3944.8226721499614, z: -2409.0350261969947 };
|
||||
// let target = { x: -3088.665295409939, y: 3944.824672148628, z: -2409.124904566436 };
|
||||
// let bookmark = new Bookmark(position, target);
|
||||
// scene.add(bookmark);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
|
||||
for (let child of scene.children) {
|
||||
if (child instanceof Bookmark) {
|
||||
child.update(camera);
|
||||
}
|
||||
}
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
}
|
||||
|