Как сделать треугольник в visual studio

Обновлено: 06.07.2024

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

Если программа "падает" при запуске, то скорее всего это потому, что вы запускаете ее из неправильной директории. Внимательно прочитайте первый урок, чтобы узнать как настроить Visual Studio.

Мы не хотим сейчас углубляться в детали, но вам необходимо создать Vertex Array Object и установить его текущим:

Сделайте это после создания окна (т.е. после создания контекста OpenGL) и до любого другого вызова OpenGL.

Если вы хотите узнать больше о VAO, то здесь есть несколько уроков, но это не так важно сейчас.

Треугольник задается тремя точками. Когда мы говорим о точках в 3D графике, мы используем слово вершина/vertex (вершины/vertices во множественном числе). Каждая вершина имеет 3 координаты: X, Y, Z. Вы можете представить эти координаты так:

  • X находится справа
  • Y находится вверху
  • Z выходит из вашей спины назад. Z указывает именно назад, а не вперед.

Чтобы лучше понять это используйте правило правой руки:

  • X - это ваш большой палец, направленный вправо
  • Y - это ваш указательный палец, направленный вверх
  • Z - это ваш средний палец, направленный на вас, а не от вас.

Заметьте, что вы можете свободно перемещать вашу руку в пространстве и оси X, Y, Z будут передвигаться также, но подробнее об этом мы поговорим позже.

Итак, все что нам нужно - это 3 точки в трехмерном пространстве, чтобы создать треугольник:

Первая вершина имеет координаты (-1, -1, 0). Это означает, что пока мы не используем какие-либо трансформации вершина будет отображаться на экране в точке (-1, -1). Центр экрана имеет координаты (0, 0), ось X направлена вправо, а ось Y вверх, что показано на изображении:

screenCoordinates

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

Следующим шагом будет передача данных о нашем треугольнике в OpenGL. Для этого мы создаем буфер:

Сейчас нам необходимо сделать это только 1 раз.

Теперь, в главном цикле, где до этого мы ничего не выводили, наконец можно вывести треугольник :

Если у вас карта NVidia, то уже сейчас вы можете видеть результат (для других карт продолжайте читать):

triangle_no_shader

Наконец мы вывели наш скучный белый треугольник. Чтобы пойти дальше и раскрасить его в красный нам понадобится нечто, что называется “шейдеры”.

Компиляция шейдеров

В простейшей возможной конфигурации нам понадобится два шейдера. Один из них называется Вершинным и выполняется для каждой вершины, а другой называется Фрагментным и выполняется для каждого фрагмента. А так как мы включили 4х сглаживание (см. первый урок), то для каждого пикселя мы имеем 4 фрагмента.

В OpenGL шейдеры программируются на языке GLSL (GL Shader Language). В отличие от C или Java, GLSL компилируется во время выполнения программы, поэтому каждый новый запуск приложения будет сопровождаться перекомпиляцией шейдеров.

Эти два шейдера как правило находятся в разных файлах. В этом примере мы имеем SimpleFragmentShader.fragmentshader и SimpleVertexShader.vertexshader. Расширение файлов не имеет значения и может быть любым, к примеру .txt или .glsl.

Итак, вот код. Сейчас вам не обязательно углубляться в понимание шейдеров и так как этот код выполняется всего 1 раз за время исполнения программы, то комментариев в коде будет достаточно. Эта функция будет использована во всех уроках и находится в отдельном файле common/loadShader.cpp . Обратите внимание на то, что также как и с буферами мы не имеем прямого доступа к шейдерам. Мы лишь имеем Идентификатор, который указывает на шейдер, а все остальное скрыто внутри драйвера.

Наш Вершинный шейдер

Итак, давайте напишем наш первый вершинный шейдер.

Первая строка в нем говорит компилятору, что мы будем использовать синтаксис OpenGL 3.

Вторая строка объявляет входные данные:

Остановимся подробнее на этом моменте:

  • “vec3″ - это вектор с тремя компонентами в GLSL. Это похоже на glm::vec3, который мы использовали для описания треугольника. Главное помнить, что если мы используем 3х компонентные векторы в C++, то мы должны использовать 3х компонентные векторы в GLSL.
  • “layout(location = 0)” указывает на буфер из которого мы будем получать атрибут vertexPosition_modelspace. Каждая вершина может иметь несколько атрибутов, такие как: позиция, один или несколько цветов, текстурные координаты и другие. OpenGL на данном этапе ничего не знает о цвете и все, что он “видит” - это vec3, т. е. вектор с тремя компонентами. Мы же в свою очередь указываем, каким входным данным соответствует какой буфер. Для этого мы устанавливаем параметр location в такое же значение, которое мы использовали в качестве первого параметра в glVertexAttribPointer. Вообще, здесь не обязательно будет 0, здесь может быть и 12 и любое другое, но не большее чем glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &v), а также важно чтобы число в location было таким же, как и в glVertexAttribPointer.
  • “vertexPosition_modelspace” будет содержать позицию вершины для каждого прохода вертексного шейдера. Название может быть любым.
  • Ключевое слово “in” означает, что этот атрибут является входными данными. Также существует слово “out”, которое указывает соответственно на выходные данные.

