Как реализовать катание шарика по сфере в терминах матриц?
Цель
Необходимо создать две сферы, одну из которых можно катать по поверхности другой при помощи мышки и реализовать камеру, которую можно перемещать вокруг этих шаров при помощи клавиатуры.
Реализация
Я завёл матрицу, которая хранит текущее состояние поворота катающегося шара. Когда пользователь тянет мышью, я получаю череду событий перемещения мыши, и каждый раз при перемещении вычисляю, на сколько градусов вокруг текущих X и Y, как их видит пользователь, изменился поворот. Затем вычисляю матрицу, которая представляет эти два поворота и умножаю в обратном порядке изначальную матрицу поворота сферы на нее - обратный порядок нужен по той причине, что поворот происходит с точки зрения камеры, а не с точки зрения пространства модели.
Проблема
Но при такой реализации, вторая сфера не будет менять точку соприкосновения с первой сферой (будет как бы скользить по ней), как можно реализовать аналитически поворот точки соприкосновения шаров в терминах матриц?
Вот код, если кому интересно.
Ответы (1 шт):
Имея два соседних положения сферы можно найти плоскость в которой она катится. Тогда сфера вращается вокруг нормали к этой плоскости. Скорость вращения в два раза больше скорости движения точки касания сферы. Надеюсь вы поняли. Изменения ниже заставляют кота вращаться без проскальзывания:
$ 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 для меня новая технология. В коде перемешаны движения сфер и их расположение в пространстве относительно камеры. Всё это делает решение хрупким. Считайте этот код прототипом или источником идей.