WebGL - Warna: Panduan Pemula untuk Menambahkan Kehidupan ke Grafik 3D Anda

Hai teman-teman, penggemar WebGL yang bersemangat! Saya sangat gembira untuk menjadi panduan Anda dalam perjalanan warna-warna ini melalui dunia WebGL. Sebagai orang yang telah mengajar grafik komputer selama lebih dari satu dekade, saya dapat mengatakan bahwa menambahkan warna ke scene 3D Anda adalah hal seperti memberikan kehidupan kepada sebuah foto hitam putih. Itu magis, dan hari ini, kita akan membuka keajaiban itu bersama!

WebGL - Colors

Mengerti Warna di WebGL

Sebelum kita membanjiri detail tentang aplikasi warna, mari kitaambil sedikit waktu untuk memahami apa arti warna dalam konteks WebGL. Dalam realm digital ini, warna direpresentasikan menggunakan model warna RGB (Merah, Hijau, Biru). Setiap warna adalah kombinasi dari tiga warna primer ini, dengan nilai berada dalam rentang 0.0 hingga 1.0.

Misalnya:

  • Merah: (1.0, 0.0, 0.0)
  • Hijau: (0.0, 1.0, 0.0)
  • Biru: (0.0, 0.0, 1.0)
  • Putih: (1.0, 1.0, 1.0)
  • Hitam: (0.0, 0.0, 0.0)

Pertimbangkan hal ini seperti mencampur cat, tapi dengan cahaya bukannya pigmen. Itu seperti menjadi seorang seniman digital dengan palet tak terbatas di ujung jari Anda!

Mengaplikasikan Warna di WebGL

Sekarang kita telah memahami dasarnya, mari kita kerjakan tangan (atau seharusnya, warna-warna?) untuk mengaplikasikan warna di WebGL.

Langkah untuk Mengaplikasikan Warna

  1. Definisikan atribut warna dalam shader vertex Anda
  2. Kirim data warna dari kode JavaScript Anda
  3. Gunakan warna dalam shader fragment Anda

mari kita rincikan langkah ini dengan beberapa contoh kode.

Langkah 1: Definisikan Atribut Warna di Shader Vertex

Pertama, kita perlu memberitahu shader vertex kita bahwa kita akan bekerja dengan warna. Berikut adalah caranya:

attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
v_Color = a_Color;
}

Dalam kode ini, kita mendefinisikan atribut a_Color untuk menerima data warna, dan variabel v_Color untuk mengirim warna ke shader fragment. Itu seperti menyiapkan saluran warna dari kode JavaScript kita hingga piksel kita!

Langkah 2: Kirim Data Warna dari JavaScript

Sekarang, kita perlu mengirim data warna dari kode JavaScript kita ke shader. Berikut adalah contoh bagaimana kita bisa melakukan itu:

// Definisikan vertices dan warna
var vertices = new Float32Array([
0.0, 0.5, 1.0, 0.0, 0.0,  // Vertex 1: x, y, r, g, b
-0.5, -0.5, 0.0, 1.0, 0.0,  // Vertex 2: x, y, r, g, b
0.5, -0.5, 0.0, 0.0, 1.0   // Vertex 3: x, y, r, g, b
]);

// Buat buffer dan kirim data kepadanya
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// Beritahu WebGL bagaimana membaca buffer
var FSIZE = vertices.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0);
gl.enableVertexAttribArray(a_Position);

var a_Color = gl.getAttribLocation(program, 'a_Color');
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
gl.enableVertexAttribArray(a_Color);

Kode ini mungkin terlihat menakutkan pertama kalinya, tapi mari kita pecahnya:

  1. Kita mendefinisikan vertices dan warna dalam sebuah array tunggal. Setiap vertex memiliki 5 nilai: x, y, r, g, b.
  2. Kita membuat buffer dan mengirim data kita kepadanya.
  3. Kita memberitahu WebGL bagaimana membaca buffer, baik untuk posisi (2 nilai pertama) maupun warna (3 nilai terakhir).

Itu seperti mempack suitcase dengan pakaian dan peralatan, dan kemudian memberitahu teman Anda bagaimana mempergiatnya!

Langkah 3: Gunakan Warna di Shader Fragment

Akhirnya, kita gunakan warna di shader fragment:

precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}

