В разделе рассматриваются методы OpenGL, обеспечивающие эффект глубины в зависимости от значений z-координаты вершины. Это, так называемый "тест глубины", включив и настроив который, можно различать положение объектов по глубине – расстоянию от наблюдателя до объекта по нормали к плоскости экрана.
Включается тест глубины методом Enable с параметром
///
/// Параметр активации теста глубины.
///
public const int DEPTH_TEST = 0x0B71;
Узнать, включен ли тест глубины можно методом IsEnabled либо методом Get с тем же параметром.
При работе с буфером глубины необходимо в начале каждого фрейма очищать этот буфер точно так же, как это делается с буфером цвета. Для очистки используется тот же метод Clear с параметром
///
/// Идентифицирует буфер глубины в методах Clear и PushAttrib.
///
public const int DEPTH_BUFFER_BIT = 0x00000100;
Тот же параметр используется для сохранения состояния буфера глубины в стеке методом PushAttrib.
Поместите описания этих констант в класс gl библиотеки GL.
Для проверки работы теста глубины необходимы две точки, имеющие одни и те же координаты xo, yo, но разные координаты zo. Преобразование порта наблюдения координаты zo (которая в данном случае w = 1 совпадает с zd) имеет вид zw = (f – n)/2*zd + (f + n)/2, где n и f – близкая (near) и дальняя (far) границы буфера глубины. По умолчанию n = 0 и f = 1.
Из этой формулы следует, что минимальному значению координаты zo = zd = -1 отвечает zw = n = 0, а максимальному zo = zd = 1 значение zw = f =1. Тестированию подвергаются значения zw. По умолчанию при включении теста глубины более удаленный от наблюдателя пиксель (с большим значением zw) оказывается скрытым более близким (с меньшим значением zw).
Если тест глубины не активирован, то из двух вершин, имеющих одни и те же координаты xo, yo будет изображена та, которая направляется в буфер последней по очереди. Если тест включен, то, по умолчанию, будет изображена та, у которой значение zw меньше.
Для проверки работы теста глубины следует изменить код в случае "One point" в методе BuildFrame() класса f3D так, чтобы код содержал две точки, имеющие одинаковые значения координат x, y, но разные значения координаты z, и точки имели бы разный цвет. Например,
case "One point": //0
double[] prMtrx = new double[16], mvMtrx = new double[16];
int[] vp = new int[4];
for (int i = 0; i < 16; i++)
{
prMtrx[i] = gl.Get(gl.PROJECTION_MATRIX, 16)[i];
mvMtrx[i] = gl.Get(gl.MODELVIEW_MATRIX, 16)[i];
if (i < 4) vp[i] = (int)gl.Get(gl.VIEWPORT, 4)[i];
}
float Zo1 = 0, Zo2 = 1;
gl.PointSize(10);
gl.Begin(gl.POINTS);
// В начале идет красная точка
gl.Color(1, 0, 0);
gl.Vertex(0, 0, Zo1);
// Затем зеленая
gl.Color(0, 1, 0);
gl.Vertex(0, 0, Zo2);
gl.End();
double Zw1, Zw2, Xw1, Xw2, Yw1, Yw2;
gl.Project(0, 0, Zo1,
mvMtrx, prMtrx, vp, out Xw1, out Yw1, out Zw1);
gl.Project(0, 0, Zo2,
mvMtrx, prMtrx, vp, out Xw2, out Yw2, out Zw2);
stLabel.Text = string.Format("Zw1={0:f}; Zw2={1:f}", Zw1, Zw2);
break;
В этом примере значение z-координаты у красной точки меньше, чем у зеленой точки. Однако на экране будет видна зеленая точка. Это происходит потому, что тест глубины по умолчанию не активен, а зеленая точка изображается последней. Если тест глубины не активен, то всегда будет изображаться последняя точка, не зависимо от значений координаты глубины.
Для включения теста глубины добавьте в начало метода BuildFrame() две строки:
gl.Clear(gl.DEPTH_BUFFER_BIT);
gl.Enable(gl.DEPTH_TEST);
Убедитесь, что видна красная точка, которая находится ближе.
Поменяйте значения z-координат точек так, чтобы у зеленой точки z-координата была меньше. Убедитесь, что видна зеленая точка. Теперь, при включенном тесте глубины, точка, имеющая меньшую глубину, будет перекрывать изображение точки с большей глубиной, и это не зависит от последовательности, в которой точки изображаются.
В приведенном примере можно так же проверить работу формулы zw = (f – n)/2*zd + (f + n)/2, преобразующей объектную координату глубины zo = zd в оконную координату zw, учитывая, что f = 1 и n = 0 по умолчанию.
Методы ClearDepth и DepthFunc
Очищается буфер глубины значением, которое указывает метод
///
/// Очищает буфер глубины
///
///
/// Значение, которым заполняется буфер глубины. По умолчанию это 1.
///
[DllImport("OPENGL32.DLL", EntryPoint = "glClearDepth")]
public static extern void ClearDepth(double depth);
Узнать текущее значение, которым очищен буфер глубины, можно методом Get в форме
gl.Get(gl.DEPTH_CLEAR_VALUE, 1)[0]
Постоянная, использованная здесь, равна
///
/// Аргумент Get требует возврата значения одного параметра -
/// оконной координаты zw, которым заполняются битовые плоскости
/// буфера глубины при его очистке.
///
public const int DEPTH_CLEAR_VALUE = 0x0B73;
Тестирование фрагмента, направляемого в буфер глубины, проводится функцией DepthFunc по тому же правилу и с теми же параметрами, что и альфа-тестирование. Метод DepthFunc активен лишь при включенном тестировании глубины. Описание функции DepthFunc имеет вид
///
/// Устанавливает операцию сравнения при работе теста глубины.
///
///
/// Определяет операцию сравнения глубины. Имеет значения символьных постоянных
/// NEVER, LESS, EQUAL, LEQUAL, GREATER, NOTEQUAL, GEQUAL и ALWAYS.
/// Значение по умолчанию LESS.
///
[DllImport("OPENGL32.DLL", EntryPoint = "glDepthFunc")]
public static extern void DepthFunc(int function);
Текущее значение параметра function функции DepthFunc может быть получено методом Get в форме
(int)gl.Get(gl.DEPTH_FUNC, 1)[0]
Здесь константа DEPTH_FUNC имеет вид
///
/// Аргумент Get требует возврата значения 1 параметра -
/// целой символьной постоянной, определяющей функцию тестирования глубины.
///
public const int DEPTH_FUNC = 0x0B74;
Примечание
Казалось бы, если с помощью функции DepthFunc изменить условие тестирования, например, с LESS (установлено по умолчанию) на GREATER, то будет изображена та вершина, у которой значение zw больше. Но по умолчанию буфер глубины очищен максимальным значением zw = 1. Поэтому все фрагменты с меньшими значениями будут отсекаться правилом тестирования. Для эффективного использования функции GREATER следовало бы изменить значение параметра очистки методом ClearDepth.
В практическом программировании не рекомендуется изменять условие тестирования по глубине (LESS) и параметр очистки буфера глубины (1), установленные по умолчанию.
Посмотрите сцену тестирования глубины в приложении.
Пояснения и код для того, кто продолжает строить авторский проект.
Примечания
-
В OpenGL есть функция DepthRange, устанавливающая значения параметров n и f. Здесь эта функция использоваться не будет, но, при желании, можно ее описать в классе gl и затем использовать. Так может выглядеть описание
///
/// Определяет отображение нормализованных координат устройства на оконные координаты
///
///
/// Определяет отображение ближней плоскости на оконные координаты
///
///
/// Определяет отображение дальней плоскости на оконные координаты
///
[DllImport("OPENGL32.DLL", EntryPoint = "glDepthRange")]
public static extern void DepthRange(double near, double far);
-
В OpenGL есть метод DepthMask(bool mask) , который работает по аналогии с методом ColorMask, разрешая и запрещая запись в буфер глубины. По умолчанию параметр mask равен true – запись разрешена.
Тест рубежного контроля
-
Каким образом активируется тест глубины?
-
Как очищается буфер глубины?
-
Опишите, как работает тест глубины.
-
Как определить, активирован ли тест глубины?
-
Какой метод задает значение zw, очищающее буфер глубины?
-
Как получить текущее значение zw, очищающее буфер глубины?
-
Какое значение имеет параметр, очищающий буфер глубины, по умолчанию?
-
Какой метод определяет функцию тестирования глубины?
-
Как определить текущие значения функции тестирования глубины?
-
С каким параметром следует вызвать метод PushAttrib, чтобы сохранить в стеке текущие атрибуты тестирования глубины?
Тестирование глубины показывает, что по умолчанию, объектная система координат, как и оконная, имеет левую ориентацию (ось x направлена вправо, y – вверх, а z – в глубину экрана), что не очень удобно в приложениях, где обычной является правая система координат. В следующем разделе будет введено важное преобразование от координат наблюдения к координатам отсечения, в котором ось z испытывает отражение. Это позволит использовать правую объектную систему координат. Кроме того, новое преобразование позволит сохранять пропорции объекта (отношение ширины к высоте) при переходе к оконным координатам.
Достарыңызбен бөлісу: |