Нашли ошибку или опечатку? Выделите текст и нажмите

Поменять цветовую

гамму сайта?

Поменять
Обновления сайта
и новые разделы

Рекомендовать в Google +1

Трехмерные объекты

126

Для прорисовки всего лишь одного треугольника нужно позаботиться о буфере вершин, эффектах, видах и проекциях. Треугольник всегда плоский поэтому предыдущий пример вряд ли может быть достаточно полной иллюстрацией инструментов трехмерного рисования. Однако из него вы узнали о базовых концепциях трехмерного рисования в Silverlight и теперь готовы к созданию более сложных фигур.

Сложная составная трехмерная фигура создается путем комбинирования небольшой группы плоских двухмерных треугольников. В следующем примере мы создадим куб.

Куб состоит из шести квадратных сторон. Каждая квадратная сторона состоит из двух треугольников н соединена со смежными квадратными сторонами под прямым углом. На рисунке показано разбиение куба на треугольники, которые можно смоделировать в Silverlight:

Разбиение куба на треугольники

Чтобы уменьшить накладные расходы и повысить производительность трехмерной программы, невидимые фигуры обычно не визуализируют. Например, если известно, что мы никогда не увидим на экране нижнюю сторону куба, то нет причин нумеровать и определять в коде два треугольника, расположенных на этой стороне. Однако в данном примере мы определим все стороны куба, чтобы можно было свободно вращать его перед камерой или перемещать камеру вокруг него.

Базовая инфраструктура данного примера такая же, как и предыдущего, в котором мы нарисовали один треугольник. В первую очередь необходимы два поля, содержащие буфер вершин и объект эффектов.

Буфер вершин необходимо заполнить непосредственно перед выводом страницы (в конструкторе). Обычно это делается путем вызова другого метода, созданного вами (аналогично методу PrepareDrawing() в предыдущем примере). В этом методе сначала нужно определить цвета. Следующий этап — определение точек, служащих вершинами треугольников. Чтобы легче было управлять набором вершин, имеет смысл определить точки отдельно, а затем многократно использовать их для определения вершин.

Для каждого куба необходимы восемь точек: четыре на передней грани и четыре на задней. Каждый куб состоит из двенадцати треугольников, по два на каждую грань. Каждый треугольник состоит из трех вершин. Следовательно, для прорисовки куба необходимы тридцать шесть вершин. Ниже показан весь код, включая определение камеры и установку эффекта:

// Хранение вершин треугольников
VertexBuffer vertexBuffer;

// Параметры процесса рисования
BasicEffect effect;

private void PrepareDrawing()
{
            // Определение цветов для заливки треугольников
            Color colorRed = new Color(255, 0, 0, 0);
            Color colorBlue = new Color(0, 255, 0, 0);
            Color colorGreen = new Color(0, 0, 255, 0);
            Color colorWhite = new Color(255, 255, 255, 255);

            // Определение точек - вершин всех треугольников           
            Vector3 topLeftFront = new Vector3(-1, 1, 1);
            Vector3 bottomLeftFront = new Vector3(-1, -1, 1);
            Vector3 topRightFront = new Vector3(1, 1, 1);
            Vector3 bottomRightFront = new Vector3(1, -1, 1);
            Vector3 topLeftBack = new Vector3(-1, 1, -1);
            Vector3 topRightBack = new Vector3(1, 1, -1);
            Vector3 bottomLeftBack = new Vector3(-1, -1, -1);
            Vector3 bottomRightBack = new Vector3(1, -1, -1);

            // Массив вершин
            VertexPositionColor[] vertices = new VertexPositionColor[36];

            // Задание всех вершин
            // Передняя грань
            vertices[0] = new VertexPositionColor(topRightFront, colorBlue);
            vertices[1] = new VertexPositionColor(bottomLeftFront, colorBlue);
            vertices[2] = new VertexPositionColor(topLeftFront, colorBlue);
            vertices[3] = new VertexPositionColor(topRightFront, colorGreen);
            vertices[4] = new VertexPositionColor(bottomRightFront, colorGreen);
            vertices[5] = new VertexPositionColor(bottomLeftFront, colorGreen);
            // Задняя грань
            vertices[6] = new VertexPositionColor(bottomLeftBack, colorRed);
            vertices[7] = new VertexPositionColor(topRightBack, colorRed);
            vertices[8] = new VertexPositionColor(topLeftBack, colorRed);
            vertices[9] = new VertexPositionColor(bottomRightBack, colorWhite);
            vertices[10] = new VertexPositionColor(topRightBack, colorWhite);
            vertices[11] = new VertexPositionColor(bottomLeftBack, colorWhite);
            // Верхняя грань
            vertices[12] = new VertexPositionColor(topLeftBack, colorRed);
            vertices[13] = new VertexPositionColor(topRightBack, colorRed);
            vertices[14] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[15] = new VertexPositionColor(topRightBack, colorWhite);
            vertices[16] = new VertexPositionColor(topRightFront, colorWhite);
            vertices[17] = new VertexPositionColor(topLeftFront, colorWhite);
            // Нижняя грань
            vertices[18] = new VertexPositionColor(bottomRightBack, colorWhite);
            vertices[19] = new VertexPositionColor(bottomLeftBack, colorWhite);
            vertices[20] = new VertexPositionColor(bottomLeftFront, colorWhite);
            vertices[21] = new VertexPositionColor(bottomRightFront, colorGreen);
            vertices[22] = new VertexPositionColor(bottomRightBack, colorGreen);
            vertices[23] = new VertexPositionColor(bottomLeftFront, colorGreen);
            // Левая грань
            vertices[24] = new VertexPositionColor(bottomLeftFront, colorGreen);
            vertices[25] = new VertexPositionColor(bottomLeftBack, colorGreen);
            vertices[26] = new VertexPositionColor(topLeftFront, colorGreen);
            vertices[27] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[28] = new VertexPositionColor(bottomLeftBack, colorRed);
            vertices[29] = new VertexPositionColor(topLeftBack, colorRed);
            // Правая грань
            vertices[30] = new VertexPositionColor(bottomRightBack, colorRed);
            vertices[31] = new VertexPositionColor(bottomRightFront, colorRed);
            vertices[32] = new VertexPositionColor(topRightFront, colorRed);
            vertices[33] = new VertexPositionColor(bottomRightBack, colorBlue);
            vertices[34] = new VertexPositionColor(topRightFront, colorBlue);
            vertices[35] = new VertexPositionColor(topRightBack, colorBlue);

            // Установка буфера вершин
            GraphicsDevice device = GraphicsDeviceManager.Current.GraphicsDevice;
            vertexBuffer = new VertexBuffer(device, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly);
            vertexBuffer.SetData(0, vertices, 0, vertices.Length, 0);

            // Настройка камеры
            Matrix view = Matrix.CreateLookAt(new Vector3(1, 1, 3), Vector3.Zero, Vector3.Up);
            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.33f, 1, 100);

            // Задание эффекта
            effect = new BasicEffect(device);
            effect.World = Matrix.Identity;
            effect.View = view;
            effect.Projection = view * projection;
            effect.VertexColorEnabled = true;
}

