Интересные статьи
CUDA
- Информация о материале
- Автор: Андрей
- Просмотров: 8731
Создается небольшой поект. Одной из задач проекта является морфинг поверхности, состоящей из полигонов. В связи с большим количеством точек поверхности и медленным выполнением кода было решено искать пути ускорения процесса. Переход на OpenMP дал прирост производительности порядка 2-х раз на 4-х ядерном процессоре Intel Q6800. В настоящее время эксперементирую с CUDA. Для сравнения скорости привожу кусок кода проверки попадания точек полигонов в усеченый конус.
Данные о процессоре:
Number of CPU(s) One Physical Processor / 2 Cores / 2 Logical Processors / 64 bits
CPU Full Name Intel(R) Pentium(R) D CPU 3.20GHz
CPU Name Intel Pentium D 940
CPU Code Name Presler
Platform Name Socket 775 LGA
Revision B1
Technology 65 nm
Instructions MMX, SSE, SSE2, SSE3, ET64, VMX
Original Clock 3200 MHz
Original System Clock 200 MHz
Original Multiplier 16.0
CPU Clock 3201 MHz
System Clock 200.0 MHz
FSB 800.1 MHz
Core 0 Speed 3200.6 MHz
Core 0 Multiplier 16.0
Core 1 Speed 3200.6 MHz
Core 1 Multiplier 16.0
L1 Data Cache 2 x 16 KBytes
L1 Trace Cache 2 x 12 Kuops
L2 Cache 2 x 2048 Kbytes
Данные о видео:
Number of GPUs 2
Display Adapter NVIDIA GeForce 9400 GT
Video Processor GeForce 9400 GT
Video memory size 1024 MBytes
Adapter DAC Type Integrated RAMDAC
BIOS String Version 62.94.72.00.C1
BIOS Date 08/28/09
Display Drivers nv4_disp.dll
Driver Version 6.14.12.5721
Driver Date 2010-06-07 23:57:00
Inf File Name oem104.inf
Inf Section Section005
Display Adapter BB Capture Driver
Driver Version 1.00
Driver Date 2008-05-19 04:30:53
Inf File Name oem42.inf
Inf Section bbcap
В таблице приведены результаты.
Первый столбик: 0 без CUDA/1 с CUDA.
Второй столбик: количество полигонов.
Третий столбик: общее количество точек.
Четвертый столбик: затраченое время в тиках процессора.
Как видно из таблицы, при изменении количества точек в полигоне, среднее время, затраченное на одну точку остается постоянным (примерно 3100-3200 на точку), а с использованием CUDA при увеличении количества точек, имеется прирост производительности до 10 раз(около 400 на точку).
0 16 18512 59129664
0 16 18512 58459152
0 16 18512 58712096
0 16 18512 60967168
0 16 18512 57244720
1 16 18512 502950240 (первый длительный цикл с CUDA связан с инициализацией GPU)
1 16 18512 52466864
1 16 18512 53369744
1 16 18512 50947872
1 16 18512 49795088
0 16 69872 224359936
0 16 69872 216826112
0 16 69872 218405712
0 16 69872 228633536
0 16 69872 225921376
1 16 69872 510279616
1 16 69872 62507984
1 16 69872 59920208
1 16 69872 58379904
1 16 69872 72676896
0 16 270992 865252016
0 16 270992 871903296
0 16 270992 875956464
0 16 270992 866460912
0 16 270992 871480384
1 16 270992 546036912
1 16 270992 102836928
1 16 270992 95773008
1 16 270992 101953184
1 16 270992 96566416
Код Microsoft Visual C++ 2008:
__int64 t1,t2,t3;
t2=0;
t3=0;
for (int i=0; ipMesh.size(); i++){
Model->pMesh[i]->GetVertexBuffer(&mVB);
mVB->Lock( 0, 0, ( void** )&m, D3DLOCK_READONLY );
DWORD i2=Model->pMesh[i]->GetNumVertices();
for (DWORD i1=0; i1 { p[i1].x=m[i1].p.x; p[i1].y=m[i1].p.y; p[i1].z=m[i1].p.z; t3++; } t1=__rdtsc(); if (Model->CUDA==TRUE) { // cuda if (Cuda_PoligonInstr(i2, p, _matr1, _a, _d)==1) _Count.push_back(i); } else { for (int i1=0; i1 D3DXVECTOR3 _vecSource; D3DXVec3TransformCoord(&_vecSource,&m[i1].p,&Matr1); if (_vecSource.z > 0 ){ D3DXVECTOR2 _l=D3DXVECTOR2(_vecSource.x, _vecSource.y); float l=D3DXVec2Length(&_l); float l1=_a*_vecSource.z+_d; if (l _Count.push_back(i); i1=i2; } } } } t2+=__rdtsc()-t1; mVB->Unlock(); mVB->Release(); m=NULL; } delete(p); ////////////////////// std::ofstream out; out.open("prim.txt",std::ios.app); out out.close(); ////////////////////// Код CUDA: __global__ void PoligonInstrKernel(float3* point, float* matr, float a, float r, int* len) { unsigned int x1 = threadIdx.x+blockIdx.x*blockDim.x; float3 p; p.x = matr[0]*point[x1].x+matr[1]*point[x1].y+matr[2]*point[x1].z+matr[12]; p.y = matr[4]*point[x1].x+matr[5]*point[x1].y+matr[6]*point[x1].z+matr[13]; p.z = matr[8]*point[x1].x+matr[9]*point[x1].y+matr[10]*point[x1].z+matr[14]; point[x1]=p; if (point[x1].z>0) if (x1 { float l=sqrt(point[x1].x*point[x1].x+point[x1].y*point[x1].y); float l1=a*point[x1].z+r; if (l } } _declspec(dllexport) int Cuda_PoligonInstr(int len, float3* point, float* matr, float a, float r) { float3* point1 = new float3[len]; float3* devpoint; cutilSafeCall(cudaMalloc((void**)&devpoint, sizeof(float3) * len)); cutilSafeCall( cudaMemset(devpoint, 0, sizeof(float3) * len) ); cutilSafeCall(cudaMemcpy(devpoint, point, sizeof(float3) * len, cudaMemcpyHostToDevice)); float* devmatr; cutilSafeCall(cudaMalloc((void**)&devmatr, sizeof(float) * 16)); cutilSafeCall(cudaMemcpy(devmatr, matr, sizeof(float) * 16, cudaMemcpyHostToDevice)); int* l= new int[2]; l[0]=0; l[1]=len; int* devlen; cutilSafeCall(cudaMalloc((void**)&devlen, sizeof(int)*2)); cutilSafeCall(cudaMemcpy(devlen, l, sizeof(int)*2, cudaMemcpyHostToDevice)); dim3 gridSize = dim3(1, 1, 1); dim3 blockSize = dim3(len, 1, 1); PoligonInstrKernel(devpoint, devmatr, a, r, devlen); cudaEvent_t syncEvent; cudaEventCreate(&syncEvent); cudaEventRecord(syncEvent, 0); cudaEventSynchronize(syncEvent); cudaMemcpy(point1, devpoint, sizeof(float3) * len, cudaMemcpyDeviceToHost); cutilSafeCall(cudaMemcpy(l, devlen, sizeof(float)*2, cudaMemcpyDeviceToHost)); cudaFree(devpoint); cudaFree(devmatr); delete point1; int _a; if (l[0]>0) _a=1; else _a=0; delete l; return _a; }
G-код
- Информация о материале
- Автор: Administrator
- Просмотров: 45366
Материал из Википедии — свободной энциклопедии
G-код — условное именование языка программирования устройств с ЧПУ (Числовое программное управление). Был создан компанией Electronic Industries Alliance в начале 1960-х. Финальная доработка была одобрена в феврале 1980 года как стандарт RS274D. Комитет ИСО утвердил G-код, как стандарт ISO 6983-1:1982, Госкомитет по стандартам СССР — как ГОСТ 20999-83. В советской технической литературе G-код обозначается, как код ИСО 7-бит (ISO 7-bit).
Производители систем управления используют G-код в качестве базового подмножества языка программирования, расширяя его по своему усмотрению.
Содержание |
Структура программы
Программа, написанная с использованием G-кода, имеет жесткую структуру. Все команды управления объединяются в кадры — группы, состоящие из одной или более команд. Кадр завершается символом перевода строки (ПС/LF) и имеет номер, за исключением первого кадра программы и комментариев. Первый кадр содержит только один символ «%». Завершается программа командой M02 или M30. Комментарии к программе размещаются в круглых скобках, занимая отдельный кадр.
Порядок команд в кадре строго не оговаривается, но традиционно предполагается, что первыми указываются подготовительные команды, (например, выбор рабочей плоскости), затем команды перемещения, затем выбора режимов обработки и технологические команды.
Подпрограммы должны быть описаны после команды M02, но до M30. Начинается подпрограмма с кадра вида Lxx, где xx — номер подпрограммы, заканчивается командой M17.
Сводная таблица кодов
Основные (называемые в стандарте подготовительными) команды языка начинаются с буквы G:
- Перемещение рабочих органов оборудования с заданой скоростью (линейное и круговое)
- Выполнение типовых последовательностей (таких, как обработка отверстий и резьб)
- Управление параметрами инструмента, системами координат, и рабочих плоскостей
Коды | Описание |
---|---|
G00-G04 | Позиционирование инструмента |
G17-G19 | Переключение рабочих плоскостей (XY, XZ, YZ) |
G20-G21 | Не стандартизовано |
G40-G44 | Компенсация размера различных частей инструмента (длина, диаметр) |
G53-G59 | Переключение систем координат |
G80-G84 | Циклы сверления, нарезания резьбы |
G90-G92 | Переключение систем координат (абсолютная, относительная) |
Таблица основных команд
Код | Описание | Пример |
---|---|---|
G00 | Ускоренное перемещение инструмента (холостой ход) | G0 X0 Y0 Z100 |
G01 | Линейная интерполяция | G01 X0 Y0 Z100 F200 |
G02 | Круговая интерполяция по часовой стрелке | G02 X15 Y15 R5 F200 |
G03 | Круговая интерполяция против часовой стрелки | G03 X15 Y15 R5 F200 |
G04 | Задержка на E миллисекунд | G04 E500 |
G40 | Отмена компенсации размера инструмента | G1 G40 X0 Y0 F200 |
G41 | Компенсировать радиус инструмента слева от траектории | G41 X15 Y15 D1 F100 |
G42 | Компенсировать радиус инструмента справа от траектории | G42 X15 Y15 D1 F100 |
G43 | Компенсировать длину инструмента положительно | G43 X15 Y15 Z100 H1 S1000 M3 |
G44 | Компенсировать длину инструмента отрицательно | G44 X15 Y15 Z4 H1 S1000 M3 |
G53 | Отключить смещение начала системы координат станка | G53 G0 X0 Y0 Z0 |
G54-G59 | Переключиться на заданную оператором систему координат | G54 G0 X0 Y0 Z100 |
G80 | Отмена циклов сверления (G81-G84) | G80 |
G81 | Цикл сверления | G81 X0 Y0 Z-10 R3 F100 |
G82 | Цикл сверления с задержкой | G82 X0 Y0 Z-10 R3 P100 F100 |
G83 | Цикл сверления с отходом | G83 X0 Y0 Z-10 R3 Q8 F100 |
G84 | Цикл нарезания резьбы | G95 G84 X0 Y0 Z-10 R3 F1.411 |
G90 | Задание абсолютных координат опорных точек траектории | G90 G1 X0.5 Y0.5 F10 |
G91 | Задание координат относительно последней введённой опорной точки | G91 G1 X4 Y5 F100 |
G94 | F (подача) — в формате мм/мин. | G94 G80 Z100 |
G95 | F (подача) — в формате мм/об. | G95 G84 X0 Y0 Z-10 R3 F1.411 |
Таблица технологических кодов
Технологические команды языка начинаются с буквы М. Включают такие действия, как:
- Сменить инструмент
- Включить/выключить шпиндель
- Включить/выключить охлаждение
Код | Описание | Пример |
---|---|---|
M00 | Приостановить работу станка до нажатия кнопки «старт» на пульте управления, так называемый "технологический останов" | G0 X0 Y0 Z100 M0 |
M01 | Приостановить работу станка до нажатия кнопки «старт», если включён режим подтверждения останова | G0 X0 Y0 Z100 M1 |
M02 | Конец программы | M02 |
M03 | Начать вращение шпинделя по часовой стрелке | M3 S2000 |
M04 | Начать вращение шпинделя против часовой стрелки | M4 S2000 |
M05 | Остановить вращение шпинделя | M5 |
M06 | Сменить инструмент | M6 T15 |
M07 | Включить дополнительное охлаждение | M3 S2000 M7 |
M08 | Включить основное охлаждение | M3 S2000 M8 |
M09 | Выключить охлаждение | G0 X0 Y0 Z100 M5 M9 |
M17 | Конец подпрограммы | M17 |
M30 | Конец информации | M30 |
Параметры команд
Параметры команд задаются буквами латинского алфавита
Код | Описание | Пример |
---|---|---|
X | Координата точки траектории по оси X | G0 X100 Y0 Z0 |
Y | Координата точки траектории по оси Y | G0 X0 Y100 Z0 |
Z | Координата точки траектории по оси Z | G0 X0 Y0 Z100 |
E | Величина задержки в микросекундах | G04 E101 |
F | Скорость рабочей подачи | G1 G91 X10 F100 |
S | Скорость вращения шпинделя | S3000 M3 |
R | Параметр стандартного цикла или радиус дуги (расширение стандарта) | G81 R1 0 R2 -10 F50 или G1 G91 X12.5 R12.5 |
D | Параметр коррекции выбранного инструмента | M06 T1 D1 |
P | Число вызовов подпрограммы | L82 P10 |
I,J,K | Параметры дуги при круговой интерполяции | G03 X10 Y10 I0 J0 F10 |
L | Вызов подпрограммы с данной меткой | L12 |
Пример
Обработка буквы W (вписанной в прямоугольник 34х27 мм, см рис.) на условном вертикально-фрезерном станке с ЧПУ, фрезой диаметром 4 мм, в заготовке из органического стекла:
Кадр | Содержание | Комментарий |
---|---|---|
% | Начало программы | |
N1 | G90 G40 G17 | Система координат абсолютная, компенсация на инструмент выключена, плоскость интерполяции XOY |
N2 | G00 X2.54 Y26.15 | Переход в точку начала обработки |
N3 | S500 F0.5 M3 | Выбрать режимы резания и включить привод главного движения |
N4 | G01 Z-1.0 | Врезание в заготовку |
N5 | G01 X5.19 Y 2.0 | Первый штрих буквы W |
N6 | G01 X7.76 | Продолжение движения |
N7 | G01 X16.93 Y26.15 | Второй штрих буквы W |
N8 | G01 X18.06 | Продолжение движения |
N9 | G01 X25.4 Y2.0 | Третий штрих буквы W |
N10 | G01 X25.96 | Продолжение движения |
N11 | G01 X32.17 Y 26.15 | Четвертый штрих буквы W |
N12 | G00 Z12 | Отвод инструмента от заготовки |
N13 | M5 | Выключить привод главного движения |
N14 | M02 | Конец программы |
Дополнительная информация
Основы программирования OpenGL в Borland С++Builder и Delphi.
- Информация о материале
- Автор: Андрей
- Просмотров: 9713
Источник: http://www.compdoc.ru/prog/builder/opengl/
На кого рассчитана статья
Я рассчитываю на то, что вы знакомы с азами создания приложений в С++Builder или Delphi и совсем не знаете OpenGL.
Введение
OpenGL (Open Graphics Library) - популярная библиотека для работы с 3D графикой. Стандарт OpenGL появился в 1992 году благодаря компании Silicon Graphics и сейчас переживает годы своего самого бурного развития.
Чуть-чуть побольше узнать об OpenGL и о том, как с ним работать в VC, можно, почитав wat'а: http://www.gamedev.ru/coding/11203.shtml
Я хочу показать, как работать с этой библиотекой в таких популярных и, на мой взгляд, очень удобных средах разработки, как Delphi и С++Builder.
Эта - первая - статья посвящена в основном инициализации OpenGL.
Инициализация
Первым делом нужно подключить заголовочные файлы:
С++ |
#include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> |
Delphi |
uses OpenGL; |
Если вы используете Delphi, то всё необходимое для работы с OpenGL находится в модуле OpenGL.dcu. А если вы используете С++Builder, то подключать придётся несколько файлов:
- gl.h и glu.h содержат прототипы основных функций OpenGL определённых в opengl32.dll и glu32.dll.
- glaux.h содержит вспомогательные (auxiliary) функции (glaux.dll). В этой статье я не буду использовать glaux.h, т.к. его функции не доступны в Delphi, да и не люблю я эту библиотеку. Кроме того основные задачи glaux (как, в прочем, и аналогичной, но более качественной, библиотеки GLUT) - это создание окон, таймеров, обработка клавиатуры и мыши, всё это есть в ИСР (Интегральная Среда Разработки) Delphi или С++Builder.
После подключения заголовочных файлов нужно установить формат пикселей. Я для этой цели использую следующую функцию:
С++ |
BOOL bSetupPixelFormat(HDC hdc) { PIXELFORMATDESCRIPTOR pfd, *ppfd; int pixelformat; ppfd = &pfd; ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); ppfd->nVersion = 1; ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; ppfd->dwLayerMask = PFD_MAIN_PLANE; ppfd->iPixelType = PFD_TYPE_RGBA; ppfd->cColorBits = 16; ppfd->cDepthBits = 16; ppfd->cAccumBits = 0; ppfd->cStencilBits = 0; if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0) { MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; } if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE) { MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); return FALSE; } return TRUE; } |
Delphi |
function bSetupPixelFormat(DC:HDC):boolean; var pfd:PIXELFORMATDESCRIPTOR; ppfd:PPIXELFORMATDESCRIPTOR; pixelformat:integer; begin ppfd := @pfd; ppfd.nSize := sizeof(PIXELFORMATDESCRIPTOR); ppfd.nVersion := 1; ppfd.dwFlags := PFD_DRAW_TO_WINDOW xor PFD_SUPPORT_OPENGL xor PFD_DOUBLEBUFFER; ppfd.dwLayerMask := PFD_MAIN_PLANE; ppfd.iPixelType := PFD_TYPE_RGBA; ppfd.cColorBits := 16; ppfd.cDepthBits := 16; ppfd.cAccumBits := 0; ppfd.cStencilBits := 0; pixelformat := ChoosePixelFormat(dc, ppfd); if pixelformat=0 then begin MessageBox(0, 'ChoosePixelFormat failed', 'Error', MB_OK); bSetupPixelFormat:=FALSE; exit; end; if SetPixelFormat(dc, pixelformat, ppfd)=false then begin MessageBox(0, 'SetPixelFormat failed', 'Error', MB_OK); bSetupPixelFormat:=FALSE; exit; end; bSetupPixelFormat:=TRUE; end; |
Вряд ли вам придётся менять что-нибудь в этой функции, но кое-что о структуре PIXELFORMATDESCRIPTOR сказать надо.
cColorBits - глубина цвета
cDepthBits - размер буфера глубины (Z-Buffer)
cStencilBits - размер буфера трафарета (мы его пока не используем)
iPixelType - формат указания цвета. Может принимать значения PFD_TYPE_RGBA (цвет указывается четырьмя параметрами RGBA - красный, зленный, синий и альфа) и PFD_TYPE_COLORINDEX (цвет указывается индексом в палитре). Как вы видите, я использую RGBA, и вам придётся поступить также, т.к. если вы захотите использовать COLORINDEX, то вам придётся изменить мою функцию: добавить пару флагов и дать начальные значения ещё нескольким переменным.
Более подробную информацию смотрите в справочнике или в MSDN.
Функция ChoosePixelFormat подбирает формат пикселей, максимально удовлетворяющий нашим требованиям, и возвращает его дескриптор, а SetPixelFormat устанавливает его в контексте устройства (dc).
После того как в контексте устройства установлен формат пикселей, нужно создать контекст воспроизведения (Rendering Context) для этого в OpenGL определены следующие функции:
С++ |
HGLRC wglCreateContext(HDC hdc); BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc); |
Delphi |
function wglCreateContext(dc: HDC): HGLRC; function wglMakeCurrent(dc: HDC; glrc: HGLRC):Boolean; |
Наверное, объяснять их значение не стоит
Теперь перейдём к форме. В объявлении класса формы в области private добавьте следующее:
С++ |
HGLRC ghRC; HDC ghDC; void Draw(); |
Delphi |
ghRC:HGLRC; ghDC:HDC; procedure Draw; |
ghRC - указатель на контекст воспроизведения (Rendering Context)
ghDC - дескриптор устройства (для нас - просто указатель на окно)
Процедура Draw будет отвечать за рисование.
Далее заполняем FormCreate:
С++ |
void __fastcall TForm1::FormCreate(TObject *Sender) { ghDC = GetDC(Handle); if (!bSetupPixelFormat(ghDC)) Close(); ghRC = wglCreateContext(ghDC); wglMakeCurrent(ghDC, ghRC); glClearColor(0.0, 0.0, 0.0, 0.0); FormResize(Sender); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float p[4]={3,3,3,1}, d[3]={-1,-1,-3}; glLightfv(GL_LIGHT0,GL_POSITION,p); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,d); } |
Delphi |
procedure TForm1.FormCreate(Sender: TObject); var p: TGLArrayf4; d: TGLArrayf3; begin ghDC := GetDC(Handle); if bSetupPixelFormat(ghDC)=false then Close(); ghRC := wglCreateContext(ghDC); wglMakeCurrent(ghDC, ghRC); glClearColor(0.0, 0.0, 0.0, 0.0); FormResize(Sender); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); p[0]:=3; p[1]:=3; p[2]:=3; p[3]:=1; d[0]:=-1; d[1]:=-1; d[2]:=-3; glLightfv(GL_LIGHT0,GL_POSITION,@p); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,@d); end; |
Вы видите, что тут вызывается FromResize, который мы ещё не описали. Надо это исправить. Поместите туда следующий код:
С++, Delphi |
glViewport( 0, 0, Width, Height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(-5,5, -5,5, 2,12); gluLookAt(0,0,5, 0,0,0, 0,1,0); glMatrixMode( GL_MODELVIEW ); |
Теперь, наверное, надо кое-что объяснить.
glClearColor устанавливает цвет (в нашем случае чёрный), которым будет заполняться экран при очищении. У этой процедуры - 4 параметра, что соответствует RGBA. Вместо нее можно написать glClearIndex(0.0). Эта процедура устанавливает индекс цвета в палитре.
glViewport устанавливает область вывода - область, в которую OpenGL будет выводить изображение. В нашем случае - вся форма.
glMatrixMode устанавливает режим матрицы видового преобразования. Не забивайте ей себе голову, просто запомните, что, если вы меняете тип проецирования, положение или направление камеры, то параметр должен быть GL_PROJECTION. После того, как вы завершили свои изменения, вызовите эту процедуру с параметром GL_MODELVIEW.
glLoadIdentity заменяет текущую матрицу видового преобразования на единичную (матрицу идентичности), т.е. просто сбрасывает ваши изменения.
glOrtho устанавливает режим ортогонального (прямоугольного) проецирования. Это значит, что изображение будет рисоваться как в изометрии. 6 параметров типа GLdouble (или просто double): left, right, bottom, top, near, far определяют координаты соответственно левой, правой, нижней, верхней, ближней и дальней плоскостей отсечения, т.е. всё, что окажется за этими пределами, рисоваться не будет. На самом деле эта процедура просто устанавливает масштабы координатных осей. Для того чтобы установить перспективное проецирование, используются процедуры glFrustum и gluPerspective, но о них - потом.
gluLookAt устанавливает параметры камеры: первая тройка - её координаты, вторая - вектор направления, третья - направление оси Y.
В OpenGL всё включается и выключается (разрешается и запрещается) процедурами glEnable и glDisable. Таким образом, мы разрешили тест глубины (GL_DEPTH_TEST), чтобы изображение было объёмным, разрешили давать нашим объектам какой-то цвет (GL_COLOR_MATERIAL), разрешили освещение (GL_LIGHTING) и включили <лампочку №0> (GL_LIGHT0).
glLightfv устанавливает свойства <лампочек>: позицию и направление света.
После того, как вы завершили работу с OpenGL, нужно освободить занятые ресурсы: освободить контекст, вызвав wglMakeCurrent с параметром ноль для идентификатора контекста OpenGL и разрушить этот контекст функцией wglDeleteContext. Кроме того нужно удалить дескриптор ghDC. Так как обычно работу с OpenGL завершается при завершении работы приложения, то соответствующий код нужно поместить в FormClose:
С++ |
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if(ghRC) { wglMakeCurrent(ghDC,0); wglDeleteContext(ghRC); } if(ghDC) ReleaseDC(Handle, ghDC); } |
Delphi |
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if ghRC<>0 then begin wglMakeCurrent(ghDC,0); wglDeleteContext(ghRC); end; if ghDC<>0 then ReleaseDC(Handle, ghDC); end; |
А теперь, давайте уже что-нибудь нарисуем!
Пример
Давайте нарисуем сферу, а потом заставим её крутиться. Итак, всё, что нам понадобится - это форма и таймер.
Установите интервал таймера на 10 миллисекунд (нам этого будет вполне достаточно). Теперь скопируйте все представленные выше фрагменты кода в соответствующие места. В процедуре Timer1Timer напишите одну сточку: Draw(); (в Delphi без скобок).
Теперь нам осталось только что-нибудь нарисовать, т.е. отредактировать функцию Draw.
С++ |
void TForm1.Draw() { glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT); GLUquadricObj *quadObj; quadObj:=gluNewQuadric(); gluQuadricDrawStyle(quadObj, GLU_FILL); glColor3f(1,0,0); gluSphere(quadObj, 2,10,10); glRotatef(3, 0,1,0); gluDeleteQuadric(quadObj); SwapBuffers(ghDC); } |
Delphi |
procedure TForm1.Draw; var quadObj :GLUquadricObj; begin glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT); quadObj:=gluNewQuadric; gluQuadricDrawStyle(quadObj, GLU_FILL); glColor3f(1,0,0); gluSphere(quadObj, 2,10,10); glRotatef(3, 0,1,0); gluDeleteQuadric(quadObj); SwapBuffers(ghDC); end; |
Всё, можно нажимать F9!!!
А теперь кое-что поясню (в процедуре Draw не встретилось ни одной знакомой строчки).
glClear сбрасывает значения всего перечисленного в качестве параметров (в нашем случае очищает буфер цвета и буфер глубины). Этой процедуре передавать много всяких буферов для очистки, но лично я использую только 3: GL_DEPTH_BUFFER_BIT, GL_COLOR_BUFFER_BIT, иногда GL_STENCIL_BUFFER_BIT (буфер трафарета).
glColor устанавливает цвет фигуры. Существует следующий синтаксис как для glColor, так и для других функций OpenGL:
gl<name>[n][type]
Поясняю, каждая функция OpenGL начинается с префикса . Далее следует название функции. После названия - количество параметров (если функция определена для разного кол-ва параметров). И, наконец, переменными какого типа являются параметры:
- b - GLbyte байт
- s - GLshort короткое целое
- i - GLint целое
- f - GLfloat дробное
- d - GLdouble дробное с двойной точностью
- ub - GLubyte беззнаковый байт
- us - GLushort беззнаковое короткое целое
- ui - GLuint беззнаковое целое
- v - вектор - массив из n элементов указанного типа
Итак, glColor3f означает, что цвет задаётся тремя компонентами типа GLfloat.
Для рисования сферы мы используем механизм из glu32.dll. Создаём объект типа GLUquadricObj и инициализируем его функцией gluNewQuadric. Далее устанавливаем стиль фигуры функцией gluQuadricDrawStyle (quadObj, GLU_FILL). Стиль может быть GLU_FILL, GLU_LINE или GLU_POINT. Что каждый из них значит, проверьте сами.
gluSphere - делает из quadObj сферу. Три последних параметра - это радиус и количество разбиений поперёк и вдоль оси Z соответственно. Я взял маленькое число разбиений, чтобы было видно, что сфера крутится.
И не забудем освободить память, занимаемую под quadObj - gluDeleteQuadric(quadObj).
glRotatef - заставляет нашу сферу крутиться. О том, как это делается - в следующей статье.
И, наконец, SwapBuffers (ghDC) выводит всё на экран.
Архив с проектом примера на Delphi
Пока всё.
Луковкин Сергей,
Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.
Советую почитать:
- Тарасов И.А. <Основы программирования OpenGL: учебный курс>.
Скачать её можно здесь: http://itsoft.miem.edu.ru/ - Тихомиров Ю. <Программирование трёхмерной графики>.
Пишет мудрёно, но очень много полезной информации. Кстати, у него вышла вторая книга, может она ещё толковее и понятней? - wat OpenGL: Основы http://www.gamedev.ru/coding/11203.shtml Просто, доступно, но для другой ИСР.