/// <summary> /// Возвращает истину при пересечении плоскости и линии /// </summary> /// <param name="vPolygon">Треугольник (плоскость)</param> /// <param name="vLine">Линия</param> /// <returns>Истина при пересечении, иначе - ложь</returns> public static bool intersectedPlane(Vector3[] vPolygon, Vector3[] vLine, Vector3 vNormal, ref float originDistance) { bool intersection = false; float distance1 = 0, distance2 = 0; // Дистанция 2х точек линии vNormal = VectorMathOperations.GetNormalToPlane(vPolygon); // Рассчитываем нормаль плоскости // Найдем дистанцию плоскости от начала координат: originDistance = planeDistance(vNormal, vPolygon[0]); // Получим дистанции от первой и второй точек: distance1 = ((vNormal.X * vLine[0].X) + // Ax + (vNormal.Y * vLine[0].Y) + // Bx + (vNormal.Z * vLine[0].Z)) + originDistance; // Cz + D distance2 = ((vNormal.X * vLine[1].X) + // Ax + (vNormal.Y * vLine[1].Y) + // Bx + (vNormal.Z * vLine[1].Z)) + originDistance; // Cz + D // Проверим на пересечение if (distance1 * distance2 >= 0) { intersection = false; } else { intersection = true; } return(intersection); }
public static BoneTransform SLerp(BoneTransform lhv, BoneTransform rhv, float blend) { Vector3 lerpPosition = VectorMathOperations.LerpVector(blend, 0, 1, lhv.m_toBoneTranslation, rhv.m_toBoneTranslation); Vector3 lerpScale = VectorMathOperations.LerpVector(blend, 0, 1, lhv.m_toBoneScale, rhv.m_toBoneScale); Quaternion lerpRotation = Quaternion.Slerp(lhv.m_toBoneRotation, rhv.m_toBoneRotation, blend); return(new BoneTransform(lerpRotation, lerpPosition, lerpScale)); }
public void MultMatrix(ref Matrix4 modelMatrix) { for (Int32 i = 0; i < Vertices.Length / 3; i++) { Vector4 vertex = new Vector4(Vertices[i, 0], Vertices[i, 1], Vertices[i, 2], 1.0f); vertex = VectorMathOperations.multMatrix(modelMatrix, vertex); this.Vertices[i, 0] = vertex.X; this.Vertices[i, 1] = vertex.Y; this.Vertices[i, 2] = vertex.Z; if (_normals != null) { Vector4 normal = new Vector4(Normals[i, 0], Normals[i, 1], Normals[i, 2], 0.0f); normal = VectorMathOperations.multMatrix(modelMatrix, normal); this.Normals[i, 0] = normal.X; this.Normals[i, 1] = normal.Y; this.Normals[i, 2] = normal.Z; } } }
private void UpdateRotationMatrix(Int32 deltaX, Int32 deltaY) { m_eyeSpaceForwardVector = VectorMathOperations.multMatrix(m_rotationMatrix, m_localSpaceForwardVector).Normalized(); m_eyeSpaceRightVector = Vector3.Cross(m_eyeSpaceForwardVector, m_localSpaceUpVector).Normalized(); float anglePitch = deltaY * rotateSensetivity; float angleYaw = deltaX * rotateSensetivity; Matrix3 rotatePitch = Matrix3.CreateFromAxisAngle(m_eyeSpaceRightVector, MathHelper.DegreesToRadians(anglePitch)); Matrix3 rotateYaw = Matrix3.CreateRotationY(MathHelper.DegreesToRadians(angleYaw)); Matrix3 tempRotationMatrix = Matrix3.Identity; tempRotationMatrix *= rotateYaw; tempRotationMatrix *= rotatePitch; m_rotationMatrix = tempRotationMatrix * m_rotationMatrix; bTransformationDirty = true; //Console.Clear(); //pitch = (float)Math.Atan2(-rotationMatrix[2, 0], Math.Sqrt(rotationMatrix[2, 1] * rotationMatrix[2, 1] + rotationMatrix[2, 2] * rotationMatrix[2, 2])); //Console.WriteLine(pitch); }
static public VertexArrayObject getTerrainAttributes(TableGrid LandscapeMap, Int32 normalSmoothLvl) { Int32 VERTEX_COUNT = LandscapeMap.TableSize - 1; float x, z; float[,] vertices = new float[(VERTEX_COUNT * VERTEX_COUNT) * 6, 3]; float[,] texCoords = new float[(VERTEX_COUNT * VERTEX_COUNT) * 6, 2]; float[,] normals = new float[(VERTEX_COUNT * VERTEX_COUNT) * 6, 3]; Int32 vertexPointer = 0; Vector3 tempNormal; Vector3[,] normalMatrix = new Vector3[LandscapeMap.TableSize, LandscapeMap.TableSize]; for (Int32 i = 0; i < LandscapeMap.TableSize - 1; i++) { for (Int32 j = 0; j < LandscapeMap.TableSize - 1; j++) { x = i * (float)LandscapeMap.GridStep; z = j * (float)LandscapeMap.GridStep; vertices[vertexPointer, 0] = x; vertices[vertexPointer, 1] = LandscapeMap.Table[i, j]; vertices[vertexPointer, 2] = z; tempNormal = VectorMathOperations.GetNormalToPlane(new Vector3[3] { new Vector3(x, LandscapeMap.Table[i, j], z), new Vector3(x, LandscapeMap.Table[i, j + 1], z + (float)LandscapeMap.GridStep), new Vector3(x + (float)LandscapeMap.GridStep, LandscapeMap.Table[i + 1, j], z) }); normalMatrix[i, j] = tempNormal; //tempNormal = getLandscapeNormal(i, j); normals[vertexPointer, 0] = tempNormal.X; normals[vertexPointer, 1] = tempNormal.Y; normals[vertexPointer, 2] = tempNormal.Z; texCoords[vertexPointer, 0] = vertices[vertexPointer, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer, 1] = vertices[vertexPointer, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertices[vertexPointer + 1, 0] = x; vertices[vertexPointer + 1, 1] = LandscapeMap.Table[i, j + 1]; vertices[vertexPointer + 1, 2] = z + (float)LandscapeMap.GridStep; tempNormal = VectorMathOperations.GetNormalToPlane(new Vector3[3] { new Vector3(x, LandscapeMap.Table[i, j + 1], z + (float)LandscapeMap.GridStep), new Vector3(x + (float)LandscapeMap.GridStep, LandscapeMap.Table[i + 1, j], z), new Vector3(x, LandscapeMap.Table[i, j], z) }); normalMatrix[i, j + 1] = tempNormal; //tempNormal = getLandscapeNormal(i, j + 1); normals[vertexPointer + 1, 0] = tempNormal.X; normals[vertexPointer + 1, 1] = tempNormal.Y; normals[vertexPointer + 1, 2] = tempNormal.Z; texCoords[vertexPointer + 1, 0] = vertices[vertexPointer + 1, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer + 1, 1] = vertices[vertexPointer + 1, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertices[vertexPointer + 2, 0] = x + (float)LandscapeMap.GridStep; vertices[vertexPointer + 2, 1] = LandscapeMap.Table[i + 1, j]; vertices[vertexPointer + 2, 2] = z; tempNormal = VectorMathOperations.GetNormalToPlane(new Vector3[3] { new Vector3(x + (float)LandscapeMap.GridStep, LandscapeMap.Table[i + 1, j], z), new Vector3(x, LandscapeMap.Table[i, j], z), new Vector3(x, LandscapeMap.Table[i, j + 1], z + (float)LandscapeMap.GridStep) }); normalMatrix[i + 1, j] = tempNormal; //tempNormal = getLandscapeNormal(i + 1, j); normals[vertexPointer + 2, 0] = tempNormal.X; normals[vertexPointer + 2, 1] = tempNormal.Y; normals[vertexPointer + 2, 2] = tempNormal.Z; texCoords[vertexPointer + 2, 0] = vertices[vertexPointer + 2, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer + 2, 1] = vertices[vertexPointer + 2, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertices[vertexPointer + 3, 0] = x + (float)LandscapeMap.GridStep; vertices[vertexPointer + 3, 1] = LandscapeMap.Table[i + 1, j]; vertices[vertexPointer + 3, 2] = z; normals[vertexPointer + 3, 0] = normals[vertexPointer + 2, 0]; normals[vertexPointer + 3, 1] = normals[vertexPointer + 2, 1]; normals[vertexPointer + 3, 2] = normals[vertexPointer + 2, 2]; texCoords[vertexPointer + 3, 0] = vertices[vertexPointer + 3, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer + 3, 1] = vertices[vertexPointer + 3, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertices[vertexPointer + 4, 0] = x; vertices[vertexPointer + 4, 1] = LandscapeMap.Table[i, j + 1]; vertices[vertexPointer + 4, 2] = z + (float)LandscapeMap.GridStep; normals[vertexPointer + 4, 0] = normals[vertexPointer + 1, 0]; normals[vertexPointer + 4, 1] = normals[vertexPointer + 1, 1]; normals[vertexPointer + 4, 2] = normals[vertexPointer + 1, 2]; texCoords[vertexPointer + 4, 0] = vertices[vertexPointer + 4, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer + 4, 1] = vertices[vertexPointer + 4, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertices[vertexPointer + 5, 0] = x + (float)LandscapeMap.GridStep; vertices[vertexPointer + 5, 1] = LandscapeMap.Table[i + 1, j + 1]; vertices[vertexPointer + 5, 2] = z + (float)LandscapeMap.GridStep; tempNormal = VectorMathOperations.GetNormalToPlane(new Vector3[3] { new Vector3(x + (float)LandscapeMap.GridStep, LandscapeMap.Table[i + 1, j + 1], z + (float)LandscapeMap.GridStep), new Vector3(x + (float)LandscapeMap.GridStep, LandscapeMap.Table[i + 1, j], z), new Vector3(x, LandscapeMap.Table[i, j + 1], z + (float)LandscapeMap.GridStep) }); normalMatrix[i + 1, j + 1] = tempNormal; //tempNormal = getLandscapeNormal(i + 1, j + 1); normals[vertexPointer + 5, 0] = tempNormal.X; normals[vertexPointer + 5, 1] = tempNormal.Y; normals[vertexPointer + 5, 2] = tempNormal.Z; texCoords[vertexPointer + 5, 0] = vertices[vertexPointer + 5, 0] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); texCoords[vertexPointer + 5, 1] = vertices[vertexPointer + 5, 2] / (float)(LandscapeMap.GridStep * LandscapeMap.TableSize); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vertexPointer += 6; } } // Making smooth normals vertexPointer = 0; for (Int32 i = 0; i < LandscapeMap.TableSize - 1; i++) { for (Int32 j = 0; j < LandscapeMap.TableSize - 1; j++) { tempNormal = getLandscapeSmoothNormal(LandscapeMap, normalMatrix, i, j, normalSmoothLvl); normals[vertexPointer, 0] = tempNormal.X; normals[vertexPointer, 1] = tempNormal.Y; normals[vertexPointer, 2] = tempNormal.Z; tempNormal = getLandscapeSmoothNormal(LandscapeMap, normalMatrix, i, j + 1, normalSmoothLvl); normals[vertexPointer + 1, 0] = tempNormal.X; normals[vertexPointer + 1, 1] = tempNormal.Y; normals[vertexPointer + 1, 2] = tempNormal.Z; tempNormal = getLandscapeSmoothNormal(LandscapeMap, normalMatrix, i + 1, j, normalSmoothLvl); normals[vertexPointer + 2, 0] = tempNormal.X; normals[vertexPointer + 2, 1] = tempNormal.Y; normals[vertexPointer + 2, 2] = tempNormal.Z; normals[vertexPointer + 3, 0] = normals[vertexPointer + 2, 0]; normals[vertexPointer + 3, 1] = normals[vertexPointer + 2, 1]; normals[vertexPointer + 3, 2] = normals[vertexPointer + 2, 2]; normals[vertexPointer + 4, 0] = normals[vertexPointer + 1, 0]; normals[vertexPointer + 4, 1] = normals[vertexPointer + 1, 1]; normals[vertexPointer + 4, 2] = normals[vertexPointer + 1, 2]; tempNormal = getLandscapeSmoothNormal(LandscapeMap, normalMatrix, i + 1, j + 1, normalSmoothLvl); normals[vertexPointer + 5, 0] = tempNormal.X; normals[vertexPointer + 5, 1] = tempNormal.Y; normals[vertexPointer + 5, 2] = tempNormal.Z; vertexPointer += 6; } } VertexBufferObjectTwoDimension <float> verticesVBO = new VertexBufferObjectTwoDimension <float>(vertices, OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, 0, 3, VertexBufferObjectBase.DataCarryFlag.Invalidate); VertexBufferObjectTwoDimension <float> normalsVBO = new VertexBufferObjectTwoDimension <float>(normals, OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, 1, 3, VertexBufferObjectBase.DataCarryFlag.Invalidate); VertexBufferObjectTwoDimension <float> texCoordsVBO = new VertexBufferObjectTwoDimension <float>(texCoords, OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, 2, 2, VertexBufferObjectBase.DataCarryFlag.Invalidate); VertexBufferObjectTwoDimension <float> tangentsVBO = new VertexBufferObjectTwoDimension <float>(AdditionalVertexInfoCreator.CreateTangentVertices(vertices, texCoords), OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, 4, 3, VertexBufferObjectBase.DataCarryFlag.Invalidate); VertexBufferObjectTwoDimension <float> bitangentsVBO = new VertexBufferObjectTwoDimension <float>(AdditionalVertexInfoCreator.CreateBitangentVertices(vertices, texCoords), OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, 5, 3, VertexBufferObjectBase.DataCarryFlag.Invalidate); VertexArrayObject vao = new VertexArrayObject(); vao.AddVBO(verticesVBO, normalsVBO, texCoordsVBO, tangentsVBO, bitangentsVBO); vao.BindBuffersToVao(); return(vao); }
////////////////////////////// SPHERE POLYGON COLLISION """""""""\\* ///// ///// возвращает true если сфера пересекает переданный полигон. ///// ////////////////////////////// SPHERE POLYGON COLLISION """""""""\\* public static bool SpherePolygonCollision(Vector3[] vPolygon, Vector3 vCenter, Int32 vertexCount, float radius) { // // 1) Сначала нужно проверить, пересекается ли сфера с плоскостью, на которой находится // полигон. Помните, что плоскости бесконечны, и сфера может быть хоть в пятистах // единицах от полигона, если сфера пересекает его плоскость - триггер сработает. // Нам нужно написать функцию, возвращающую положение сферы: либо она полностью // с одной стороны плоскости, либо с другой, либо пересекает плоскость. // Для этого мы создали функцию ClassifySphere(), которая возвращает BEHIND, FRONT // или INTERSECTS. Если она вернёт INTERSECTS, переходим ко второму шагу, иначе - мы // не пересекаем плоскость полигона. // // 2) Второй шаг - получить точку пересечения. Это одна из хитрых частей. Мы знаем, // что имея точку пересечения с плоскостью, нужно просто вызвать функцию InsidePolygon(), // чтобы увидеть, находится ли эта точка внутри полигона, точно так же, как мы делали // в уроке "Коллизия линии и полигона". Итак, как получить точку пересечения? Это // не так просто, как кажется. Поскольку на сфере может распологатся бесконечное // число точек, могут быть миллионы точек пересечения. Мы попробуем немного другой путь. // Мы знаем, что можем найти нормаль полигона, что скажет нам направление, куда // он "смотрит". ClassifyPoly() кроме всего прочего вернёт дистанцию от центра сферы до // плоскости. И если мы умножим нормаль на эту дистанцию, то получим некое смещение. // Это смещение может затем быть вычтено из центра сферы. Хотите верьте, хотите нет, // но теперь у нас есть точка на плоскости в направлении плоскости. Обычно эта точка // пересечения работает хорошо, но если мы пересечем ребра полигона, она не сработает. // То, что мы только что сделали, называется "проекция центра сферы на плоскость". // Другой путь - "выстрелить" луч от центра сферы в направлении, противоположном // нормали плоскости, тогда мы найдем точку пересечения линии (этого луча) и плоскости. // Мой способ занимает 3 умножения и одно вычитание. Выбирайте сами. // // 3) Имея нашу псевдо-точку пересечения, просто передаём её в InsidePolygon(), // вместе с вершинами полигона и их числом. Функция вернёт true, если точка // пересечения находится внутри полигона. Запомните, одно то, что функция // вернёт false, не значит, что мы на этом остановимся! Если мы ещё не "пересеклись", // переходим к шагу 4. // // 4) Если мы дошли досюда, значит, мы нашли точку пересечения, и она находится // вне периметра полигона. Как так? Легко. Подумайте, если центр сферы находится // вне треугольника, но есть пересечение - остаётся ещё её радиус. Последняя // проверка нуждается в нахождении точка на каждом ребре полигона, которая // ближе всего к центру сферы. У нас есть урок "ближайшая точка на линии", так что // убедитесь, что вы его поняли, прежде, чем идти дальше. Если мы имеем дело // с треугольником, нужно пройти три ребра и найти на них ближайшие точки к центру // сферы. После этого рассчитываем дистанцию от этих точек до центра сферы. Если // дистанция меньше, чем радиус, есть пересечение. Этот способ очень быстр. // Вым не нужно рассчитывать всегда все три ребра, так как первая или вторая // дистанция может быть меньше радиуса, и остальные рассчеты можно будет не производить. // // Это было вступление, *уфф!*. Надеюсь, вам ещё не хочется плакать от такого обилия // теории, так как код на самом деле будет не слишком большим. // 1) ШАГ ОДИН - Найдем положение сферы // Сначала найдем нормаль полигона Vector3 vNormal = VectorMathOperations.GetNormalToPlane(vPolygon); // Переменная для хранения дистанции от сферы float distance = 0.0f; // Здесь мы определяем, находится ли сфера спереди, сзади плоскости, или пересекает её. // Передаём центр сферы, нормаль полигона, точку на плоскости (любую вершину), радиус // сферы и пустой float для сохранения дистанции. Int32 classification = ClassifySphere(vCenter, vNormal, vPolygon[0], radius, ref distance); // Если сфера пересекает плоскость полигона, нам нужно проверить, пересекает ли // она сам полигон. if (classification == 1) { // 2) ШАГ ДВА - Находим псевдо точку пересечения. // Теперь нужно спроецировать центр сфера на плоскость полигона, в направлении // его номали. Это делается умножением нормали на расстояние от центра сферы // до плоскости. Расстояние мы получили из ClassifySphere() только что. // Если вы не понимаете суть проекции, представьте её примерно так: // "я стартую из центра сферы и двигаюсь в направлении плоскости вдоль её нормали // Когда я должен остановится? Тогда, когда моя дистанция от центра сферы станет // равной дистанции от центра сферы до плоскости." Vector3 vOffset = new Vector3(vNormal.X * distance, vNormal.Y * distance, vNormal.Z * distance); // Получив смещение "offset", просто вычитаем его из центра сферы. "vPosition" // теперь точка, лежащая на плоскости полигона. Внутри ли она полигона - это // другой вопрос. Vector3 vPosition = vCenter - vOffset; // 3) ШАГ ТРИ - Проверим, находится ли точка пересечения внутри полигона // Если точка пересечения внутри // полигона, ф-я вернёт true, иначе false. if (insidePolygon(vPosition, vPolygon, vertexCount)) { return(true); // Есть пересечение! } else // Иначе { // 4) ШАГ ЧЕТЫРЕ - Проверим, пересекает ли сфера рёбра треугольника // Если мы дошли досюда, центр сферы находится вне треугольника. // Если хоть одна часть сферы пересекает полигон, у нас есть пересечение. // Нам нужно проверить расстояние от центра сферы до ближайшей точки на полигоне. if (EdgeSphereCollision(vCenter, vPolygon, vertexCount, radius)) { return(true); // We collided! } } } // Если мы здесь, пересечения нет return(false); }