Shader ini mengambil warna yang kita kirim dari shader vertex dan mengaplikasikannya ke fragmen (pixel). Itu langkah terakhir dalam perjalanan warna kita, tempat warna akhirnya bersinar di layar!

Contoh – Mengaplikasikan Warna

Mari kita gabungkan semua itu dalam contoh lengkap. Kita akan membuat triangle berwarna cantik menggunakan kode yang kita diskusikan.

<!DOCTYPE html>
<html>
<head>
<title>Triangle Berwarna WebGL</title>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script>
// Shader program vertex
const vsSource = `
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
v_Color = a_Color;
}
`;

// Shader program fragment
const fsSource = `
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`;

function main() {
const canvas = document.querySelector("#glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("Tidak dapat menginisialisasi WebGL. Browser atau mesin Anda mungkin tidak mendukungnya.");
return;
}

// Inisialisasi program shader
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);

// Dapatkan lokasi atribut
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'a_Position'),
vertexColor: gl.getAttribLocation(shaderProgram, 'a_Color'),
},
};

// Buat buffer
const buffers = initBuffers(gl);

// Gambar scene
drawScene(gl, programInfo, buffers);
}

function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
0.0,  0.5,  1.0, 0.0, 0.0,
-0.5, -0.5,  0.0, 1.0, 0.0,
0.5, -0.5,  0.0, 0.0, 1.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

return {
position: positionBuffer,
};
}

function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(programInfo.program);

{
const numComponents = 2;  // ambil 2 nilai per iterasi
const type = gl.FLOAT;    // data di buffer adalah float 32bit
const normalize = false;  // jangan normalisasi
const stride = 20;        // berapa banyak byte untuk mendapatkan dari satu set nilai ke nilai berikutnya
const offset = 0;         // berapa banyak byte di dalam buffer untuk memulai dari
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(
programInfo.attribLocations.vertexPosition);
}

{
const numComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 20;
const offset = 8;
gl.vertexAttribPointer(
programInfo.attribLocations.vertexColor,
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(
programInfo.attribLocations.vertexColor);
}

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Tidak dapat menginisialisasi program shader: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}

return shaderProgram;
}

function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('Terjadi kesalahan kompilasi shader: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}

return shader;
}

window.onload = main;
</script>
</body>
</html>

Ketika Anda menjalankan kode ini, Anda akan melihat triangle yang indah dengan vertices merah, hijau, dan biru. Itu seperti menyaksikan彩虹 hidup di layar Anda!

Kesimpulan

Dan begitulah, teman-teman! Kita telah menjelajahi dunia warna-warna WebGL, dari memahami bagaimana warna direpresentasikan hingga mengaplikasikannya ke grafik 3D kita. Ingat, ini hanya awal. Dengan dasar-dasar ini di bawah pinggang Anda, Anda sudah dalam jalur untuk menciptakan grafik 3D yang menakjubkan dan berwarna.

Saat kita berakhir, saya teringat kata seorang murid yang pernah katakan kepada saya bahwa belajar warna di WebGL adalah seperti belajar menggambar dengan cahaya. Dan Anda tahu apa? Dia sungguh benar. Jadi, pergilah, teman-teman saya, dan lukislahkan kanvas digital Anda dengan semua warna angin (ya, itu referensi Disney, dan tidak, saya tidak merasa malu tentangnya).

Selamat coding, dan mayat WebGL Anda selalu berwarna-warni!

Metode Deskripsi
gl.clearColor(r, g, b, a) Mengatur warna untuk menghapus buffer warna
gl.clear(gl.COLOR_BUFFER_BIT) Menghapus buffer warna
gl.createBuffer() Membuat buffer baru
gl.bindBuffer(gl.ARRAY_BUFFER, buffer) Mengikat buffer objek ke target
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW) Membuat dan menginisialisasi toko data buffer
gl.getAttribLocation(program, name) Mengembalikan lokasi variabel atribut
gl.vertexAttribPointer(index, size, type, normalized, stride, offset) Menentukan tata letak data atribut vertex
gl.enableVertexAttribArray(index) Mengaktifkan array atribut vertex
gl.useProgram(program) Mengatur program tertentu menjadi bagian dari keadaan rendering saat ini
gl.drawArrays(gl.TRIANGLES, 0, 3) Menggambar primitif dari data array

Credits: Image by storyset