И наконец, нужно применить тот же код рисования, который мы использовали в предыдущем примере с одним треугольником. Фактически мы решаем ту же задачу — копирование буфера вершин в GraphicsDevice и его визуализация как списка треугольников:

private void DrawingSurface_Draw_1(object sender, DrawEventArgs e)
{
            GraphicsDevice device = GraphicsDeviceManager.Current.GraphicsDevice;

            device.Clear(new Color(0, 0, 0, 0));
            device.SetVertexBuffer(vertexBuffer);

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer.VertexCount / 3);
            }
}
Трехмерный куб в Silverlight

В данном примере каждому треугольнику присвоен сплошной цвет (например, синий, зеленый и т.д.). Это позволяет легко различать рисуемые треугольники. Однако в более реалистичных приложениях часто нужно использовать вершины с разными цветами. Соответственно треугольники будут залиты градиентами. Иногда требуется, чтобы раскраска смежных сторон двух треугольников на разных гранях была одинаковой. Для этого нужно присвоить вершинам в одной точке одинаковые цвета, даже если эти вершины принадлежат разным треугольникам:

...
            // Передняя грань
            vertices[0] = new VertexPositionColor(topRightFront, colorBlue);
            vertices[1] = new VertexPositionColor(bottomLeftFront, colorGreen);
            vertices[2] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[3] = new VertexPositionColor(topRightFront, colorBlue);
            vertices[4] = new VertexPositionColor(bottomRightFront, colorWhite);
            vertices[5] = new VertexPositionColor(bottomLeftFront, colorGreen);
            // Задняя грань
            vertices[6] = new VertexPositionColor(bottomLeftBack, colorWhite);
            vertices[7] = new VertexPositionColor(topRightBack, colorRed);
            vertices[8] = new VertexPositionColor(topLeftBack, colorBlue);
            vertices[9] = new VertexPositionColor(bottomRightBack, colorGreen);
            vertices[10] = new VertexPositionColor(topRightBack, colorRed);
            vertices[11] = new VertexPositionColor(bottomLeftBack, colorWhite);
            // Верх
            vertices[12] = new VertexPositionColor(topLeftBack, colorRed);
            vertices[13] = new VertexPositionColor(topRightBack, colorBlue);
            vertices[14] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[15] = new VertexPositionColor(topRightBack, colorBlue);
            vertices[16] = new VertexPositionColor(topRightFront, colorBlue);
            vertices[17] = new VertexPositionColor(topLeftFront, colorRed);
            // Низ
            vertices[18] = new VertexPositionColor(bottomRightBack, colorRed);
            vertices[19] = new VertexPositionColor(bottomLeftBack, colorBlue);
            vertices[20] = new VertexPositionColor(bottomLeftFront, colorWhite);
            vertices[21] = new VertexPositionColor(bottomRightFront, colorGreen);
            vertices[22] = new VertexPositionColor(bottomRightBack, colorRed);
            vertices[23] = new VertexPositionColor(bottomLeftFront, colorWhite);
            // Левая грань
            vertices[24] = new VertexPositionColor(bottomLeftFront, colorWhite);
            vertices[25] = new VertexPositionColor(bottomLeftBack, colorGreen);
            vertices[26] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[27] = new VertexPositionColor(topLeftFront, colorRed);
            vertices[28] = new VertexPositionColor(bottomLeftBack, colorGreen);
            vertices[29] = new VertexPositionColor(topLeftBack, colorRed);
            // Правая грань
            vertices[30] = new VertexPositionColor(bottomRightBack, colorWhite);
            vertices[31] = new VertexPositionColor(bottomRightFront, colorGreen);
            vertices[32] = new VertexPositionColor(topRightFront, colorRed);
            vertices[33] = new VertexPositionColor(bottomRightBack, colorWhite);
            vertices[34] = new VertexPositionColor(topRightFront, colorRed);
            vertices[35] = new VertexPositionColor(topRightBack, colorBlue);
...

Недостаток данного подхода состоит в том, что при этом не видны ребра куба, потому что цвета смежных граней сливаются:

Тонированный куб Silverlight

Куб — настоящий трехмерный объект, хотя выглядит он не очень впечатляюще. Поскольку это настоящий трехмерный объект, на него можно смотреть с разных точек зрения, перемещая камеру или поворачивая куб.

Пройди тесты