Функция, которая будет вызываться для каждого шейдера называется “main”, также как и в C:

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

gl_Position - одна из нескольких встроенных в GLSL переменных. В данном случае мы просто присваиваем ей полученное из буфера значение. Все остальное не является обязательным и будет рассмотрено в Уроке 4.

Наш Фрагментный шейдер

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

И да, вы правы, vec3(1, 0, 0) соответствует красному цвету. Это потому, что на экране компьютера каждый цвет представляется триплетом из Красного, Зеленого и Синего. Таким образом (1, 0, 0) показывает, что цвет является полностью красным, без зеленого и синего.

Перед главным циклом вызываем нашу функцию LoadShaders:

Теперь внутри главного цикла первым делом мы будем очищать экран. Строка приведенная ниже будет заполнять экран темно-синим цветом, так как перед главным циклом мы указываем именно его glClearColor(0.0f, 0.0f, 0.4f, 0.0f):

И теперь мы сообщаем OpenGL, что хотим использовать именно наш шейдер:

… и наконец получаем наш красный треугольник:

red_triangle

В следующем уроке вы узнаете о трансформациях, т.е. узнаете как установить камеру, как перемещать объекты и т.д. Увидимся :)

Круги

Предлагаю для начала потренироваться на простых геометрических фигурах типа Михаила круга. В этом деле большую помощь нам окажет класс CircleShape:

конструктор данного класса принимает в качестве параметра радиус нашей будущей фигуры (например, circle(50.f) );

закрасить фигуру можно с помощью метода setFillColor() , который очень похож на уже знакомый нам метод window.clear() ;

ну и для отображения круга в окне используется метод window.draw() .

using namespace sf ; // подключаем пространство имен sf // Объект, который, собственно, является главным окном приложения RenderWindow window ( VideoMode ( 200 , 200 ) , "SFML Works!" ) ; // Главный цикл приложения: выполняется, пока открыто окно // Пользователь нажал на «крестик» и хочет закрыть окно?

Результат выполнения программы:


Наша фигура может иметь контур. Для его создания используется метод setOutlineThickness(), а для цвета контура — setOutlineColor():

Результат выполнения программы:


Как уже знаем из предыдущего урока, при закрашивании фигур или фона можно еще указать значение прозрачности. Например, строкой setOutlineColor(Color(80, 220, 50, 150)) мы устанавливаем 150 в качестве значения прозрачности контура:


А теперь с помощью строки setOutlineColor(Color(80, 220, 50, 50)) мы установим 50 в качестве значения прозрачности контура:


Вы уже наверняка заметили, что наш круг выходит за границы окна, а это не совсем хорошо. Нужно его немного подвинуть, а поможет нам в этом метод move():

// Перемещаем круг для корректного отображения в окне

Результат выполнения программы:


Регулярные полигоны

-Welcome to the real world!

Отлично! Сейчас мы рассмотрим, как нарисовать и другие фигуры. Теперь ты готов узнать истину. Она заключается в том, что, на самом деле, ложки не существует, Нео твой круг — это немножко не круг, а многоугольник. Да-да, самый обычный многоугольник с большИм количеством вершин. Всё дело в том, что у конструктора класса CircleShape есть еще и второй параметр (помимо радиуса), который отвечает за количество вершин у создаваемой фигуры, и он по умолчанию равен 30 . Именно при значениях близких к 30, многоугольник становится мало отличимым от круга. В то же время, задавая этот параметр самостоятельно, мы можем получить абсолютно другие геометрические элементы. Не трудно догадаться, что 3 вершины — это треугольник, 4 вершины — квадрат, 5 вершин — пятиугольник, ну а 8 вершин — восьмиугольник (октагон).

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

Одним из способов построения двухмерной графики в окне - это использование фигур. Фигуры фактически являются обычными элементами как например кнопка или текстовое поле. К фигурам относят такие элементы как Polygon (Многоугольник), Ellipse (овал), Rectangle (прямоугольник), Line (обычная линия), Polyline (несколько связанных линий). Все они наследуются от абстрактного базового класса System.Windows.Shapes.Shape :

Фигуры в WPF

От базового класса они наследуют ряд общих свойств:

Fill заполняет фон фигуры с помощью кисти - аналогичен свойству Background у прочих элементов

Stroke задает кисть, которая отрисовывает границу фигуры - аналогичен свойству BorderBrush у прочих элементов

StrokeThikness задает толщину границы фигуры - аналогичен свойству BorderThikness у прочих элементов

StrokeStartLineCap и StrokeEndLineCap задают для незамкнутых фигур (Line) контур в начале и в конце линии соответственно

