Ada 5 tipe kamera di dalam ThreeJS:
- Array Camera, adalah kamera yang bisa menampilkan beberapa kamera sekaligus di dalam satu canvas. Seperti game multiplayer jaman dulu yang ada split-screen-nya.
- Stereo Camera, adalah kamera yang meniru bagaimana mata kita menangkap gambar, biasanya di pakai untuk VR atau efek Parallax.
- Cube Camera, adalah kamera yang digunakkan untuk me-render lingkungan, jadi perlu ada arahnya (depan, belakang, kiri, kanan, atas, dan bawah). Biasanya di pakai untuk buat map atau shadow map.
- Orthographic Camera, adalah camera yang hasil tangkapannya tidak punya perspektif sendiri, tidak peduli kameranya jauh atau dekat, ukuran objeknya di layar pasti akan tetap terlihat. Biasanya di pakai di game-game RTS kaya Age of Empire.
- Perspective Camera, ini seperti camera-camera biasanya, punya perspective sendiri sebagaimana kalau kita pakai camera, objek juga bisa hilang jika terlalu jauh atau terlalu dekat.
Perspective Camera
Parameter yang dibutuhkan perspective camera adalah:
- fov (field of view),
- aspect ratio,
- jarak terdekat, dan
- jarak terjauh.
const camera = new THREE.PerspectiveCamera(fov, aspect_ratio, near, far)
const camera = new THREE.PerspectiveCamera(75, sizes.width / size.height, 1, 100)1. fov (field of view)
Field of view atau sudut pandang mengatur seberapa besar sudut bukaan vertikal kamera dalam ukuran derajat. Di kode atas di tulis 75 artinya 75 Derajat.
Kalau nilai derajat terlalu kecil, maka tampilannya seperti zoom jarak jauh dari teleskop, sedangkan jika nilai derajat terlalu besar, maka tampilannya seperti efek mata ikan/fish-eye.
2. Aspect Ratio
Parameter ini menentukan proporsi bentuk gambar yang nilainya didapatkan dari hasil pembagian lebar (width) dibagi dengan tinggi (height).
3. Jarak Terdekat dan Terjauh
Nilai terdekat dan terjauh adalah seberapa dekat atau jauh camera bisa di zoom-in atau zoom-out sampai objek itu hilang atau tidak terlihat lagi. Kalau sudah sampai nilai terdekat masih di zoom-in nanti objeknya hilang ga kelihatan begitu juga dengan zoom-out sampai nilai terjauh.
Logikanya sama kaya z-index kalau pernah jadi front-end developer, jadi jangan sampai kasih nilai terlalu kecil dan terlalu besar seperti 0.0001 dan 99999999 nanti GPU bakal bingung kalau ada objek yang saling berdekatan atau berjauhan banget sehingga terjadi yang namanya z-fighting.
Ortographic Camera
Ortographic Camera tidak punya konsep jarak atau perspective, sehingga di dalam syntax-nya tidak ada field of view, sebagai gantinya kita yang nentuin batas kiri, batas kanan, batas atas, dan batas bawah-nya.
const camera = new THREE.OrtographicCamera(kiri, kanan, atas, bawah, near, far)
const camera = new THREE.OrtographicCamera(-1, 1, 1, -1, 0.1, 100)Custom Control
Kalau selama ini kita lihat statis set posisi kamera, sekarang kita atur posisi kamera dengan mouse.
Pertama-tama, karena mau mouse kita yang kontrol posisi kamera, matiin dulu atau komen dulu posisi-posisi kamera yang barusan sudah kita set di ortographic dan perspective camera.
// Camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 1, 1000)
// const aspectRatio = sizes.width / sizes.height
// const camera = new THREE.OrthographicCamera(- 1 * aspectRatio, 1 * aspectRatio, 1, - 1, 0.1, 100)
// camera.position.x = 2
// camera.position.y = 2
camera.position.z = 3
camera.lookAt(mesh.position)
scene.add(camera)Karena yang menggerakkan kamera sekarang adalah mouse artinya kita harus tau dulu posisi kursor mouse, kita pakai JavaScript biasa di sini, gak perlu ThreeJS:
window.addEventListener('mousemove', event => {
console.log(event.clientX, event.clientY)
})dari sini sebenarnya udah bisa di pakai karena udah dapat posisi kursor-nya, tapi kalau di cek lagi nilai yang di hasilkan selalu positif, sedangkan namanya 3D pasti ada nilai negatif-nya di koordinat x, y, dan z.
Dari nilai code tersebut di atas kita akalin aja, lagipula ngoding itu segalanya tentang ngakalin. Kita buat nilai tengah-nya 0, kalau negatif kita kasih aja -0.5 dan positifnya 0.5:
// Cursor
const cursor = {
x: 0,
y: 0
}
window.addEventListener('mousemove', (event) =>
{
cursor.x = event.clientX / sizes.width - 0.5
cursor.y = event.clientY / sizes.height - 0.5
console.log(cursor.x, cursor.y)
})sekarang, objek kita udah bisa bergerak sesuai gerakan mouse kita, tapi ini masih gerak di koordinat x dan y saja ya. Kalau masih di kasih mode invert di salah satu koordinat kita bisa tinggal kasih nilai minus saja. Sebagai contoh, saya kalau main game lebih suka kamera koordinat y itu invert biar kerasa lebih natural, jadi tinggal seperti ini:
window.addEventListener('mousemove', (event) =>
{
cursor.x = event.clientX / sizes.width - 0.5
cursor.y = - (event.clientY / sizes.height - 0.5)
})Selanjutnya, kita kunci posisi kamera di bagian objeknya, biar kamera ini ga jalan-jalan, kalau kita gerakin mouse, posisi kamera tetap di objeknya jadinya camera akan gerak mengelilingi objeknya bukan lingkungannya. Masih ingat caranya di bagian 03 Transform Object > Look at this!? Betul! Kita pakai method lookAt.
const tick = () =>
{
// ...
// Update camera
camera.position.x = cursor.x * 5
camera.position.y = cursor.y * 5
camera.lookAt(mesh.position)
// ...
}Built-in Controls
Sebelumnya kita udah buat kontrol kamera kita sendiri, seperti halnya Clock di bagian Animasi, ThreeJS juga punya kontrol kamera bawaan.
1. Fly Controls
Fly Controls, bentuk kontrol kamera seperti kita sedang terbang di dalam pesawat sebagai pilot, Kamera bisa di putar di ketiga axes (x, y, dan z) dan bisa maju dan mundur.
2. First Person Controls
First Person Controls, sama seperti 1. Fly Controls, tapi axis-nya tetap jadi tidak bisa di putar, perlu di catat ini tidak sama seperti kamera di game game FPS.
3. Pointer Lock Controls
Nah, ini baru seperti kamera di game FPS, Pointer Lock Controls akan mengunci kamera di tengah-tengah, nyembunyiin kursor, dan bergerak mengikuti gerakan mouse. Semua ini menggunakan JavaScript biasa di dalam Pointer Lock Controls, yaitu pointer lock JavaScript API.
4. Orbit Controls
Orbit Controls, adalah yang paling mirip dengan yang kita buat manual barusan di bagian Built-in Controls.
5. TrackBall Controls
TrackBall Controls, mirip seperti 4. Orbit Controls, bedanya di sudut vertikal dia tidak memiliki batasan, kamu bisa terus melakukan putaran walaupun kameranya di bolak-balik.
6. Transform Controls
Transform Controls sebenarnya tidak ada hubungannya dengan kontrol kamera tapi kita bisa menambahkan ikon kecil di tengah objek tersebut untuk lihat mana koordinat x, y, dan z.
7. Drag Controls
Drag Controls juga sama, ga ada hubungannya sama kontrol kamera, tapi kita bisa drag and drop object.
Sekarang kita ubah yang kita buat sebelumnya secara manual pakai 4. Orbit Controls.
Orbit Controls
Memanggil fungsi OrbitControls
Di atas import fungsi / method OrbitControls
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'biar bisa di pakai Orbit Control-nya untuk mengontrol kamera berarti kita harus panggil camera sama canvas ke dalam parameter OrbitControls.
const controls = new OrbitControls(camera, canvas)Dengan gini aja udah bisa jalan Orbit Control-nya sama seperti yang sebelumnya kita buat secara manual di Custom Control. Tapi ayo kita tambahin lagi biar tau apa saja yang bisa dilakukan oleh Orbit Control.
Target
Kamera itu akan selalu berlokasi di tengah-tengah canvas bawaannya, tapi kita bisa ubah lokasi kameranya, kita tinggal atur saja koordinat x, y, dan z-nya. Misalkan, kita mau kameranya melihat ke bagian atas objek, tinggal atur saja nilai y-nya controls.target.y = 2, tapi masih kurang, kalau sudah ditentukan lokasi barunya, kita update lokasi baru kameranya, jadi kode lengkapnya seperti ini:
const controls = new OrbitControls(camera, canvas)
controls.target.y = 2
controls.update()Damping
Damping memberikan efek animasi yang lebih smooth ke gerakan kamera, jadi seperti ada efek melambat di akhir. Kita tinggal kasih enableDampling = true, kalau mau pakai efek ini.
const controls = new OrbitControls(camera, canvas)
controls.enableDampling = trueCode Lengkap
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
/**
* Base
*/
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Sizes
const sizes = {
width: 800,
height: 600
}
// Cursor
const cursor = {
x: 0,
y: 0
}
window.addEventListener('mousemove', (event) =>
{
cursor.x = event.clientX / sizes.width - 0.5
cursor.y = - (event.clientY / sizes.height - 0.5)
})
// Scene
const scene = new THREE.Scene()
// Object
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1, 5, 5, 5),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
scene.add(mesh)
// Camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
// const aspectRatio = sizes.width / sizes.height
// const camera = new THREE.OrthographicCamera(- 1 * aspectRatio, 1 * aspectRatio, 1, - 1, 0.1, 100)
camera.position.z = 3
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
// Animate
const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()Bab selanjutnya kita akan buat animasi 3D kita full-screen dan responsif.