Programming and animation
Programming and animation ideas, articles, tutors, scripts, plugins in the 3d-
Online Car tuning demo.
Posted on 16 July 2009 Neill No commentsTech page is now moved here
All rights for the design and models belong to “DDD Interior”.
Programming 2009, ActiveX, Car, Online, OpenGL, tuning -
MoCap for entertainment
Posted on 6 June 2009 Neill No commentsI had an idea to experiment with MoCap equipment and make simple game for entertainment. Indeed, opportunities may be obtained from the same device as a Nintendo Wii console. I have built a game-like range of those that were at the Dendy console, coming complete with a pistol. The challenge to shoot a mouse in the monitor on a red square (the enemies) and do not shoot on the green (the hostages). For this game it was enough a three cameras and two rigid bodies(the gun and monitor).
Miscellaneous Games, MoCap, OpenGL, Optitrack -
MotionBuilder Multidisplay slug on NVidia cards
Posted on 3 May 2009 Neill 1 commentWith the advent of the new cards from NVidia (in this case the video cards 7x and above), any attempt to work in two screens in MotionBuilder ended terrible slugs. So finally I managed to find a way out of this situation – RivaTuner Softquadro. In other words, to work in a professional 3D graphics packages, you must either be owner of the line card Quadro, or to the existence of a professional card emulation, which in fact lead to a solution of the problem multidisplay draw.
MotionBuilder OpenGL, patch -
ActiveX умер? Браузерная OpenGL игра
Posted on 11 March 2009 Neill No commentsСам не так давно задавался вопросом, умерла ли технология ActiveX для браузеров. И был уверен что да, по сути технология живет уже очень давно и потеряла какой-либо интерес к себе, поддерживается только Internet Explorer’ом. Наверно так бы и думал дальше пока не узнал о появлении проекта Quake Live. К моему удивлению там онлайновый квейк в браузерном окне реализован именно посредством ActiveX и графической библиотеки OpenGL. Кажется ведь существует совместимость только с IE, это ведь будет отпугивать пользователей… но сам, пользуясь Opera и Google Chrome, включаю IE для того, чтобы поиграть в Quake Live, благо в Windows этот браузер всегда имеется в наличие.
Быть может этот проект от Id позволит большинству пользователей не так принципиально отстранено относится в модулям ActiveX и это станет снова вполне естественным и действующим путем для браузерных игр или приложений.Пример браузерного приложения с OpenGL и ActiveX можно найти здесь – http://www.sulaco.co.za
Graphics, Programming ActiveX, Browser, Games, Online, OpenGL -
OpenGL в среде Windows. Для начинающих
Posted on 11 March 2009 Neill 1 commentПредставляю вашему вниманию кое-что из раннего…
Создание Win32 приложения
Прежде чем создавать реалистичные трехмерные миры и различные красочные спецэффекты, давайте научимся создавать обычное виндовское окно. Впоследствии мы будем использовать его как канву для наших приложений.
1) Создание начального проекта
С помощью Visual Studio это сделать очень просто:
1. Выбирите в меню File(Файл) пункт New (новый).
2. Среди всего перечня возможных проектов нам потребутся Win32 приложение. В поле Project Name (название проекта) введите Skel (Skeleton – Скелет. Этим мы будем называть приложение на основе которого будем строить все остальные. Это костяк.) На рис.01 изображен диалог установок.

Рис.01 Создание Win32 приложения
Не забудьте указать в поле Location (местонахождение) расположение проекта. Лучше всего отведите для этого отдельную директорию.3. После нажатия кнопки Ок (применить) появиться диалоговое окно с выбором типа нашего проекта. Рис.02. Выбирите Simple Win32 application (простое Win32 приложение).