StrokeDashArray задает границу фигуры в виде штриховки, создавая эффект пунктира

StrokeDashOffset задает расстояние до начала штриха

StrokeDashCap задает форму штрихов

Ellipse

Ellipse представляет овал:

При одинаковой ширине и высоту получается круг:

Ellipse в WPF

Rectangle

Rectangle представляет прямоугольник::

С помощью свойств RadiusX и RadiusY можно округлить углы прямоугольника:

Rectangle в WPF

Line представляет простую линию. Для создания линии надо указать координаты в ее свойствах X1, Y1, X2 и Y2. При этом надо учитывать, что началом координатной системы является верхний левый угол:

Line в WPF

Polygon

Polygon представляет многоугольник. С помощью коллекции Points элемент устанавливает набор точек - объектов типа Point, которые последовательно соединяются линиями, причем последня точка соединяется с первой:

Polygon в WPF

В данном случае у нас три точки (50, 150), (150, 50) и (250, 150), которые образуют треугольник.

Polyline

Polyline представляет набор точек, соединенных линиями. В этом плане данный элемент похож на Polygon за тем исключением, что первая и последняя точка не соединяются:

Polyline в WPF

Настройка контура

С помощью ряда свойств мы можем настроить отображение контура. Например:

Stroke в WPF

Цвет самого контура определяется с помощью свойства Stroke , а его толщина - с помощью StrokeThickness .

StrokeDashArray устанавливает длину штрихов вместе с отступами. Например, StrokeDashArray="4 2" устанавливает длину штриха в 4 единицы, а последующего отступа в 2 единицы. И эти значения будут повторяться по всему контуру. При другой установке, например, StrokeDashArray="1 2 3" уже задается два штриха. Первый штрих имеет длину в 1 единицу, а второй - в 3 единицы и между ними расстояие в 2 единицы. И так вы можем настроить количество штрихов и расстояний между ними.

StrokeDashCap задает форму на концах штрихов и может принимать следующие значения:

Flat : стандартные штрихи с плоскими окончаниями

Square : штрихи с прямоугольными окончаниями

Round : штрихи с округлыми окончаниями

Triangle : штрихи с окончаниями в виде треугольников

Программное рисование

Создание фигур программным образом осуществляется так же, как и создаются и добавляются все остальные элементы:

Изучаю шарп, хотелось бы получить критику и советы как лучше сделать!

Три класса

  • Program : Мейн класс вызывает классы Rectangle and Triangle.
  • Rectangle : Содержит метод получение площади по двум сторонам.
  • Triangle : Содержит методы вывода в консоль треугольников с помощью *

Задания

27k 5 5 золотых знаков 14 14 серебряных знаков 45 45 бронзовых знаков @dIm0n может и всё так но я бы хотел узнать как можно сделать лучше если можно @dIm0n Ну так подправьте заголовок, если он вам не нравиться. Человек пришел с полностью рабочим кодом, попросил посмотреть, правильно-ли он написал все, может можно иначе, дал задание по которому он это написал, поставил инспецию кода, но нет, получает минусы, за что? Где тут несогласование с инспекцией то?

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

1. Безотказный ввод числа

Чтобы реализовать "безотказный" ввод числе с клавиатуры, я предлагаю создать вот такой вспомогательный класс.

ConsoleHelper.cs

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

Для одновременной проверки и чтения числа используется метод int.TryParse , который возвращает true , если преобразование строки в int успешно, и false , если нет. В случае успешного преобразования он одновоременно возвращает и само число через out аргумент. Получается 2 в 1.

Из нового и незнакомого здесь используется Predicate<in T> . Предикат - это метод в форме выражения, возвращающего bool (то есть логического выражения), в который передается какой-то аргумент, а нашем случае int . Подробнее о предикатах можно прочитать здесь.

2. Реализация задания

Много кто начинает обучение с консоли, работает со строками, но почему-то мало кто в курсе, что у класса string есть конструкторы, всего 8 перегрузок. В данном случае очень полезной оказалась вот эта перегрузка. Она позволяет создать строку заданной длины, заполненную указанным символом. Это позволит избежать лишних циклов и сделает код проще.

Я переписал классы задания с использованием выше показанного консольного помощника и конструктора string (char c, int count) .

Кстати, если конструктор класса пустой, его можно не указывать. Я убрал пустые конструкторы.

Rectangle.cs

Triangle.cs

Еще я сделал, чтобы положение курсора в консоли менялось относительно текущей строки, а не абсолютных координат экрана, с помощью свойства консоли CursorTop .

3. Пользовательский интерфейс

Для исправления этого, я переписал класс Program , добавил главное меню.

Program.cs

В соответствии с принципом SRP в SOLID, я бы еще вынес меню в отдельный класс, но оставил здесь, чтобы не усложнять пример.

Читайте также: