-
Давно и довольно успешно (начиная с Delphi7) работал фрагмент кода для вывода OpenGL графики на BitMap (этот фрагмент вызывается в ходе выполнения программы многократно, в цикле: из Bitmap строится AVI-файл-мультик):
procedure TFormOpenGL.RenderToBitmap(const ABitmap: TBitmap);
var FormatIndex: Integer; PFD: TPixelFormatDescriptor; lFDC: HDC;
begin
lFDC := ABitmap.Canvas.Handle;
FillChar(PFD, SizeOf(PFD), 0);
With PFD do begin
nSize := SizeOf(PFD); nVersion := 1;
dwFlags := pfd_Draw_to_Bitmap or pfd_Support_OpenGL;
iPixelType := pfd_Type_RGBA;
cColorBits := 24; cDepthBits := 32;
iLayerType := pfd_Main_Plane;
end;
FormatIndex := ChoosePixelFormat(lFDC, @PFD);
SetPixelFormat(lFDC, FormatIndex, @PFD);
FGLContext := wglCreateContext(lFDC);
wglMakeCurrent(lFDC, FGLContext);
MyPaint(True);
.............
end;
Недавно перешёл на Delphi XE2. При компиляции 32bit - по-прежнему всё ОК. А вот при создании приложения 64bit -при выводе на Bitmap иногда (!!), причём ни сразу вылезают ошибки с сообщением "External error 80000003". Вопросы: 1) Это моя ошибка, или ошибка нового компилятора? 2) Почему при замене строки lFDC := ABitmap.Canvas.Handle; на строку lFDC := ABitmap.Handle; пустой лист (и под Delphi7 тоже)? 3) Можно ли использовать при выводе на Bitmap флаг pfd_DoubleBuffer и затем делать как обычно SwapBuffers(...)? 4) Не ли примера вывода на Bitmap функциями OpenGL сохранения текстуры или чем то ещё более правильным и не таким глючным?
-
>Почему при замене строки\ Потому что контекст и битмап - совсем не одно и то же.
-
> Потому что контекст и битмап - совсем не одно и то же
И что вы хотели этим сказать? Я не понял...В коде выше должен получаться контекст для битмапа. Что не так? В большинстве примеров рендеринга в битмап пишут именно lFDC := ABitmap.Handle
-
HDC и HBITMAP - дескрипторы разных графических объектов Windows Дельфийский TBitmap - сложный объект, в котором есть и битмап, и свой ручной контекст.
-
Сформулирую вопрос по-другому. При компиляции под 32бита приложение всегда работает устойчиво, генерит неограниченное количество битмапов безо всяких ошибок. А при компиляции под 64бита оно тоже работает, но через 10-100генераций битмапов (в зависимости от их сложности - количества графических примитивов) вылезает пресловутая ошибка "External exception 80000003", причём после неё приложение полностью не закрыть [x]: останки его болтаются где-то в памяти, и жрут ресурсы (даже немного процессорного времени). Добивается только через TaskMngr. Доходило до того, что гас экран, и появлялось сообщение типа "Драйвер видео был повреждён и успешно восстановлен системой Windows" - работа продолжается. Вопрос 1: о чём это говорит? О том что неправильно работает менеджер памяти на 64бита - грузит что-то в память, отведённую под OpenGL? Может ли это быть следствие моей программной ошибки, или ошибки в самом дельфовом программном коде в принципе не должны приводить к подобному краху? Можно ли отловить подобные ошибки, скажем, Application.OnException (Try-Except-finally - не помогает)? Вопрос 2: можно ли рисовать ф-ми OpenGL не на капризном битмапе, а на невидимом окне, а потом импортировать его попиксельный образ в битмап, или - раз уж окно невидимо - на нём ничего не нарисуется?
-
можно рендерить в текстуру, потом её читать и переписывать в битмап. так даже быстрее должно быть.
-
> можно рендерить в текстуру, потом её читать и переписывать > в битмап. так даже быстрее должно быть.
Понимаю, что так. Но как рендерить в текстуру? И как её потом прочитать в битмап? Хорошо бы примерчик кода, если есть
-
Чтобы рендерить даже в текстуру, надо (ИМХО) всё равно иметь какой-то контекст, на котором будет рисовать ОГЛ. Как этот контекст для невидимого объекта типа текстуры задать - не понимаю....
-
я уже раз приводил здесь этот код контекст безусловно нужен, но на нём ничего рисоваться не будет. если у вас нет окна - создайте невидимое. вообще похоже есть варианты контекста без окна, но могут быть проблемы. unit FrameBufferUnit;
interface
uses
Windows, SysUtils, Graphics, GL, GLu, GLext;
type
TFrameBuffer = class
private
width : Integer;
height : Integer;
frameb : GLuint;
depthb : GLuint;
texture : GLuint;
ftex : boolean;
public
constructor Create(const nWidth,nHeight:Integer;ctexture:Integer = 0 );
destructor Destroy;override;
procedure BindFrameBuffer;
procedure UnbindFrameBuffer;
function GetBitmap:TBitmap;
procedure AttachTexture;
procedure DettachTexture;
end;
implementation
type
TRGBLine = array [0..1023] of TRGBTriple;
PRGBLine = ^TRGBLine;
procedure TFrameBuffer.AttachTexture;
begin
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,texture,0);
end;
procedure TFrameBuffer.BindFrameBuffer;
begin
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameb);
end;
constructor TFrameBuffer.Create(const nWidth, nHeight: Integer;ctexture:Integer);
var
res : Integer;
ww,hh : Integer;
begin
Width:=nWidth;
Height:=nHeight;
ww:=Width;
hh:=Height;
ftex:=ctexture<>0;
if ftex then
texture:=ctexture
else
glGenTextures(1,@texture);
glBindTexture(GL_TEXTURE_2D,texture);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_GENERATE_MIPMAP,0);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,ww,hh,0,GL_RGBA,GL_UNSIGNED_BYTE,nil);
glBindTexture(GL_Texture_2D,0);
glGenFramebuffersEXT(1,@frameb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,frameb);
glGenRenderbuffersEXT(1,@depthb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,depthb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,width,height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,texture,0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDE RBUFFER_EXT,depthb);
res:=glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if res<>GL_FRAMEBUFFER_COMPLETE_EXT then
raise Exception.Create('frame buffer error');
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
end;
destructor TFrameBuffer.Destroy;
begin
DettachTexture;
glDeleteFramebuffersEXT(1,@frameb);
glDeleteRenderbuffersEXT(1,@depthb);
if not ftex then
glDeleteTextures(1,@texture);
inherited;
end;
procedure TFrameBuffer.DettachTexture;
begin
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE _2D,0,0);
end;
function TFrameBuffer.GetBitmap: TBitmap;
var
buf : Pointer;
l : PRGBLine;
b : ^TRGBTriple;
i,j : Integer;
h,w : Integer;
function PtrAllign(APointer:Pointer; bytes: cardinal):Pointer;
begin
Result := Ptr(cardinal(APointer) + (bytes-cardinal(APointer) mod bytes) mod bytes);
end;
begin
w:=width;
h:=height;
result:=TBitmap.Create;
result.PixelFormat:=pf24bit;
result.Width:=w;
result.Height:=h;
GetMem(buf,w*h*3);
glBindTexture(GL_TEXTURE_2D,texture);
ZeroMemory(buf,w*h*3);
glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,buf);
glBindTexture(GL_TEXTURE_2D,0);
b:=buf;
for i:=h-1 downto 0 do
begin
l:=result.ScanLine[i];
for j:=0 to w-1 do
begin
l[j].rgbtBlue:=b.rgbtRed;
l[j].rgbtGreen:=b.rgbtGreen;
l[j].rgbtRed:=b.rgbtBlue;
Inc(b);
end;
b:=PtrAllign(b,4);
end;
FreeMemory(buf);
end;
procedure TFrameBuffer.UnbindFrameBuffer;
begin
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
end;
end.
-
> я уже раз приводил здесь этот код
Да, спасибо: я этот кусок кода уже поиском находил. Не смог применить: это ведь некий вспомогательный (универсальный) модуль создания текстуры, и потом копирования её в обычный битмап. Так? Но как вызывать процедуры этого модуля? Я спрашивал скорее про пример его применения - в виде кода полной тестовой программы, которая рисует на текстуре заданных размеров, скажем, сферу, а затем запихивает рисунок с текстуры в битмап.
-
Вначале подключаете GL_EXT_FrameBufferObject. Затем примерно так function TScene.DrawToBitmap(ww,hh:Integer): TBitmap;
var
w,h : Integer;
fb : TFrameBuffer;
begin
w:=Width;
h:=Height;
Width:=ww;
Height:=hh;
UseContext;
fb:=TFrameBuffer.Create(ww,hh);
fb.BindFrameBuffer;
Draw(False);
Result:=fb.GetBitmap;
fb.UnbindFrameBuffer;
fb.Free;
Width:=w;
Height:=h;
end;
-
Спасибо огромное! Буду пробовать. Я так понимаю, надо скачать библиотеки GL, GLu, GLext - в модуле OpenGL некоторых использованных процедур нет? Это не сложно. И....начинаю тупить: fb:=TFrameBuffer.Create(ww,hh); ...не маловато параметров? Там же ещё ...;ctexture: Integer); > Вначале подключаете GL_EXT_FrameBufferObject
этого вообще не понял: где это подключение?
-
...и ещё глупый вопрос в догонку: не нашёл, где вызывается proc.AttachTexture и что такое UseContext - библиотечная функция?
-
возможно поможет вот это: ABitmap.Canvas.Lock;
lFDC := ABitmap.Canvas.Handle;
...
wglMakeCurrent(lFDC, FGLContext);
...
wglMakeCurrent(0, 0);
ABitmap.Canvas.Unlock;
- либо ручками сделать "некапризный битмап" CreateCompatibleDC + CreateCompatibleBitmap/CreateDIBSection + SelectObject
-
я использовал библиотеку dot, её сейчас уже не найти. UseContext это просто wglMakeCurrent(DC, hrc);
ctexture по умолчанию равен 0 смотрите в интерфейсной части модуля.
AttachTexture наверное не пригодился. GL_EXT_FrameBufferObject обычно есть в модулях типа GLExt. В случае использования dot его подключение выглядело так Load_GL_EXT_framebuffer_object; В принципе могу dot выложить.
-
> - либо ручками сделать "некапризный битмап" > CreateCompatibleDC + CreateCompatibleBitmap/CreateDIBSection > + SelectObject
С Lock-UnLock не получилось: всё равно программа терпит крах (не с первого битмапа, а с 10-го - 100-го) с ошибкой "External Exception 8000003". Но! Теперь после краха её хоть можно закрыть нормально [x], а без Lock в памяти болтались её "останки", которые добивались только через TaskMngr. Уже неплохо! Вариант с DIB наверно, самый правильный и простой, но у меня с ним не вышло. Код использовал такой: ........................................
var DC: HDC; Binf: TBitMapInfo; Dib: HBitmap; Bits: Pointer;
begin
With Binf.bmiHeader do begin
biSize := SizeOf(TBitmapInfoHeader);
biWidth := ABitmap.Width; biHeight := ABitmap.Height;
biPlanes := 1; biBitCount := 24;
biCompression := bi_RGB;
biSizeImage := biWidth * biHeight * 3;
end;
DC := GetDC(ABitmap.Canvas.Handle);
Dib := CreateDIBSection(DC, Binf, DIB_RGB_Colors, Bits, 0, 0);
ReleaseDC(ABitmap.Canvas.Handle, DC);
lFDC := CreateCompatibleDC(0);
SelectObject(lFDC, Dib);
FillChar(PFD, SizeOf(PFD), 0);
With PFD do begin
nSize := SizeOf(PFD); nVersion := 1;
dwFlags := pfd_Draw_to_Bitmap or pfd_Generic_Accelerated or
pfd_Support_OpenGL;
iPixelType:= pfd_Type_RGBA;
cColorBits:= 24; cDepthBits:= 16;
iLayerType:= pfd_Main_Plane;
end;
FormatIndex := ChoosePixelFormat(lFDC, @PFD);
SetPixelFormat(lFDC, FormatIndex, @PFD);
FGLContext := wglCreateContext(lFDC);
wglMakeCurrent(lFDC, FGLContext);
TestPaint;
glFinish;
.................. Получаю в итоге белый пустой Битмап. Что не так в этом коде? Нет ли правильного примера с DIB?
-
может wglDeleteContext?
-
Вот такой код с DIB у меня заработал в маленькой тестовой программе:
procedure TFormMain.RenderDIB_BtnClick(Sender: TObject);
var hMemRC, hOldRC: HGLRC; FormatIndex, W1, H1: Integer;
pfd: TPixelFormatDescriptor; poBits: Pointer;
bmpAux, BBitmap: TBitmap; bmiAux: BitmapInfo;
hhDc, hDIB, hMemDC, hOldDc: HDC;
const BmpFileName = 'D:\FileOpenGL_DIB.bmp';
begin
W1 := SpinEditR2BWidth.Value; H1 := SpinEditR2BHeight.Value;
With bmiAux.bmiHeader do begin
biSize := SizeOf(BitmapInfoHeader);
biWidth := W1; biHeight := H1;
biPlanes := 1; biBitCount := 24;
biCompression := bi_RGB;
biSizeImage := 3 * W1 * H1;
end;
hhDC := GetDC(Panel1.Handle);
hDIB := CreateDIBSection(hhDc, bmiAux, DIB_RGB_Colors, poBits, 0, 0);
ReleaseDC(Panel1.Handle, hhDc);
hMemDC := CreateCompatibleDC(0);
If hMemDC = 0 then begin
DeleteObject(hMemDC); ShowMessage('DIB: Err1');
Exit
end;
SelectObject(hMemDC, hDIB);
FillChar(pfd, SizeOf(pfd), 0);
With pfd do begin
nSize := SizeOf(pfd); nVersion := 1;
dwFlags := pfd_Draw_To_Bitmap or pfd_Support_OpenGL
or pfd_Generic_Accelerated;
iPixelType := pfd_Type_RGBA;
cColorBits := bmiAux.bmiHeader.biBitCount;
cDepthBits := 32;
iLayerType := pfd_Main_Plane;
end;
FormatIndex := ChoosePixelFormat(hMemDC, @pfd);
If not SetPixelFormat(hMemDC, FormatIndex, @pfd) then begin
DeleteObject(hDIB); DeleteDC(hMemDC);
ShowMessage('DIB: Err2');
Exit
end;
hMemRC := wglCreateContext(hMemDC);
If hMemRC = 0 then begin
DeleteObject(hDIB); DeleteDC(hMemDC);
ShowMessage('DIB: Err3');
Exit
end;
hOldDc := wglGetCurrentDC; hOldRC := wglGetCurrentContext;
wglMakeCurrent(hMemDC, hMemRC);
TestPaint;
glFinish;
wglMakeCurrent(0, 0);
wglDeleteContext(hMemRC);
wglMakeCurrent(hOldDc, hOldRC);
bmpAux := TBitmap.Create;
bmpAux.Width := W1; bmpAux.Height := H1;
StretchDIBits(bmpAux.Canvas.Handle, 0, 0, W1, H1,
0, 0, W1, H1, poBits, bmiAux, DIB_RGB_Colors, SRCCopy);
DeleteFile(BmpFileName);
bmpAux.SaveToFile(BmpFileName);
DeleteObject(hDIB); DeleteDC(hMemDC);
BBitmap := TBitmap.Create;
With BBitmap do begin
PixelFormat := pf24bit;
Width := W1; Height := H1;
LoadFromFile(BmpFileName);
end;
With ImageGL.Canvas do StretchDraw(ClipRect, BBitmap);
BBitmap.Free;
ShowMessage('OK 2 !');
end; Завтра попробую подключить его - т.е. вариант с DIB - к "большой" программе.
-
> biSizeImage := biWidth * biHeight * 3;
cbPitch:= ((biWidth * biBitCount + 31) and not $1F) div 8;
biSizeImage := cbPitch * biHeight;
biClrUsed:= 0;
biClrImportant:= 0;
- а лучше не мелочиться и использовать глубину цвета 32-бита(в отличие от 24- bpp - поддерживаемую аппаратно)... - более предпочтителен Compatible Bitmap, но GetDIBBits - может затратным оказаться... (Вечная дилемма - с одной стороны рендеринг быстрее на видеопамяти, с другой - чтение видеопамяти - очень медленное(т.к. все оптимизировано только на вывод) ) DC := GetDC(ABitmap. Canvas.Handle); - вообще бред - у GetDC - на входе HWND, а не HDC(в отличие от CreateCompatibleDC) и даже не HBITMAP... CreateDBISection - прекрасно на hMemDC( := CreateCompatibleDC(0)) отрабатывает... Но если уж очень хочется - то GetDC( 0) (весь экран)... З.Ы. Если тебе лень напрямую данные(TBitmapFileHeader + bmiAux + poBits) в файл писать, то StretchDIBits - лучше заменить на BitBlt/StretchBlt, т.к. DC->DC - операции обычно быстрее...
-
Увы... В "большой" программе, где отрисовка на невидимый Bitmap или даже на DIB происходит в цикле многократно, рано или поздно ошибка External Exception 800003 всё равно выскакивает. Причём только при компиляции Delphi XE2 под 64бит. В то же время, на видимую форму точно такая же картинка выводится прекрасно хоть тысячу раз в процессе счёта. Видимо, это всё-таки баг нового 64-битного компилятора (или менеджера памяти?) - потому как при компиляции под 32бит всегда всё ОК. Нет ли примера, как выводить без флага Draw_To_Bitmap например, на панель на невидимой форме, а потом уже считывать биты цвета с этой панели (невидимой формы) в необходимый битмап? С текстурами уж больно мудрёно...
-
> AttachTexture наверное не пригодился. > GL_EXT_FrameBufferObject обычно есть в модулях типа GLExt. > В случае использования dot его подключение выглядело так > Load_GL_EXT_framebuffer_object; > В принципе могу dot выложить.
С рисованием на невидимой текстуре - а"ля подложке на невидимой форме для накапливания рисунка - разобрался: в тестовой программе под 32бита идёт нормально! Обошёлся без внешних библиотек (только дельфовая OpenGL - GLu, GLut, GLext не понадобились): все необходимые константы и gl-функции работы с текстурами подгружаю сам (код новой FrameBufferUnit выложу, когда доделаю). Вызывать AttachTexture всё-таки надо (!): сразу после создания FrameBuffer (иначе на выходе битмам - чёрный квадрат Малевича). Одно НО. Завершающая процедура копирования битов с текстуры в битмап написана неудачно: не учтено, что Delphi для 64бит запрещает записывать указатели в целые переменные, а там похоже это есть - чувствую, но найти не могу (в итоге под 64бит - AccessViolation): function TFrameBuffer.GetBitmap: TBitmap;
var buf: Pointer; l: PRGBLine; b: ^TRGBTriple; i,j, h,w: Integer;
function PtrAllign(APointer: Pointer; bytes: cardinal): Pointer;
begin
Result := Ptr(cardinal(APointer) +
(bytes - cardinal(APointer) mod bytes) mod bytes);
end;
begin
w := width; h := height;
result := TBitmap.Create;
result.PixelFormat := pf24bit;
result.Width := w; result.Height := h;
GetMem(buf, w*h*3);
glBindTexture(GL_TEXTURE_2D, texture);
ZeroMemory(buf, w*h*3);
glGetTexImage(GL_TEXTURE_2D,0, GL_RGB,GL_UNSIGNED_BYTE, buf);
glBindTexture(GL_TEXTURE_2D,0);
b := buf;
for i := h-1 downto 0 do begin
l := result.ScanLine[i];
for j:=0 to w-1 do begin
l[j].rgbtBlue := b.rgbtRed;
l[j].rgbtGreen := b.rgbtGreen;
l[j].rgbtRed := b.rgbtBlue;
Inc(b);
end;
b := PtrAllign(b,4);
end;
FreeMemory(buf);
end; Думаю, ошибка во встроенной ф-ии PtrAllign. Поможете найти?
-
-
> Замените Cardinal на NativeInt
Не помогает! Это первое, что я сделал. В этом коде вообще довольно вольно обходятся с указателями - я стараюсь избегать такого заумного и глючного кода. Нельзя ли как-то по-простому текстуру скопировать в битмап: осталось то только это для 64бит? Быстродействие для меня ни малейшей роли не играет: просто в двойном цикле. Как? Там же, насколько помню, и цвета и строки перевёрнуты как-то?
-
С этим уже тоже разобрался. Вот работающий код под 32 и 64 бита. function TFrameBuffer.GetBitmap: TBitmap;
var tbuf,buf,Pline: Pointer; i,h,w: Integer; waserror: boolean;
begin
waserror := TRUE; buf := nil;
Try
w := width; h := height;
Result := TBitmap.Create;
Result.PixelFormat := pf24bit;
Result.Width := width; Result.Height := height;
GetMem(buf, w*h*3);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, texture);
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, buf);
tbuf := buf;
For i := h-1 downto 0 do begin
Pline := Result.ScanLine[i];
Move(tbuf^, Pline^, w*3);
Inc(NativeInt(tbuf), w*3);
end;
waserror := FALSE;
finally
If waserror then FreeAndNil(Result);
FreeMemory(buf);
end;
end; Осталась одна (?) проблема. Рендеринг в текстуру работает у меня только на одном компе (карта NVIDIA GTS450). На пяти (!!) других не выходит подгрузить вспомогательные процедуры работы с текстурой и FrameBuffer. Пытаюсь подгружать функцией: function dglGetProcAddress(ProcName: PAnsiChar;
LibHandle: Pointer = nil): Pointer;
begin
If LibHandle = nil then LibHandle := GL_LibHandle;
Result := GetProcAddress(HMODULE(LibHandle), ProcName);
If result <> nil then exit;
If Addr(wglGetProcAddress) <> nil then
Result := wglGetProcAddress(ProcName);
If Result = nil then ShowMessage('No Proc.ADDRES ' + ProcName);
end; У меня задана LibHandle=nil (возможно, это не верно, но на одном компе всё-таки работает). Задаю, скажем, второй параметр ProcName='glGenTextures' ---> получаю фиг (точнее nil). Как правильно подгружать процедуры, связанные с видеокартой?
-
Похоже, понятно... Функции типа glFramebufferTexture2DEXT и др. для работы с FrameBufferObject (FBO) большинством современных видеокарт не поддерживаются. Мёртвые они... Скачал пример-EXE для работы с FBO - идёт опять же только на одном компе. Так что, рендеринг в текстуру - не выходит.
-
В догонку (общаюсь похоже сам с собой)... Вот теперь к своему изумлению выяснил следующее. Не всякая поверхность строится нормально - некоторые сразу дают ошибку External Exception 8000003. Итак, тестовая поверхность, заданная просто на сетке. Индекс i = 0.....1000 Индекс j = 0.....1200 Координата X = i*0.02 Координата Y = j*0.02 Т.е, просто декартова сетка (ради теста). Сама поверхность: Z = 0.2 + 0.2*sin((i+j) / 30) - слабо волнистая - строится нормально Z = 0.2 + 0.2*sin((i+j) / 5) - сильно волнистая - не строится вообще Нормали к поверхности задавать или нет - без разницы. Пробовал в каждой ячейке сетки строить пару треугольников (понятно как) - режим gl_Triangles Пробовал так же полосами - режим gl_Quad_strip. Тоже без разницы. Что это за бред такой? Не хватает какого-то буфера глубины? Или это глюк нового компилятора??
-
Они не мёртвые, скорее всего у вас драйвера от Микрософта - в них нет поддержки OpenGL.
-
> Они не мёртвые, скорее всего у вас драйвера от Микрософта > - в них нет поддержки OpenGL.
А вообще - это "продвинутая" технология - Frame Buffer Object, или она в дальнейшем сойдёт на нет и поддерживаться не будет, как считаете?
-
Вот что с текстурами на сег. день вышло: 1) Полностью рендеринг в них работает только на одном из 7 компов (не густо!) 2) На одних компах подгружаемые функции-расширения OpenGL не находятся функцией типа ....:=wglGetProcAddress('glFramebufferTexture2DEXT') - это стандартная функция поиска в библиотеках dll . Драйверы, скачанные с офиц. сайтов видеокарт, не всегда помогают... 3) На другом компе (ноутбук, карта NVIDIA 9600M GT) функции подгрузились успешно, но в самом начале инициализации работы с FrameBuffer стоят 2 строки: glGenRenderbuffersEXT(1, @depthb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthb); Затыкается уже на второй (первая проходит)... Ошибку не выдаёт, но функция проверки завершения: Res := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); не даёт желаемое Res = GL_FRAMEBUFFER_COMPLETE_EXT (только если вторую строку закомментировать - ОК, все операции инициализации буферов идут до конца) У меня задано: GL_RENDERBUFFER_EXT = $8D41;
......
type TglBindRenderbufferEXT = procedure(target: GLenum;
renderbuffer: GLuint); stdcall;;
...................
var glBindRenderbufferEXT: TglBindRenderbufferEXT;
-
У меня на всех компьютерах работает. Из последних карт: GT 9600M, GTX460, GTX550, всякие GTS 250 и так далее, из AMD Radeon 2600 XT
-
Может я как-то не так подгружаю библиотеки? Вот начало Вашей слегка переделанной Unit: unit FrameBufferUnit;
interface
uses Windows, SysUtils, Graphics, OpenGL, Dialogs;
type TFrameBuffer = class private width, height: Integer; frameb, depthb, texture: GLuint; ftex: boolean; public constructor Create(const nWidth, nHeight: Integer; ctexture: Integer = 0); destructor Destroy;override; procedure BindFrameBuffer; procedure UnbindFrameBuffer; function GetBitmap:TBitmap; procedure AttachTexture; procedure DettachTexture; end; {---------------------------------------------------------------------} procedure glGenTextures(n: GLsizei; textures: PGLuint); stdcall; external 'opengl32.dll'; procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external 'opengl32.dll'; procedure glDeleteTextures(n: GLsizei; const textures: PGLuint); stdcall; external 'opengl32.dll'; {---------------------------------------------------------------------} implementation { TFrameBuffer }
type TglFramebufferTexture2DEXT = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); stdcall; TglBindFramebufferEXT = procedure(target: GLenum; framebuffer: GLuint); stdcall; TglGenFramebuffersEXT = procedure(n: GLsizei; framebuffers: PGLuint); stdcall; TglGenRenderbuffersEXT = procedure(n: GLsizei; renderbuffers: PGLuint); stdcall; TglBindRenderbufferEXT = procedure(target: GLenum; renderbuffer: GLuint); stdcall; TglRenderbufferStorageEXT = procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei); stdcall; TglFramebufferRenderbufferEXT = procedure(target: GLenum; attachment: GLenum; renderbuffertarget: GLenum; renderbuffer: GLuint); stdcall; TglCheckFramebufferStatusEXT = function(target:GLenum):GLenum; stdcall; TglDeleteFramebuffersEXT = procedure(n: GLsizei; const framebuffers: PGLuint); stdcall; TglDeleteRenderbuffersEXT = procedure(n: GLsizei; const renderbuffers: PGLuint); stdcall;
var glFramebufferTexture2DEXT: TglFramebufferTexture2DEXT; glBindFramebufferEXT: TglBindFramebufferEXT; glGenFramebuffersEXT: TglGenFramebuffersEXT; glGenRenderbuffersEXT: TglGenRenderbuffersEXT; glBindRenderbufferEXT: TglBindRenderbufferEXT; glRenderbufferStorageEXT: TglRenderbufferStorageEXT; glFramebufferRenderbufferEXT: TglFramebufferRenderbufferEXT; glCheckFramebufferStatusEXT: TglCheckFramebufferStatusEXT; glDeleteFramebuffersEXT: TglDeleteFramebuffersEXT; glDeleteRenderbuffersEXT: TglDeleteRenderbuffersEXT;
const GL_FRAMEBUFFER_EXT = $8D40; GL_COLOR_ATTACHMENT0_EXT = $8CE0; GL_GENERATE_MIPMAP = $8191; GL_RGBA8 = $8058; GL_RGB8 = $8051; GL_RENDERBUFFER_EXT = $8D41; GL_DEPTH_ATTACHMENT_EXT = $8D00; GL_FRAMEBUFFER_COMPLETE_EXT = $8CD5; GL_BGR = $80E0; GL_STENCIL_ATTACHMENT_EXT = $8D20; GL_DEPTH_COMPONENT24 = $81A6;
var GL_LibHandle: Pointer = nil;
{=====================================================================} function dglGetProcAddress(ProcName: PAnsiChar; LibHandle: Pointer = nil): Pointer; begin If LibHandle = nil then LibHandle := GL_LibHandle; Result := GetProcAddress(HMODULE(LibHandle), ProcName); If result <> nil then exit; If Addr(wglGetProcAddress) <> nil then Result := wglGetProcAddress(ProcName); If Result = nil then ShowMessage('No Proc.ADDRES ' + ProcName); end;
{=====================================================================} procedure TFrameBuffer.AttachTexture; begin glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0); end;
{=====================================================================} procedure TFrameBuffer.BindFrameBuffer; begin glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameb); end;
{=====================================================================} constructor TFrameBuffer.Create(const nWidth, nHeight: Integer; ctexture: Integer); var Res: Integer; begin glFramebufferTexture2DEXT := dglGetProcAddress(PAnsiChar('glFramebufferTexture2DEXT')); glBindFramebufferEXT := dglGetProcAddress('glBindFramebufferEXT'); glGenFramebuffersEXT := dglGetProcAddress('glGenFramebuffersEXT'); glGenRenderbuffersEXT := dglGetProcAddress('glGenRenderbuffersEXT'); glBindRenderbufferEXT := dglGetProcAddress('glBindRenderbufferEXT'); glRenderbufferStorageEXT := dglGetProcAddress('glRenderbufferStorageEXT'); glFramebufferRenderbufferEXT := dglGetProcAddress('glFramebufferRenderbufferEXT'); glCheckFramebufferStatusEXT := dglGetProcAddress('glCheckFramebufferStatusEXT'); glDeleteFramebuffersEXT:= dglGetProcAddress('glDeleteFramebuffersEXT'); glDeleteRenderbuffersEXT := dglGetProcAddress('glDeleteRenderbuffersEXT'); {.....................................................................} Width := nWidth; Height:=nHeight; ftex := ctexture <> 0; If ftex then texture := ctexture else glGenTextures(1, @texture); glBindTexture(GL_TEXTURE_2D,texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP,0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); glBindTexture(GL_Texture_2D, 0); {.....................................................................} glGenRenderbuffersEXT(1, @depthb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthb); glGenFramebuffersEXT(1, @frameb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthb); {.....................................................................} Res := glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); If Res <> GL_FRAMEBUFFER_COMPLETE_EXT then raise Exception.Create('Frame Buffer error'); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); { Присоединяем текстуру } AttachTexture; end;
Спотыкается почти а всех компах именно на glBindRenderbufferEXT уже в Constructor, даже когда находит все необходимые функции-расширения (на карте 9600M GT)
-
контекст выбран?
-
> контекст выбран?
Конечно! Без его выбора программа тоже не найдёт функции-расширения OpenGL. Да и, как говорил, на одном компе всё идёт...
function TFormMain.GetScreenContext(const CanHandle: THandle): HGLRC;
var nPixelFormat: Integer; PFD: TPixelFormatDescriptor;
begin
FillChar(PFD, SizeOf(PFD), 0);
With PFD do begin
nSize := SizeOf(PFD); nVersion := 1;
dwFlags := pfd_Draw_to_Window or pfd_Generic_Accelerated or
pfd_Support_OpenGL or pfd_DoubleBuffer;
iPixelType := pfd_Type_RGBA;
cColorBits := 24; cDepthBits := 32;
iLayerType := pfd_Main_Plane;
end;
nPixelFormat := ChoosePixelFormat(CanHandle, @PFD);
SetPixelFormat(CanHandle, nPixelFormat, @PFD);
Result := wglCreateContext(CanHandle);
end;
function TFormMain.DrawToText(ww,hh: Integer): TBitmap;
var FrameBuffer: TFrameBuffer;
var MyDC: HDC; MainGLContext: HGLRC;
begin
Hide;
MyDC := GetDC(Panel1.Handle);
MainGLContext := GetScreenContext(MyDC);
wglMakeCurrent(MyDC, MainGLContext);
FrameBuffer := TFrameBuffer.Create(ww, hh);
FrameBuffer.BindFrameBuffer;
TestPaint; SwapBuffers(MyDC);
glFinish;
Result := FrameBuffer.GetBitmap;
FrameBuffer.UnbindFrameBuffer;
FrameBuffer.Free;
Sleep(300); Show;
end;
-
Дополнение к сообщению от 26.11.11 16:02 Говорил там о совершенно бредовой ошибке: успех вывода на битмап (и DIB тоже) зависит от того, насколько сложная поверхность рисуется. Ну не бред ли? Этот баг проявляется только при компиляции под 64бит. Всё-таки сделал отдельный тестовый проект и выложил на файлообменник. 1) http://exfile.ru/232178 - полная версия, где для картинки с синусами есть нормали, блеск, можно повращать и помасштабировать её обычными средствами (Ctrl-Shifr-Alt-mouse). Там в основной форме 2 кнопки. Первая просто рисует графику OpenGL на ещё одну форму. Вторая (справа) рисует, а потом рендерит в битмап (DIB) и сохраняет в файл. Успех работы второй зависит от значения DENOMINATOR, выбираемого на форме - это знаменатель в формуле с синусом, определяющей поверхность. Под 32бит идёт всё. Под 64бит идёт только при Denominator >100: когда "волны" синуса не сильно затеняют друг-друга. 2) http://exfile.ru/232180 - усечённая версия: кода меньше, с ней проще работать, анализировать - картинки не столь красивы, неподвижны, но баги те же (на любом компе). Привожу там полные тексты PAS и все EXE (64bit и 32bit). Всё делалось под Delphi XE2 Update2 (сборка 4316). Похоже, у Embarcadero возникла проблема с буфером глубины именно для DIB или Bitmap под 64бит.
-
Начал переписывать под xe2 64 bit. Сам пока заткнулся на d3d, но нашёл одну возможную проблему. Покажите ваш прототип wglGetProcAddress
-
> Покажите ваш прототип wglGetProcAddress
Не совсем понимаю, о чём речь? У меня с текстурами сейчас по-прежнему - на одном компе идёт выложенный выше код. На другом - никак не проходит пресловутая ф-я glGenRenderbuffersEXT(1, @depthb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthb); Причём все остальные функции - расширения OpenGL идут нормально... Не могли бы Вы выложить на какой-то файлообменник полностью код примера с FBO и необходимыми библиотеками? Кстати, вот здесь выложил совсем укороченный пример кода с OpenGL и Bitmap, который идёт под 32бита, но не идёт под 64 http://exfile.ru/232453 Там опять же - нажать правую кнопку - откроется окно с "синусоидой". При закрытии его - должен пойти рендеринг в битмап (DIB)... Но на 64битах он пойдёт только если периодов синусоиды немного: Denominator=100. При 20 - крах. Сам код там уже довольно простой, без арифметики: только OpenGL .
|