Рис.02 Выбор начального приложения
Простое приложение создаст нам главный файл, в котором мы и будем писать программы.Теперь щелкните Finish (завершить) и на этом работу с менеджером проектов можно считать завершенной.
2) создание главного окна
Если вы запустите сейчас откомпилируете наше приложение (с помощью команды Build – клавиша F7), а потом запустите его (с помощью команды Execute Program – клавиши Ctrl_F5), то ничего не произойдет. Это потому, что наше приложение сейчас пустое, но мы это быстро исправим.
Панелька, расположеная слева, содержит информацию о нашем проекте, об используемых в нем файлах. Перейдите ко кладке FileList (список файлов) и вы увидите дерево иерархий файлов нашего проекта. Найдите там файл Skel.cpp и откройте его. Рис.03. В этом файле находится функция WinMain, которая вызывается при запуске нашего приложения. Как видите она пуста (return 0 – выход из функции с возвращением 0), именно поэтому при запуске нашего приложения ничего не просходило. Теперь все, что мы напишем туда и будет выполняться, так что вперед. Наша задача построить обычное «виндовское» окно.Рис.03 Список фалов проекта и открытый главный файл – Skel.cpp
Для создания окна нам потребуется:
1. Добавим две литерные переменные – название класса нашего приложения и заголовок окна
Char *szClassName = “OpenGL Application”;
Char *szWndName = “OpenGL”;
2. Теперь нам нужно добавить еще одну переменную, характеризующую класс нашего окна.
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
Среди различных свойств, которые мы зададим этой переменной, мы должны указать и функцию, которую Windows будет использовать для отправки нам сообщений.
Wc.lpfnWndProc = (WNDPROC) MsgProc;
Т.е. технология работы нашего приложения будет следующая: создаем окно и указываем функцию обработки сообщений окна, а потом обрабатываем различные получаемые сообщения (сообщение на перерисовку, на нажатие клавиши и т.д.)
Когда же мы заполним все необходимые нам параметры нашего окна, то класс нашего окна нужно зарегистрировать с помощью функции
RegisterClass(&wc);
3. Всё, класс с таким именем зарегистрирован, теперь можно и создать наше долгожданное окошко с помощью функции
CreateWindow( <название класса>, <заголовок окна>,
<стиль>,, ,
<ширина>, <высота>,
<родитель>, <меню>,
<ссылка на окно>, <параметр> );Эта функция возвратит нам код окна. Он нам пригодится, так что сохраним его в отдельной переменной типа HWND
HWND hWnd;
…
hWnd = CreateWindow(szAppName, szAppName,
WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
CW_USEDEFAULT, CW_USEDEFAULT,
640, 480,
NULL, NULL,
hInstance,
NULL );4. Окно создали, осталось установить на него фокус
SetFocus (hWnd);
А затем показать его
Showindow (hWnd, True)
Здесь-то нам и пригодилась переменная кода нашего окна.
5. Теперь мы готовы принимать и обрабатывать Windows сообщения:
BOOL bGotMsg;
MSG msg;PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
while( WM_QUIT != msg.message )
{
bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );if( bGotMsg )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
InvalidateRect( hWnd, NULL, FALSE );
}
}return (INT)msg.wParam;
И последнее – добавим в нашу программу новую функцию
INT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam );
Переменная Msg будет означать тип сообщения из-за которого вызывается данная функция. Вообще возможных сообщений очень большой перечень, но нам в работе потребуется только самая малость.
WM_CREATE – создание
WM_DESTROY – уничтожение
WM_PAINT – перерисовка
WM_RESIZE – изменение размеров
Чтобы проверить действительность вызывания windows этих сообщений давайте сделаем так, чтобы при их вызове выдавалось сообщение
MessageBox( NULL, “WM_FormCreate”, “Message”, MB_OK);
Итак тело нашей функции должно выглядеть следующим образом:
…
switch( uMsg )
{
case WM_CREATE:
MessageBox( NULL, “WM_FormCreate”, “Message”, MB_OK);
return 0;case WM_CLOSE:
MessageBox( NULL, “WM_FormCreate”, “Message”, MB_OK);
DestroyWindow( hWnd );
PostQuitMessage(0);
return 0;
}return DefWindowProc( hWnd, uMsg, wParam, lParam );
…
Вот это я думаю все. Запустите приложение и перед вами должно появится обычное окно, причем это окно не должно иметь области рисования (как будто внутри пусто), т.к. мы её не задали и она нам и не понадобиться. В ex01 находится исходный вариант этой работы.Подключение OpenGL
1) Чтобы подключить функции библиотеки OpenGL в начале программы впишите использования заголовка с прототипами этих функций
#include
Теперь подключите саму библиотеку
#pragma comment (lib, “opengl32.lib”)2) OpenGL – библиотека рисования двухмерной и трехмерной графики, состоящая из большого количества команд. Естественно, что OpenGL’у требуется устройство, на которое будет производиться вывод. Это может быть и принтер, и рабочий стол, но мы будем использовать обычное виндовское окно (как его строить мы уже знаем). Итак, добавим новую переменную для хранения контекста устройства (в данном случае нашего окна)
HDC hDC;
Теперь занесем в неё контекст нашего окна (это лучше всего разместить после вызова функции по созданию окна)
HDC = GetDC(hWnd);
Двигаемся дальше. Очень важный момент – установка формата пикселей, т.е. мы должны установить связь между видеокартой и нашим устройством для вывода, а также задать параметрa работы OpenGL для данного устройства.
Добавим новую функцию
BOOL SetDCPixelFormat(HDC hDC);Разместим в ней новую переменную, в которой укажем необходимые для нашей работы параметры:
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // размер структуры
1, // версия
PFD_DRAW_TO_WINDOW | // рисование в окне
PFD_SUPPORT_OPENGL | // поддержка OpenGL
PFD_DOUBLEBUFFER, // режим двойной буферизации
PFD_TYPE_RGBA, // режим RGBA цвета
GetDeviceCaps(hDC, BITSPIXEL), // зададим размер буфера цвета
0,0,0,0,0,0, // не используем
0,0, // не используем
0,0,0,0,0, // не используем
16, // размер буфера глубины
0, // не используем
0, // не используем
PFD_MAIN_PLANE, // вывод на главную плоскость
0, // не используем
0,0,0
};Смысл в том, что мы зададим определенные параметры работы, чтобы настроить режим работы как нам хочется, а затем вызовем специальную функцию,
Int nPixelFormat = ChoosePixelFormat( hDC, &pfd);
которая попытается выбрать соответсвующий формат пикселей, согласуя с возможностями видео карты и учитывая наши пожелания.
Выбранный формат пикселей установим
SetPixelFormat(hDC, nPixelFormat, &pfd);! Используя следующий вызов
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
Мы получим в нашей переменной pfd флаги dwFlags, содержащие информацию о состоянии системы:
Если присутствует флаг PFD_NEED_PALETTE, то приложение запущено в режиме 256 цветов. В этом случае выдать сообщение о некорректном режиме и выйти из программы. (Какой смысл продолжать работу, если все будет не красиво)
Если присутствует флаг PFD_GENERIC_FORMAT, то приложение будет работать с поддержкой ускорителя, а иначе программная эмуляция.После того как мы задали формат пикселей, нам нужно создать контекст воспроизведения для работы с OpenGL. Подобно тому, что контекст устройства хранит настройки GDI, так и контекст воспроизведения хранит настройки OpenGL.
Добавим новую переменную, хранящую значение контекста воспроизведения
HGLRC hGLRC;
Теперь можно создать контекст. (функция wglCreateContext возвратит его значение)
hGLRC = wglCreateContext( hDC );
Когда мы активизируем контекст воспроизведения, то сможем использовать команды OpenGL для рисования.
wglMakeCurrent( hDC, hGLRC );
Т.е. схема нашего приложения будет следующая:Устройство
Монитор Видео карта
Контекст
воспроизведения приложениеЧто же касается рисования, то как вы помните при установке формата пикселей, мы указали режим двойной буферизации. Это значит, что рисовать будем на вне экранном буфере, а затем поменяем его с экранным и получим тем самым плавную перерисовку. Т.е добавим в нашу функцию обработки сообщений новое – WM_PAINT (сообщение на перерисовку). В начале рисования нем обязательное следует очистить буфер кадра, чтобы стереть все предыдущее нарисованное:
GlClear ( GL_COLOR_BUFFER_BIT );
Можете здесь же вставить команду OpenGL задающую цвет фона, которым заполняется буфер после очистки.
GlClearColor( 0.5f, 0.5f, 0.5f, 1.0f), где все 4 параметра – RGBA состовляющие цвета ( я для фона задал серый цвет)
Хотя вызов этой функции не обязателен при рисовании каждого кадра, поэтому поместите её где-нибудь после активации контекста воспроизведения.
В конце рисования – смена буферов
SwapBuffers( hDC );
3) При уничтожении приложения (сообщение WM_DESTROY или WM_CLOSE) нам нужно деактивировать контекст воспроизведения, удалить его и освободить контекст устройства:
wglMakeCurrent( 0, 0 );
wglDeleteContext( hGLRC ) ;
ReleaseDC(hWnd, hDC);
Если у вас появилось окно с серым фоном, то я вас поздравляю – вы построили простое OpenGL приложение. В ex.02 находится этот проект.Сбор информации о видео карте
OpenGL в основном рассчитан на использование акселератора (сейчас практически на всех компьютерах он имеется). Давайте научимся собирать информацию о видео карте и узнавать её возможности. Современные видео карты имеет довольно обширный перечень различных расширений, с которыми мы будем разбираться по ходу этой книги. Каждое расширение вносит дополнительную функциональность, поддерживаемую аппаратно, т.е. на использование своей видео карты. Ведь возможно у вас мощная видео карта, а вы даже не можете воспользоваться её возможностями.
После того как мы установили контекст воспроизведения, мы можем получить информацию с помощью функции glGetString(<параметр>), где в качестве параметра можно задать
Параметр Возвращаемая строка
GL_VENDOR Фирма-изготовитель видео карты
GL_RENDERER
Название видео-карты
GL_VERSION Версия
GL_EXTENSIONS Перечень расширений, поддерживаемых видео картойВот к примеру, поместим следующий код по выводу информации о видео карте после установки контекста воспроизведения:
Const Char Renderer = (const unsigned char*) glGetString(GL_RENDERER);
MessageBox( NULL, (char*) Renderer, “RENDERER”, MB_OK );
В ex.03 находится наш проект скелета OpenGL, только после создания окна появляются диалоги с информацией о видео карте.LOG – файлы
Очень удобно было бы выводить всю информации, а также различные замечания в отдельный файл, для того чтобы потом спокойно все просмотреть. Также часто возникает большая необходимость в слежке за данными, которые можно выводить также в этот файл для проведения отладки приложения.
Пусть этот файл будет log.txt, тогда нам потребуется 3 функции: для создания файла и подготовке к выводу в него; непосредственно для вывода; для закрытия файла при уничтожении окна.
1) Процедура подготовки LOG файла.
Добавьте новую переменную – FILE* logfile;
Она будет хранить контекст нашего файла. Теперь добавьте функцию
INT InitLOG()
{
//даже если этот файл уже присутсвует, то
//мы его сотрем
if((logfile=fopen(“Log.txt”, “wb”))==NULL)
return false;//закрываем файл – создание успешно завершено
fclose(logfile);
return true;
}
Мы открыли файл и отчистили его. Теперь будем только добавлять в него информацию.
2) Функция добавление в файл
printLOG(char* text, …)
{
va_list arg_list;//Initialize variable argument list
va_start(arg_list, text);//Open the log file for append
if((logfile = fopen(“Log.txt”, “a+”))==NULL)
return false;//Write the text and a newline
vfprintf(logfile, text, arg_list);
putc(‘\n’, logfile);//Close the file
fclose(logfile);
va_end(arg_list);return true;
}
Здесь мы открываем в наш файл в режиме добавления. Функция устроена так, что вы можете форматировать задаваемую строчку. Вот пример использования этой функции:
Output( “Renderer: %s”, glGetString(GL_RENDERER) );
Видите, функция вывода организована очень удобно.
3) Добавим процедуру, которую будем вызывать при уничтожении окна:
FreeLOG(void)
{
if(logfile)
fclose(logfile);return true;
}
Файл обязательно нужно закрывать, чтобы потом его можно было просматривать в других программах.
В ex.04 находится наш проект с использованием LOG файла.Подключение расширений
Как говорилось выше, каждое расширение вносит дополнительную функциональность в использовании нашей видео карты. Естественно, что каждое расширение вносит новые типы и новые функции. Чтобы узнать какие именно, нам нужно узнать их прототипы. Для этого подключим соответствующий модуль с описанием прототипов большинства из расширений.
#include
Новые функции загружаются с помощью вызова wglGetProcAddress(<имя функции>). Расширение может добавлять одну функцию, множество, а может и вообще не добавлять ни одной.Вертикальная синхронизация
В качестве примера на использование расширений возьму расширение по настройке вертикальной синхронизации – WGL_EXT_SWAP_CONTROL. Смысл в том, что смена буферов синхронизируется с видео кадровым периодом, т.е. со временем, требуемым монитору для вывода полного кадра видео данных. Если нам нужно посчитать максимальное количество FPS (кадров в секунду), то вертикальную синхронизацию нужно убрать. Кстати, это можно сделать в большинстве случаев из настроек драйверов.
Если посмотреть в модуль описания прототипов этого расширения, то там можно найти следующее
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
Отсюда видно, что нам предоставляют прототипы для двух функций:
1) Вводим PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalExt;
Теперь загружаем нашу функцию
wglSwapIntervalExt = (WINAPI * PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress(‘wglSwapIntervalEXT’);
Вызываем функция wglSwapIntervalExt(int interval), где переменной interval мы задаём значение
0 – вертикальная синхронизация выключена
1 – вертикальная синхронизация включена
2) Функция wglGetSwapInterwalExt, которая возвратит текущее значение интервала, загружаем аналогично с предыдущей.
В ex.05 содержится проект реализующий использование этого расширения. В нем на экране крутится коробка. Пока мы не будем вдаваться во все тонкости рисования, поэтому я подключил вспомогательную библиотеку
#include
И с помощью вызова функции DrawRotateBox() стал рисовать вращающийся кубик. Причем эту функцию нужно поместить в нашу процедуру Render, предназначенную для рисования.Однако можно сделать нашу работу по загрузке расширений ещё проще. Для этого можно воспользоваться, например, библиотекой GLEW. Её можно скачать в сети интернет, она свободно распространяемая. Удобно в том смысле, что в ней все функции уже описаны и нам не нужно их загружать, библиотека сделает эту работу за нас. Давайте выключим вертикальную синхронизацию, как в предыдущим примере, только теперь с использованием GLEW.
Полноэкранные/ экранные режимы
Очень часто нам потребуется не просто оконное приложение, а развертывание окна на весь экран с возможной смены разрешения экрана (как делается во всех играх). Так что давайте научимся менять разрешение экрана, а также переходить из экранного режима в полноэкранный и наоборот.
1) При создании приложения мы должны все возможные режимы занести в отдельный массив, чтобы потом знать, какие режимы поддерживает монитор. Введите новые переменные:
Int nummodes; // количество поддерживаемых режимов
DEVMODE devmodes; // массив характеристик каждого из них
Введем функцию по перечислению возможных режимов
Void EnumDisplayModes()
{
DEVMODE devmode;// подсчитаем количество режимов
// чтобы знать, сколько места отделять под массив
Nummodes=0;
While( EnumDisplaySettings(NULL, nummodes, &devmode))
Nummodes++;Devmodes = new DEVMODE[nummodes];
// заносим в наш массив характеристики каждого
// режима
Nummodes=0;
While( EnumDisplaySettings(NULL, nummodes, &devmodes[nummodes]))
Nummodes++;
}
Теперь добавим функцию перехода окна в экранный режим
Void SetWindow()
{
// меняем разрешение
ChangeDisplaySettings(NULL, 0);// выставляем положение и размеры нашего окна
Graphics, Programming OpenGL, Win32
Rect wrect;
} -
TGA. image file format
Posted on 12 February 2009 Neill No commentsФормат хранения растровых изображений. Представлен в нескольких вариантах, среди которых самый простой – хранения битовой маски без сжатия, и чуть более сложных – использование алгоритма сжатия LZW.
Самый простой вариант TGA
Данный вариант формата бывает очень уместен, когда требуется сохранить, например, скриншот экрана. Нам достаточно в этом случае считать с нарисованного очередного кадра битовый массив определенного размера и его же сохранить в файл, при этом только составив заголовок TGA в начало файла для возможности дальнейшего чтения в любом подручном растровом редакторе. Согласитесь, что такой подход манит своей простотой.
Далее код будет представлен на Delphi (Object Pascal).
TGA без сжатия
Заголовок следующий
TTGAHEADER = packed record
tfType : Byte;
tfColorMapType : Byte;
tfImageType : Byte;
tfColorMapSpec : Array[0..4] of Byte;
tfOrigX : Array [0..1] of Byte;
tfOrigY : Array [0..1] of Byte;
tfWidth : Array [0..1] of Byte;
tfHeight : Array [0..1] of Byte;
tfBpp : Byte;
tfImageDes : Byte;
end;
Запись содержимого tga файла следующая:
1. обнуляем все параметры заголовка (первоначально)
ZeroMemory(@tgaHeader, SizeOf(tgaHeader));
2. заполняем по нашему усмотрению некоторые поля в информацией о растре
// Fill the structure with info for the image to be saved
tgaHeader.tfImageType := TGA_RGB;
tgaHeader.tfWidth[0] := Width mod 256;
tgaHeader.tfWidth[1] := Width div 256;
tgaHeader.tfHeight[0] := Height mod 256;
tgaHeader.tfHeight[1] := Height div 256;
tgaHeader.tfBpp := 32;
где TGA_RGB равно 2.
3. записываем заголовок
// Write the header to disk
bytesWritten := fileStream.Write( tgaHeader, sizeof(tgaHeader) );
if bytesWritten <> SizeOf(tgaHeader) then begin
Result := False;
Exit;
end;
4. меняем местами два цветовых канала (красный и синий)
// Switch the red and blue channels (from RGB to BGR)
SwapRB();
5. рассчитываем длину битового массива (включая альфа канал)
// Calculate number of bytes in image
length := Width*Height*4;
6. записываем битовый массив после заголовка
// Save the image contents to file
bytesWritten := fileStream.Write( rgbBits^, length );
if bytesWritten <> length then begin
Result := False;
Exit;
end;
Такова последовательность записи самого простого случая для tga формата.
Берем скриншот
Теперь пару слов о скриншотах ОГЛ экрана.
1. Получаем массив с текущими параметрами видового окна
glGetIntegerv(GL_VIEWPORT, @viewport);
2. устанавливаем информацию для растрового изображения
Width := viewport[2];
Height := viewport[3];
ColorDepth := 32;
3. Выделяем память под битовый массив в соответствии с размером окна (включая альфа канал)
GetMem(rgbBits, Width*Height*4);
4. Требуем завершить все команды рисования ОГЛ
glFinish();
5. устанавливаем режим выравнивания пикселей
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
6. читаем содержимое буфера кадра в битовый массив (включая альфа канал)
glReadPixels(0, 16, viewport[2], viewport[3], GL_RGBA, GL_UNSIGNED_BYTE, rgbBits);
7. теперь остается только прочитанное сохранить на диск в определенный растровый формат файла.
Programming Delphi, OpenGL, TGA -
GLSL error C7549
Posted on 17 January 2009 Neill 2 commentsCompiling of my old glsl fragment shader was fall down with warning C7549: OpenGL does not allow C style initializers and warning
In fragment shader I have float array
1float weights[] = float[](1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
171.0000,
0.9394,
0.7788,
0.5697,
0.3678,
0.2096,
0.1053,
0.0467,
0.01831);To make it work properly, I add #version 120 command to my fragment shader, and rewrite array like this:
1float weights[] = float[](1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
171.0000,
0.9394,
0.7788,
0.5697,
0.3678,
0.2096,
0.1053,
0.0467,
0.0183Graphics GLSL, OpenGL1);






English
Russian
Recent Comments