Как реализовать катание шарика по сфере в терминах матриц?

Цель

Необходимо создать две сферы, одну из которых можно катать по поверхности другой при помощи мышки и реализовать камеру, которую можно перемещать вокруг этих шаров при помощи клавиатуры.

Реализация

Я завёл матрицу, которая хранит текущее состояние поворота катающегося шара. Когда пользователь тянет мышью, я получаю череду событий перемещения мыши, и каждый раз при перемещении вычисляю, на сколько градусов вокруг текущих X и Y, как их видит пользователь, изменился поворот. Затем вычисляю матрицу, которая представляет эти два поворота и умножаю в обратном порядке изначальную матрицу поворота сферы на нее - обратный порядок нужен по той причине, что поворот происходит с точки зрения камеры, а не с точки зрения пространства модели.

Проблема

Но при такой реализации, вторая сфера не будет менять точку соприкосновения с первой сферой (будет как бы скользить по ней), как можно реализовать аналитически поворот точки соприкосновения шаров в терминах матриц?

Вот код, если кому интересно.


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Имея два соседних положения сферы можно найти плоскость в которой она катится. Тогда сфера вращается вокруг нормали к этой плоскости. Скорость вращения в два раза больше скорости движения точки касания сферы. Надеюсь вы поняли. Изменения ниже заставляют кота вращаться без проскальзывания:

$ git diff
diff --git a/script.js b/script.js
index 3de3f98..27b6515 100644
--- a/script.js
+++ b/script.js
@@ -207,8 +207,12 @@ let mouseDown = false;
 let lastMouseX = null;
 let lastMouseY = null;
 
+let lastT = undefined;
+
 let sphereRotationMatrix = mat4.create();
 mat4.identity(sphereRotationMatrix);
+let sphereOrientationMatrix = mat4.create();
+mat4.identity(sphereOrientationMatrix);
 
 
 function MouseDown(event) {
@@ -462,10 +466,31 @@ function drawScene(ambientR,ambientG,ambientB) {
     gl.drawElements(gl.TRIANGLES, indexData2.length, gl.UNSIGNED_SHORT, 0);
 
 
+    mat4.translate(mvMatrix,sphereRotationMatrix);
+
+    const t = vec3.create();
+    t[0] = mvMatrix[12];
+    t[1] = mvMatrix[13];
+    t[2] = mvMatrix[14];
+    vec3.add(t, [xPos, yPos, zPos]);
+    vec3.add(t, [0, 0, 6]);
+    if (lastT !== undefined) {
+        const axis = vec3.create();
+        vec3.cross(lastT, t, axis);
+        const angle = vec3.length(axis);
+        if (angle > 0) {
+            vec3.normalize(axis, axis);
+            const r = mat4.create();
+            mat4.identity(r);
+            mat4.rotate(r, 2 * angle, axis);
+            mat4.multiply(r, sphereOrientationMatrix, sphereOrientationMatrix);
+        }
+    }
+    lastT = t;
+    mat4.multiply(mvMatrix, sphereOrientationMatrix, mvMatrix);
 
-    mat4.translate(mvMatrix,sphereRotationMatrix);
-    mat4.multiply(mvMatrix, sphereRotationMatrix);
     gl.activeTexture(gl.TEXTURE0);
     gl.bindTexture(gl.TEXTURE_2D, sphereTexture);
     gl.uniform1i(shaderProgram.samplerUniform, 0);

P.S. WebGL для меня новая технология. В коде перемешаны движения сфер и их расположение в пространстве относительно камеры. Всё это делает решение хрупким. Считайте этот код прототипом или источником идей.

→ Ссылка