Bagi yang baru pertama kali ingin menampilkan obyek molekul 3D dapat dicoba dengan memperlajari dan menggunakan kode di bawah ini. Boleh di muat di blog atau web pribadi atau disimpan sebagai file html tunggal untuk dibuka bahan belajar mandiri.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Judul halaman yang akan muncul di tab browser -->
<title>Model 3D SF6</title>
<style>
/* Reset margin body agar tidak ada jarak di tepi */
body { margin: 0; overflow: hidden; }
/* Container untuk kanvas 3D, mengisi seluruh viewport */
#container { width: 100%; height: 100vh; }
</style>
</head>
<body>
<!-- Div untuk menampung kanvas rendering Three.js -->
<div id="container"></div>
<!-- Memuat Three.js core library versi 0.132.2 -->
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<!-- Memuat OrbitControls untuk interaksi putar/zoom -->
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
<!-- Memuat PDBLoader untuk parse data molekul PDB -->
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/PDBLoader.js"></script>
<script>
// Periksa apakah THREE tersedia
if (typeof THREE === 'undefined') {
console.error('Three.js failed to load. Check CDN or network.');
alert('Error: Three.js not loaded. Please check your internet connection or try again later.');
throw new Error('Three.js not loaded');
}
// Membuat scene, tempat semua objek 3D berada
const scene = new THREE.Scene();
// Mengatur warna latar belakang scene menjadi putih
scene.background = new THREE.Color(0xffffff);
// Membuat kamera perspektif: FOV 30°, rasio aspek, near clip 0.1, far clip 1000
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
// Mengatur posisi kamera di sumbu Z untuk melihat molekul
camera.position.z = 10;
// Membuat renderer WebGL dengan anti-aliasing untuk tepian halus
const renderer = new THREE.WebGLRenderer({ antialias: true });
// Mengatur ukuran renderer sesuai ukuran window
renderer.setSize(window.innerWidth, window.innerHeight);
// Menambahkan elemen kanvas renderer ke container
document.getElementById('container').appendChild(renderer.domElement);
// Menambahkan OrbitControls untuk interaksi mouse (putar, zoom, pan)
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// Mengaktifkan damping untuk gerakan lebih halus
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Menambahkan ambient light untuk pencahayaan merata
const ambientLight = new THREE.AmbientLight(0x606060, 0.8); // Warna abu, intensitas 0.8
scene.add(ambientLight);
// Menambahkan directional light untuk efek bayangan
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6); // Warna putih, intensitas 0.6
directionalLight.position.set(1, 1, 1).normalize(); // Arah cahaya dari (1, 1, 1)
scene.add(directionalLight);
// Objek properti atom: warna dan radius untuk belerang (S) dan fluor (F)
const atomProperties = {
'S': { color: 0xffff00, radius: 1.04 }, // Kuning untuk sulfur
'F': { color: 0x00ff00, radius: 0.64 } // Hijau untuk fluor
};
// Fungsi untuk membuat label teks sebagai sprite
function createLabelSprite(element) {
// Membuat elemen canvas 2D untuk teks
const canvas = document.createElement('canvas');
canvas.width = 256; // Ukuran canvas 256x256 piksel
canvas.height = 256;
// Mendapatkan konteks 2D untuk menggambar
const context = canvas.getContext('2d');
// Mengatur font teks (bold, ukuran 48px, Arial)
context.font = 'bold 48px Arial';
// Mengatur warna teks hitam
context.fillStyle = 'black';
// Mengatur perataan teks ke tengah
context.textAlign = 'center';
context.textBaseline = 'middle';
// Menggambar teks di tengah canvas
context.fillText(element, 128, 128);
// Membuat tekstur dari canvas
const texture = new THREE.CanvasTexture(canvas);
texture.needsUpdate = true; // Memastikan tekstur diperbarui
// Membuat material sprite dengan tekstur transparan
const spriteMaterial = new THREE.SpriteMaterial({
map: texture,
transparent: true,
depthTest: false // Mencegah label tertutup objek lain
});
// Membuat sprite dari material
const sprite = new THREE.Sprite(spriteMaterial);
// Mengatur skala sprite untuk ukuran teks
sprite.scale.set(0.8, 0.8, 0.8);
// Mengatur urutan render untuk prioritas
sprite.renderOrder = 1;
return sprite;
}
// Fungsi untuk membuat atom sebagai bola
function createAtoms(geometry, json) {
const group = new THREE.Group(); // Grup untuk menampung semua atom
const positions = geometry.attributes.position.array; // Posisi atom dari geometri
for (let i = 0; i < json.atoms.length; i++) {
const element = json.atoms[i][4].trim(); // Nama elemen (S atau F)
const props = atomProperties[element]; // Ambil properti elemen
// Membuat geometri bola untuk atom
const sphereGeometry = new THREE.SphereGeometry(props.radius * 0.5, 16, 16);
// Membuat material dengan warna dan efek kilau
const material = new THREE.MeshPhongMaterial({
color: props.color,
shininess: 50,
specular: 0x111111
});
// Membuat mesh atom
const sphere = new THREE.Mesh(sphereGeometry, material);
// Mengatur posisi atom dari data PDB
sphere.position.set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
sphere.renderOrder = 0; // Atom dirender sebelum sprite
group.add(sphere);
// Membuat dan menambahkan label sprite
const label = createLabelSprite(element);
// Mengatur posisi label sama dengan atom, dengan offset kecil di Z
label.position.set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2] + 0.01);
group.add(label);
}
return group;
}
// Fungsi untuk membuat ikatan antar atom sebagai tabung
function createBonds(geometry) {
const group = new THREE.Group(); // Grup untuk menampung ikatan
const positions = geometry.attributes.position.array; // Posisi ikatan dari geometri
for (let i = 0; i < positions.length; i += 6) {
// Titik awal ikatan
const start = new THREE.Vector3(positions[i], positions[i + 1], positions[i + 2]);
// Titik akhir ikatan
const end = new THREE.Vector3(positions[i + 3], positions[i + 4], positions[i + 5]);
// Membuat kurva garis untuk ikatan
const path = new THREE.LineCurve3(start, end);
// Membuat geometri tabung untuk ikatan
const tubeGeometry = new THREE.TubeGeometry(path, 1, 0.08, 8, false);
// Membuat material untuk ikatan
const material = new THREE.MeshPhongMaterial({
color: 0xcccccc, // Warna abu-abu
shininess: 50,
specular: 0x111111
});
// Membuat mesh tabung
const tube = new THREE.Mesh(tubeGeometry, material);
group.add(tube);
}
return group;
}
// Data PDB untuk molekul SF6
const pdbData = `COMPND SF6
AUTHOR GENERATED BY THREE.JS
HETATM 1 S S X 1 0.000 0.000 0.000 1.00 0.00 S
HETATM 2 F F X 1 0.000 0.000 1.580 1.00 0.00 F
HETATM 3 F F X 1 0.000 0.000 -1.580 1.00 0.00 F
HETATM 4 F F X 1 0.000 1.580 0.000 1.00 0.00 F
HETATM 5 F F X 1 0.000 -1.580 0.000 1.00 0.00 F
HETATM 6 F F X 1 1.580 0.000 0.000 1.00 0.00 F
HETATM 7 F F X 1 -1.580 0.000 0.000 1.00 0.00 F
CONECT 1 2 3 4 5 6 7
CONECT 2 1
CONECT 3 1
CONECT 4 1
CONECT 5 1
CONECT 6 1
CONECT 7 1
END`;
// Mem-parse data PDB menggunakan PDBLoader
const loader = new THREE.PDBLoader();
const pdb = loader.parse(pdbData);
// Membuat atom dan ikatan dari data PDB
const atoms = createAtoms(pdb.geometryAtoms, pdb.json);
const bonds = createBonds(pdb.geometryBonds);
// Mengelompokkan atom dan ikatan ke dalam satu grup molekul
const molecule = new THREE.Group();
molecule.add(atoms, bonds);
// Menambahkan molekul ke scene
scene.add(molecule);
// Menyesuaikan posisi kamera berdasarkan ukuran molekul
const boundingBox = new THREE.Box3().setFromObject(molecule);
const size = boundingBox.getSize(new THREE.Vector3()).length();
camera.position.z = size * 2; // Jarak kamera 2x ukuran molekul
controls.target.set(0, 0, 0); // Fokus kontrol ke pusat molekul
controls.update();
// Fungsi untuk menangani perubahan ukuran window
function onWindowResize() {
// Memperbarui rasio aspek kamera
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// Memperbarui ukuran renderer
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Fungsi animasi untuk render berulang
function animate() {
requestAnimationFrame(animate); // Memanggil animate lagi
controls.update(); // Memperbarui kontrol interaksi
renderer.render(scene, camera); // Merender scene
}
// Menambahkan event listener untuk resize window
window.addEventListener('resize', onWindowResize);
// Memulai loop animasi
animate();
</script>
</body>
</html>
Selamat mencoba
Tidak ada komentar:
Posting Komentar