Итак, вот как это сделать.
Сначала необходимо сохранить восемь точек в каждой ограничительной рамке предсказуемым образом, например, каждый бит в целом числе, представляющем его положение относительно центра рамки.,Что вы можете сделать, это использовать 0x4 для представления EAST (+ x) (ноль в этом бите означает WEST), 0x2 для представления NORTH (ноль в этом бите означает SOUTH) и 0x1 для представления TOP (ноль в этом бите означает BOTTOM).Теперь вы можете универсально получить доступ ко всем точкам в одной и той же позиции ограничительной рамки, указав номер позиции.(все нулевые битовые числа равны нулю. Java предупреждает, что эти назначения не имеют смысла, но они помогают с удобочитаемостью.)
Настройка ограничивающего прямоугольника: (сделать это для каждого ограничивающего прямоугольника)
pointList = new Point3d[8];
pointList[WEST|SOUTH|BOTTOM] = new Point3d(x0,y0,z0);
pointList[WEST|SOUTH|TOP] = new Point3d(x0,y0,z1);
pointList[WEST|NORTH|BOTTOM] = new Point3d(x0,y1,z0);
pointList[WEST|NORTH|TOP] = new Point3d(x0,y1,z1);
pointList[EAST|SOUTH|BOTTOM] = new Point3d(x1,y0,z0);
pointList[EAST|SOUTH|TOP] = new Point3d(x1,y0,z1);
pointList[EAST|NORTH|BOTTOM] = new Point3d(x1,y1,z0);
pointList[EAST|NORTH|TOP] = new Point3d(x1,y1,z1);
Далее вычислите нормаль по углу обзора.(Вращение влево / вправо, наклон - вверх / вниз)
float nx = -(float)Math.cos(yaw);
float ny = (float)Math.sin(yaw);
float nz = (float)Math.sin(pitch);
Я думаю, что негатив - это правильно, но если все невидимо с одной стороны, просто поменяйте его:)
Рассчитайте характеристическую точку, которая является просто индексом, который вы собираетесь проверять в каждом ограничивающем прямоугольнике, потому что он представляет точку в каждом прямоугольнике, которая будет ближайшей к плоскости на невидимой стороне:
int characteristicPoint = (nx<0?WEST:EAST)|
(ny<0?SOUTH:NORTH)|
(nz<0?BOTTOM:TOP);
Убедитесь, что каждый ограничивающий прямоугольник настроен таким образом, чтобы x, y, z были меньше, чем x, y, z штрих (x0 = x aught, x1 = x штрих)
Затем соберите вашу характеристику ('отметьте ') точку, ваш набор нормалей (' frustrum ') и положение вашей камеры (x, y, z) и сделайте это с каждым ограничивающим прямоугольником:
float checkA = ((bounds.pointList[check].x-position.x)*frustrum.x) +
((bounds.pointList[check].y-position.y)*frustrum.y);
float checkB = ((bounds.pointList[check].x-position.x)*frustrum.x) +
((bounds.pointList[check].z-position.z)*frustrum.z);
if(checkB>=0&&checkA>=0) {
visible = true;
return;
} else if(checkB<0&&checkA<0) {
visible = false;
return;
} else {
float checkC = ((bounds.pointList[check].y-position.y)*frustrum.y) +
((bounds.pointList[check].z-position.z)*frustrum.z);
if(checkC>=0) {
visible = true;
return;
} else {
visible = false;
return;
}
}
Это простая линейная алгебра (IMO) и логика такова: если точка находится на положительной стороне двух или более линий, представляющих плоскость, она видна.Если он находится на отрицательной стороне буксира или нескольких линий, представляющих плоскость, он невидим.Вы вычисляете первые два, и если они различны (один отрицательный, один положительный), вы проверяете третий и принимаете это значение.
Важно учитывать следующее свойство при обработке линий как уравнений:
-x-y = p != x+y = p
Строка такая же, но ее неявное «обращение» обратное.
Надеюсь, это поможет кому-то еще в этом вопросе.Это было трудно, но приятно, понять.
Это можно сделать более эффективным, сохранив первую половину CheckA, я полагаю:)