ОК, вот так ...
У вас есть точки A, B и C, каждая из которых имеет координаты x, y и z.Вы хотите, чтобы длина нормали, как сказал Матиас, позволяла вычислить угол, который вектор между вашей точкой и началом нормали составляет с самой нормалью.Это может помочь вам понять, что ваше изображение вводит в заблуждение для целей наших расчетов;нормаль (синяя линия) должна исходить из одной из вершин треугольника.Чтобы превратить вашу точку в вектор, она должна куда-то идти, и вы знаете только точки вершин (хотя вы можете интерполировать любую точку внутри треугольника, вся точка затенения вершин не должна).
В любом случае, первый шаг - превратить ваши Point3D в Vector3D.Это достигается просто путем определения разницы между координатами каждой точки отправления и пункта назначения.Используйте одну точку как начало координат для обоих векторов, а две другие - как точку назначения каждого.Таким образом, если A является вашим источником, вычтите A из B, затем A из C. Теперь у вас есть вектор, который описывает величину движения по осям X, Y и Z для перехода из точки A в точку B, а также из Aна C. Стоит отметить, что теоретический вектор не имеет собственной начальной точки;чтобы добраться до точки B, вы должны начать с A и применить вектор.
Пространство имен System.Windows.Media.Media3D имеет структуру Vector3D, которую вы можете использовать, и достаточно удобно, Point3D в том же пространстве именимеет функцию Subtract (), которая возвращает Vector3D:
Vector3D vectorAB = pointB.Subtract(pointA);
Vector3D vectorAC = pointC.Subtract(pointA);
Теперь нормаль - это перекрестное произведение двух векторов.Используйте следующую формулу:
v1 x v2 = [y1 * z2 - y2 * z1, z1 * x2 - z2 * x1, x1 * y2 - x2 * y1]
Это основано наМатематическая математика, которую вам не обязательно знать, чтобы ее реализовать.Три члена в матрице - это X, Y и Z нормального вектора.К счастью, если вы используете пространство имен Media3D, структура Vector3D имеет метод CrossProduct (), который сделает это за вас:
Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC);
Теперь вам нужен третий вектор, между LightPoint и A:
Vector3D vectorLight = PointA.Subtract(LightPoint);
Это направление, в котором свет будет двигаться, чтобы попасть в PointA от вашего источника.
Теперь, чтобы найти угол между ними, вы вычисляете скалярное произведение этих двух и длину этих двух:
| v |= sqrt (x ^ 2 + y ^ 2 + z ^ 2)
v1 * v2 = x1 * x2 + y1 * y2 + z1 * z2
Или, если вы используете Media3DVector3D имеет свойство Length и статический метод DotProduct:
double lengthLight = vectorLight.Length;
double lengthNormal = vectorNormal.Length;
double dotProduct = Vector3D.DotProduct(vectorNormal, vectorLight);
Наконец, упомянутая формула Матиаса:
v1 * v2 = | v1 || v2 | cos (theta)
перестановка и замена имен переменных:
double theta = arccos(dotProduct/(lengthNormal*lengthLight))
Или, если вы достаточно умны, чтобы использовать объекты Media3D, забудьте все о длине и точечном продукте:
double theta = Vector3D.AngleBetween(vectorNormal, vectorLight);
Thetaтеперь угол в градусах.Умножьте это на количество 2 (пи) / 360, чтобы получить радианы, если вам это нужно.
Мораль этой истории такова: используйте то, что дает вам основа, если у вас нет веской причины поступить иначе;используя пространство имен Media3D, вся векторная алгебра исчезает, и вы можете найти ответ в 5 простых для чтения строках [Я отредактировал это, добавив код, который использовал - Ian]:
Vector3D vectorAB = Point3D.Subtract(pointB, pointA);
Vector3D vectorAC = Point3D.Subtract(pointC, pointA);
Vector3D vectorNormal = Vector3D.CrossProduct(vectorAB, vectorAC);
Vector3D vectorLight = Point3D.Subtract(pointA, LightPoint);
double lengthLight = light.Length;
double lengthNormal = norm.Length;
double dotProduct = Vector3D.DotProduct(norm, light);
double theta = Math.Acos(dotProduct / (lengthNormal * lengthLight));
// Convert to intensity between 0..255 range for 'Color.FromArgb(...
//int intensity = (120 + (Math.Cos(theta) * 90));