Затенение вершин и вычисление эффекта вектора освещения - PullRequest
2 голосов
/ 02 сентября 2010

При заданной вершине треугольника с тремя трехмерными точками, как рассчитать угол между ней и данной точкой.

class Point3D
{
    double x, y, z;
}

class Vertex
{
     Point3D P1, P2, P3;
}

Point3D LightPoint;

http://www.ianquigley.com/iq/RandomImages/vextor.png

Светлая точка красного цвета.Синие точки - треугольник с показанной нормалью поверхности.

Мне нужно вычислить нормаль поверхности и угол между ней и LightPoint.Я нашел несколько кусочков, но ничего, что могло бы соединить их.

Ответы [ 3 ]

5 голосов
/ 02 сентября 2010

ОК, вот так ...

У вас есть точки 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));
1 голос
/ 02 сентября 2010

Чтобы получить вектор нормали, рассчитайте перекрестное произведение между P2 - P1 и P3 - P1.

Чтобы получить угол, используйте точечное произведение между нормалью и lightPoint. Помните, что точка (a, b) = | a || b | * cos (тета), поэтому, поскольку вы можете рассчитать длину обоих, вы можете получить тета (угол между ними). ​​

0 голосов
/ 03 сентября 2010

Только тангенциально связаны, но большинство графических систем также допускают интерполяцию нормалей поверхности, где каждая вершина имеет связанную нормаль. Эффективная нормаль в данном U, V затем интерполируется из вершинных нормалей. Это обеспечивает более плавное затенение и намного лучшее представление «кривизны» при освещении без необходимости полагаться на очень большое количество треугольников. Многие системы делают подобные трюки с «рельефным отображением», чтобы ввести возмущения в нормали и получить ощущение текстуры без моделирования отдельных небольших граней.

Теперь вы можете вычислить угол между интерполированной нормалью и вектором света, как уже описывали другие.

Еще один интересный вопрос - подумать, есть ли у вас источник окружающего света. Если вы можете притворяться, что точечный источник света бесконечно далеко (по сути, это верно для источника, такого как прямой солнечный свет на небольшой поверхности, такой как Земля), вы можете избавить вас от всех проблем, связанных с вычислением векторных разностей, и просто предположить, что входящий угол света равен постоянная. Теперь у вас есть единственный постоянный вектор света для вашего точечного произведения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...