WebGL - Rotation: Bringing Your Graphics to Life

Привет,野心勃勃的WebGL开发者们!今天,我们将深入计算机图形学最激动人心的方面之一:旋转。作为您友好邻邦的计算机科学老师,我将引导您进入旋转三角形和旋转形状的神奇世界。所以,戴上你想象的3D眼镜,让我们开始吧!

WebGL - Rotation

Understanding Rotation in WebGL

Before we jump into code, let's take a moment to understand what rotation means in the context of WebGL. Imagine you're holding a paper airplane. When you rotate it, you're changing its orientation in space. In WebGL, we do the same thing, but with mathematical precision!

Rotation in WebGL involves changing the position of vertices (the points that make up our shapes) around a central axis. This can be the X, Y, or Z axis, or even a combination of them.

The Magic of Matrices

Now, I know what you're thinking: "Matrices? Isn't that something from 'The Matrix' movies?" Well, not quite, but they're just as cool! In WebGL, we use matrices to perform rotations efficiently. Don't worry if this sounds complicated – we'll break it down step by step.

Example – Rotate a Triangle

Let's start with a simple example: rotating a triangle. We'll begin with a basic triangle and then make it spin like a geometric ballerina!

Step 1: Setting Up Our WebGL Environment

First, we need to set up our WebGL context. Here's a basic HTML structure:

<canvas id="glCanvas" width="640" height="480"></canvas>
<script>
// Our WebGL code will go here
</script>

Step 2: Initializing WebGL

Now, let's initialize WebGL:

const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');

if (!gl) {
console.error('WebGL not supported');
return;
}

This code gets our canvas element and tries to obtain a WebGL context. If WebGL isn't supported, we'll see an error message.

Step 3: Creating Our Shaders

Shaders are special programs that run on the GPU. We need two types: vertex shaders and fragment shaders. Here's a simple set:

const vertexShaderSource = `
attribute vec2 a_position;
uniform mat3 u_matrix;
void main() {
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
`;

const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`;

The vertex shader applies our rotation matrix, while the fragment shader simply colors our triangle red.

Step 4: Compiling and Linking Shaders

Next, we need to compile and link our shaders:

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

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

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

This code creates our shader program, which we'll use to render our rotating triangle.

Step 5: Creating Our Triangle

Now, let's define our triangle:

const positions = [
0, 0.5,
-0.5, -0.5,
0.5, -0.5
];

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

This creates a simple triangle centered at the origin.

Step 6: The Rotation Magic

Here's where the real magic happens. We'll create a function to generate our rotation matrix:

function createRotationMatrix(angleInRadians) {
const c = Math.cos(angleInRadians);
const s = Math.sin(angleInRadians);
return [
c, -s, 0,
s, c, 0,
0, 0, 1
];
}

This function takes an angle in radians and returns a 3x3 rotation matrix.

Step 7: Rendering Our Rotating Triangle

Finally, let's put it all together and make our triangle spin:

let angleInRadians = 0;

function render() {
angleInRadians += 0.01;

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(program);

const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

const matrixLocation = gl.getUniformLocation(program, "u_matrix");
const matrix = createRotationMatrix(angleInRadians);
gl.uniformMatrix3fv(matrixLocation, false, matrix);

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

requestAnimationFrame(render);
}

render();

This function does several things:

  1. Increases our rotation angle
  2. Clears the canvas
  3. Sets up our shader program and attributes
  4. Creates and applies our rotation matrix
  5. Draws the triangle
  6. Requests the next animation frame

And voila! We have a spinning triangle!

Conclusion

Congratulations! You've just created your first rotating shape in WebGL. Remember, this is just the beginning. With these basic principles, you can create complex 3D scenes with multiple rotating objects.

As we wrap up, I'm reminded of a student who once said, "I thought computer graphics was all about fancy software, but now I see it's more like being a digital puppeteer!" And she was right – with WebGL, you're pulling the strings of your very own digital puppet show.

Keep practicing, keep experimenting, and most importantly, keep having fun with WebGL. Before you know it, you'll be creating stunning 3D visualizations that will make even the most seasoned developers say "Wow!"

Method Description
createShader(gl, type, source) Создает и компилирует шейдер
createRotationMatrix(angleInRadians) Генерирует 2D旋转矩阵
render() Рендерит вращающийся треугольник
gl.clearColor(r, g, b, a) Устанавливает цвет для清除 канвы
gl.clear(gl.COLOR_BUFFER_BIT) Очищает канву
gl.useProgram(program) Устанавливает текущий шейдерный program
gl.getAttribLocation(program, name) Получает местоположение атрибута
gl.enableVertexAttribArray(location) Включает массив атрибутов
gl.bindBuffer(gl.ARRAY_BUFFER, buffer) Привязывает буфер
gl.vertexAttribPointer(location, size, type, normalized, stride, offset) Определяет раскладку вершинных данных
gl.getUniformLocation(program, name) Получает местоположение переменной униформа
gl.uniformMatrix3fv(location, transpose, value) Устанавливает значение матрицы униформа
gl.drawArrays(mode, first, count) Рендерит примитивы из массива данных
requestAnimationFrame(callback) Запрашивает следующий кадр анимации

Счастливого кодирования, и пусть ваши треугольники всегда вращаются в правильном направлении!

Credits: Image by storyset