пересечение объектов в OpenGL
//рисуночек для наглядности
[ATTACH]3845[/ATTACH]
один товарищ посоветовал мне искать в буфере трафаретов, но честно говоря я и его то не нашёл....знающие, подскажите пожалуйста что мне делать то!:)
Скачай спецификацую OpenGL.
Ищи GL_STENCIL_TEST, glStencilFunc(), glStencilOp().
Что касается обрезания цилиндром выступающих частей, то можно поступить следующим образом.
Запрещаешь обновление color-буфер.
Код:
glColorMask (false, false, false, false);
Чистишь stencil-буфер.
Код:
glClear (GL_STENCIL_BUFFER_BIT);
Включаешь stencil-тест.
Код:
glEnable (GL_STENCIL_TEST);
Включаешь режим рисования тыльных сторон полигонов и рисуешь "полупрозрачный" цилиндр записывая в stencil-буфер 1.
Код:
glEnable (GL_CULL_FACE);
glCullFace (GL_FACE);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
glCullFace (GL_FACE);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
Теперь в пикселах, где получается задняя стенка "полупрозрачного" цилиндра, в stencil-буфере будут значения, равные 1. Это нужно для отсекания частей, лежащих за задней стенкой "полупрозрачного" цилиндра.
Далее
Код:
glStencilFunc (GL_EQUAL, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
и рисуешь "кучу тонких цилиндров внутри него".
Теперь в тех точках, где "тонкие цилиндры" лежат напротив задней стенки "полупрозрачного" цилиндра значения в stencil буфере будут равны 2.
Далее чистишь Z-буфер и аналогично, рисуешь сначала лицевую сторону "полупрозначного" цилиндра, потом установив режим теста глубины в GL_GREATER
Код:
glClear (GL_DEPTH_BUFFER_BIT);
glDepthFunc (GL_GREATER);
glStencilFunc (GL_EQUAL, 2, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
glDepthFunc (GL_GREATER);
glStencilFunc (GL_EQUAL, 2, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
опять рисуешь "тонкие цилиндры" и получаешь в тех пикселах, где эти "тонкие цилиндры" лежат за передней стенкой и перед задней, т.е. внутри "полупрозрачного"
цилиндра значения в stencil-буфере будут равны 3.
Далее все совсем просто включаешь color-буфер. Чистишь Z-буфер. Возвращаешь тест глубины в GL_LESS. Запрещаешь CULL_FACE.
Код:
glStencilFunc (GL_EQUAL, 3, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
Рисуешь "тонкие цилиндры".
Запрещаешь обновление Z-буфера и рисуешь полупрозрачный цилиндр.
[COLOR="Red"]Важно[/COLOR], чтобы то, что мы обозначили как "полупрозрачный" цилиндр было выпуклым телом. Та воронкообразная конструкция должна быть декомпозирована в множество цилиндров и усеченных конусов. И для каждого из этих объектов должен быть применён описанный алгоритм. К цилиндрам, да и конусам тоже, на этапе формирования stencil-буфера можно прилепить торцевые крышки. Тогда вообще будет правильно.
Кстати, что это за изделие такое? Похоже на кумулятивную гранату... :)
а изделие это и не изделие вовсе, это пучёк электронов в пролётном канале и коллекторе клистрона(усилитель СВЧ-мощности)
Код:
procedure TForm1.FormPaint(Sender: TObject);
const pos:array [0..3] of double=(0.1,0.1,1,1);
FogColor:array [0..3] of double=(0.9,0.9,0.9,1);
var i,k,j,h:integer;
quad,quadDisc:GLUquadricObj;
begin
SetLength(k1,Form8.SG1.RowCount-1,1);
for j:=1 to Form8.SG1.RowCount-1 do
for h:=0 to 1 do
begin
k1[h,j]:=strtofloat(Form8.SG1.Cells[h,j]);
end;
if ProblemSolved then
begin
wglMakeCurrent (Form1.Canvas.Handle, hrc );
glViewport(0,0,Form1.ClientWidth,Form1.ClientHeight);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glClearColor ( 0 , 0 , 0,1);
glClear ( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glPushMatrix;
gluPerspective(20.0, ClientWidth/ClientHeight, Scale-1.1, Scale+1.1);
glTranslate (0,0,-Scale);
glTranslate(Dx,0,0);
glTranslate(0,Dy,0);
if Light then
begin
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_POSITION,@pos);
end;
if Fog Then
begin
glEnable(GL_FOG);
glFog(GL_FOG_MODE,GL_EXP2);
glFog(GL_FOG_DENSITY,0.7);
end;
glRotate(RotX,1,0,0);
glRotate (RotY,0,1,0);
glScale(1/10/Rkan,1/10/Rkan,1/(eZ[length-1]-eZ[0]));
glTranslate(0,0,-1);
glBegin(GL_LINES);
glColor3d(1,0,0);
glVertex3d(-2,0,0);
glVertex3d (2,0,0);
glVertex3d(0,-2,0);
glVertex3d (0,2,0);
glEnd;
glColor3d(0,1,1.2);
glEnable(GL_CULL_FACE);
quad:=gluNewQuadric;
quadDisc:=gluNewQuadric;
Zkan:=StrToFloat(form3.LabeledEdit13.Text);
glColorMask (false, false, false, false);
glClear (GL_STENCIL_BUFFER_BIT);
glEnable (GL_STENCIL_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
glStencilFunc (GL_EQUAL, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
//puchek
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glClear (GL_STENCIL_BUFFER_BIT);
glEnable (GL_STENCIL_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_FRONT);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
glClear (GL_DEPTH_BUFFER_BIT);
glDepthFunc (GL_GREATER);
glStencilFunc (GL_EQUAL, 2, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
//puchek
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glColorMask (true, true, true, true);
glClear (GL_STENCIL_BUFFER_BIT);
glDepthFunc (GL_LESS);
glDisable (GL_CULL_FACE);
glStencilFunc (GL_EQUAL, 3, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
//puchek
glColor3d(0,1,1.2);
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glDisable(GL_STENCIL_TEST);
//kanal
glColor4d(0.9,0.9,0.9,0.5);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quadDisc,0,Rkan,20,1);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
Zkan:=StrToFloat(form3.LabeledEdit13.Text);
gluCylinder(quad,Rkan,Rkan,Zkan,20,1);
glPushMatrix;
glTranslate(0,0,Zkan);
gluDisk(quadDisc,0,Rkan,20,1);
glPopMatrix;
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
gluDeleteQuadric(quad);
gluDeleteQuadric(quadDisc);
SwapBuffers(Form1.Canvas.Handle);
glPopMatrix;
wglMakeCurrent ( 0 , 0 );
end;
end;
const pos:array [0..3] of double=(0.1,0.1,1,1);
FogColor:array [0..3] of double=(0.9,0.9,0.9,1);
var i,k,j,h:integer;
quad,quadDisc:GLUquadricObj;
begin
SetLength(k1,Form8.SG1.RowCount-1,1);
for j:=1 to Form8.SG1.RowCount-1 do
for h:=0 to 1 do
begin
k1[h,j]:=strtofloat(Form8.SG1.Cells[h,j]);
end;
if ProblemSolved then
begin
wglMakeCurrent (Form1.Canvas.Handle, hrc );
glViewport(0,0,Form1.ClientWidth,Form1.ClientHeight);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glClearColor ( 0 , 0 , 0,1);
glClear ( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glPushMatrix;
gluPerspective(20.0, ClientWidth/ClientHeight, Scale-1.1, Scale+1.1);
glTranslate (0,0,-Scale);
glTranslate(Dx,0,0);
glTranslate(0,Dy,0);
if Light then
begin
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_POSITION,@pos);
end;
if Fog Then
begin
glEnable(GL_FOG);
glFog(GL_FOG_MODE,GL_EXP2);
glFog(GL_FOG_DENSITY,0.7);
end;
glRotate(RotX,1,0,0);
glRotate (RotY,0,1,0);
glScale(1/10/Rkan,1/10/Rkan,1/(eZ[length-1]-eZ[0]));
glTranslate(0,0,-1);
glBegin(GL_LINES);
glColor3d(1,0,0);
glVertex3d(-2,0,0);
glVertex3d (2,0,0);
glVertex3d(0,-2,0);
glVertex3d (0,2,0);
glEnd;
glColor3d(0,1,1.2);
glEnable(GL_CULL_FACE);
quad:=gluNewQuadric;
quadDisc:=gluNewQuadric;
Zkan:=StrToFloat(form3.LabeledEdit13.Text);
glColorMask (false, false, false, false);
glClear (GL_STENCIL_BUFFER_BIT);
glEnable (GL_STENCIL_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_BACK);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
glStencilFunc (GL_EQUAL, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
//puchek
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glClear (GL_STENCIL_BUFFER_BIT);
glEnable (GL_STENCIL_TEST);
glEnable (GL_CULL_FACE);
glCullFace (GL_FRONT);
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
glClear (GL_DEPTH_BUFFER_BIT);
glDepthFunc (GL_GREATER);
glStencilFunc (GL_EQUAL, 2, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
//puchek
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glColorMask (true, true, true, true);
glClear (GL_STENCIL_BUFFER_BIT);
glDepthFunc (GL_LESS);
glDisable (GL_CULL_FACE);
glStencilFunc (GL_EQUAL, 3, 3);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
//puchek
glColor3d(0,1,1.2);
for k:=0 to Floor((length-2)/100) do
begin
i:=100*k;
glPushMatrix;
glTranslate(0,0,(eZ-eZ[0]));
glPushMatrix;
glTranslate(eX,eY,0);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quaddisc,0,R[i+100],35,1);
gluQuadricOrientation(quad,GLU_INSIDE);
gluCylinder(quad,R,R,eZ[i+100]-eZ,50,10);
gluQuadricOrientation(quad,GLU_OUTSIDE);
glPushMatrix;
glTranslate(eX[i+10]-eX,eY[i+100]-eY,eZ[i+10]-eZ);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
gluDisk(quadDisc,0,R[i+100],35,1);
glPopMatrix;
glPopMatrix;
glPopMatrix;
end;
glDisable(GL_STENCIL_TEST);
//kanal
glColor4d(0.9,0.9,0.9,0.5);
gluQuadricOrientation(quadDisc,GLU_INSIDE);
gluDisk(quadDisc,0,Rkan,20,1);
gluQuadricOrientation(quadDisc,GLU_OUTSIDE);
Zkan:=StrToFloat(form3.LabeledEdit13.Text);
gluCylinder(quad,Rkan,Rkan,Zkan,20,1);
glPushMatrix;
glTranslate(0,0,Zkan);
gluDisk(quadDisc,0,Rkan,20,1);
glPopMatrix;
//kollektor
glColor4d(0.9,0.7,0.2,0.5);
glPushMatrix;
glTranslate(0,0,Zkan);
for j:=1 to Form8.SG1.RowCount-1 do
begin
glTranslate(0,0,k1[1,j]);
gluCylinder(quad,k1[0,j]/10,k1[0,j+1]/10,k1[1,j+1],50,1);
end;
glPopMatrix;
gluDeleteQuadric(quad);
gluDeleteQuadric(quadDisc);
SwapBuffers(Form1.Canvas.Handle);
glPopMatrix;
wglMakeCurrent ( 0 , 0 );
end;
end;
единственное "но", появилась какая то линия, видимо граница между "лицевой" и "тыльной" стороной, увидеть её можно на картинке
Я тут ещё рз критически глянул на алгоритм - никуда он не годится! То есть, если бы внутренние цилиндры были бы "нитяными", то есть линиями, тогда ещё он был бы пригоден, а в общем случае работать не будет. Эх, хорошо бы ещё пару Z-буферов. Извини, что ввёл в заблуждение.
много ведь всяких интересных вещей делали на opengl, неужели нельзя каким то образом организовать запрет рисования/отображения вне какой то области?
и как я понял нельзя, по крайней мере таким алгоритмом, не отображать часть цилиндра, но ведь есть же стандартная функция glScale которая обрезает объекты, выходящие за пределы области отображения, можно ли создать похожую вращающуюся область по нужным мне размерам?
Возможно, решение следует искать здесь
если запретить очистку Z-буфера вот здесь
[ATTACH]3910[/ATTACH]
(несложно найти это место в первом ответе loki231, если обратить внимание на 2е подчёркивание)
получается вот такая штука
[ATTACH]3911[/ATTACH]
правда, вот с такой вот неприятностью
[ATTACH]3912[/ATTACH]
т.е. не прорисовывается внутренняя сторона канала и рисуется коллектор такой же формы как и должен быть, если смотреть через него на пучёк(просто боюсь что если удастся реализовать предложенный алгоритм, отсекаемая часть пучка будет видна под определённым угом).а вообще суть этого сообщения в том что вроде цилиндры то отсекаются, вот только не те....может кто придумает как сделать правильно?
лирическое отступление
ребят, 482 просмотра и один только loki231 отвечает(за что ему огромное спасибо), неужели он один разбирается в этом вопросе? я ж не какой-нибудь халявщик который хочет чтобы за него сделали всё, просто я не программист в принципе:) я физик-электронщик, которому нужно визуализировать рассчитанные процессы. войдите в моё положение, весь семестр писал эту прогу, разобрался со всеми физическими и математическими процессами, а в этом месте полный провал...курсовой срывается из-за, казалось бы, мелочи(а именно так посчитают преподы, они у нас не шарят в программировании). у тех из вас, кто действительно разбирается в этом, решение проблемы займёт ну наверно полчаса. ну не может же такая задача не быть предусмотрена разработчиками того же OpenGL......
к сожалению слишком плохо знаю английский чтобы читать такие тексты, а машинный перевод разбирать приходится минуты 3 на предложение.....
и к вопросу о "нитяном пучке", я тут прикинул, мне ведь не нужно заполние всего объёма этими нитями, так же как и с цилиндрами нужен только контур. но вопрос вот в чём, как сделать заполнение этими нитями нужного объёма по радиусу? или, допустим, просчитать 15-20 огибающих и каким то образом сгладить получивщийся каркас? просто сейчас мои рассчёты возвращают радиус в конкретной окружности, её смещение от оси, ну и продольную координату этой окружности
http://pmg.org.ru/nehe/ogl01.htm
но так и не понял как именно там организуется "расслоение" и как мне применить это к своей проблеме