求助:反馈的图元顶点值怎样从窗口坐标系变换到世界坐标系下?用gluUnProject就能转换吗?(50分)

  • 主题发起人 主题发起人 xu_orient
  • 开始时间 开始时间
X

xu_orient

Unregistered / Unconfirmed
GUEST, unregistred user!
{该代码希望通过点击鼠标来拾取组成三维图形的图元,并反馈出多边形图元的顶点在世界坐标系下的坐标。
OPenGL提供的函数可以直接反馈出被拾取图元的顶点在窗口坐标系下的坐标,而将反馈回来的窗口坐标值经过
gluUnProject过程转换,不知为什么得出的却不是世界坐标系下的坐标值。
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,ExtCtrls,Menus,GL,GLU,cgLight,cgWindow,Glut,cgTypes,math,
StdCtrls;

type
T3Darray=array[0..2]of single;
TForm1 = class(TCGForm)
Memo1: TMemo;
procedure FormPaint(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
procedure DrawCube(mode : GLenum);
end;


var
Form1: TForm1;
ax:integer=0; //绕X轴旋转变量
ay:integer=0; //绕y轴旋转变量
m:Tpoint; //鼠标位置
Pub_Light : TCGLight;
PubLight_Position : TcgVector;
PubLight_Ambient : TcgColorf;
PubLight_Diffuse : TcgColorf;
PubLight_Specular : TcgColorf;

PubLight_Shininess :single;




const
mat_specular_const:array[0..3] of single=(1.0,1.0,1.0,0);

UnitCube : ARRAY[0..7] OF T3DArray =
((0,0,1), // left lower front
(0,1,1), // left upper front
(1,1,1), // right lower front
(1,0,1), // left upper front
(0,0,0), // left lower back
(0,1,0), // left upper back
(1,1,0), // right upper back
(1,0,0)); // right lower back




function normal(A1,B1,C1:T3DArray):T3DArray;

implementation

{$R *.DFM}




//画一个单位立方体
procedure TForm1.DrawCube(mode: GLenum);
var
C:T3dArray;
N,I, J, K, L : GLInt;
outnormal:T3darray;
begin
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_MAP2_TEXTURE_COORD_2);


glPushMatrix;
glRotatef(270.0, 1.0, 0.0, 0.0);
glTranslatef(0.0, 0.0, -1.5);


// draw the six faces of the cube with triangles
// front
glColor3f(0,0,1);
if Mode=GL_FEEDBACK then glPassThrough(1);
glBegin(GL_TRIANGLE_STRIP);
C:=normal(UnitCube[3],UnitCube[2],UnitCube[0]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[0]);
glVertex3fv(@UnitCube[3]);
glVertex3fv(@UnitCube[1]);
glVertex3fv(@UnitCube[2]);
glEnd;

// bottom
if Mode=GL_FEEDBACK then glPassThrough(2);
glBegin(GL_TRIANGLE_STRIP);
C:=normal(UnitCube[3],UnitCube[4],UnitCube[0]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[0]);
glVertex3fv(@UnitCube[4]);
glVertex3fv(@UnitCube[3]);
glVertex3fv(@UnitCube[7]);
glEnd;

// back
if Mode=GL_FEEDBACK then glPassThrough(3);
glBegin(GL_TRIANGLE_STRIP);
C:=normal(UnitCube[7],UnitCube[4],UnitCube[5]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[4]);
glVertex3fv(@UnitCube[5]);
glVertex3fv(@UnitCube[7]);
glVertex3fv(@UnitCube[6]);
glEnd;

// top
if Mode=GL_FEEDBACK then glPassThrough(4);
glBegin(GL_TRIANGLE_STRIP);
C:=normal(UnitCube[1],UnitCube[2],UnitCube[5]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[1]);
glVertex3fv(@UnitCube[2]);
glVertex3fv(@UnitCube[5]);
glVertex3fv(@UnitCube[6]);
glEnd;

//left
if Mode=GL_FEEDBACK then glPassThrough(5);
glBegin(GL_TRIANGLE_STRIP);
glNormal3f(-1,0,0);
C:=normal(UnitCube[0],UnitCube[1],UnitCube[4]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[0]);
glVertex3fv(@UnitCube[1]);
glVertex3fv(@UnitCube[4]);
glVertex3fv(@UnitCube[5]);
glEnd;

// right
if Mode=GL_FEEDBACK then glPassThrough(6);
glBegin(GL_TRIANGLE_STRIP);
C:=normal(UnitCube[7],UnitCube[3],UnitCube[6]);
glNormal3fV(@C);
glVertex3fv(@UnitCube[2]);
glVertex3fv(@UnitCube[3]);
glVertex3fv(@UnitCube[6]);
glVertex3fv(@UnitCube[7]);
glEnd;
glPopMatrix;
end;

procedure TForm1.FormPaint(Sender: TObject);
var
token:single;
Vcount:Glint;
FeedbackBuf:Array [0..1023] of GLfloat;
hits:GLint;
i,j,k,n,names:GLint;
ViewPort:TviewportArray;
mview,proj:T16DArray;
px,py,pz:GLdouble;
vert:string;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glClearcolor(0.6,0.6,0.6,0);

glLoadIdentity;
glRotatef(ax,1,0,0);
glRotatef(ay,0,1,0);
glScalef(0.5,0.5,0.5);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); //深度测试
glColor3f(1.0,1.0,0.0);
DrawCube(GL_RENDER);

with Pub_Light do
begin
Position := PubLight_Position;
Infinite := False;
Ambient := PubLight_Ambient;
Diffuse := PubLight_Diffuse;
Specular := PubLight_Specular;
Enable;
end;

glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
//材料镜面反射系数
glMaterialf(GL_FRONT,GL_SHININESS,PubLight_Shininess);

glBlendFunc(GL_ONE, GL_ZERO); //恢复省却融合
glDepthFunc(GL_LESS); //恢复深度测试

glfinish;
pageflip;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
Pub_Light.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
InitGL;
//定义材质和光照
Pub_Light := TCGLight.Create(GL_LIGHT0);
Pub_Light.Infinite := False;
PubLight_Position := cgVector(-3.0,-4.0,7.0);
PubLight_Ambient := cgColorf(0.5,0.5,0.5,1);
PubLight_Diffuse := cgColorf(0.8,0.8,0.8,1);
PubLight_Specular := cgColorf(0.2,0.2,0.2,1);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glMaterialfv(GL_FRONT,GL_SPECULAR,@mat_specular_Const);
glEnable(GL_AUTO_NORMAL);
GetCursorPos(m);
m:=ScreenToClient(m);
Memo1.Lines.Add('若反馈的只有通过值,没有图元的顶点值,请先拖动鼠标右键,再点击鼠标左键,就会拾取到至少一个图元');
end;

//鼠标右键按下时图形发生变化
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssright in Shift then
begin
ay:=ay+(X-m.X);
ax:=ax+(Y-m.Y);
end;
m:=Point(X,Y);
Paint;
end;

//计算法向量
function normal(A1,B1,C1:T3DArray):T3DArray;
var
length:GLfloat;
a,b,c:T3DArray;
begin
a[0]:=A1[0]-B1[0];
a[1]:=A1[1]-B1[1];
a[2]:=A1[2]-B1[2];
b[0]:=C1[0]-B1[0];
b[1]:=C1[1]-B1[1];
b[2]:=C1[2]-B1[2];

C[0]:=a[1]*b[2]-a[2]*b[1];
C[1]:=a[2]*b[0]-a[0]*b[2];
C[2]:=a[0]*b[1]-a[1]*b[0];
length:=sqrt(c[0]*c[0]+c[1]*c[1]+c[2]*c[2]);
if (length>0.000001) then
begin
C[0]:=c[0]/length;
C[1]:=c[1]/length;
C[2]:=c[2]/length;
end;
result:=C;
end;

//左键实现拾取和反馈的功能
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
token:single;
Vcount:Glint;
FeedbackBuf:Array [0..1023] of GLfloat;
hits:GLint;
i,j,k,n:GLint;
ViewPort:TviewportArray;
mview,proj:T16DArray;
px,py,pz:GLfloat;
vert:string;
begin
if Button=mbLeft then
begin
memo1.Clear;
Memo1.Lines.Add('若反馈的只有通过值,没有图元的顶点值,请先拖动鼠标右键,再点击鼠标左键,就会拾取到至少一个图元');
glGetDoublev(GL_MODELVIEW_MATRIX,@mview);
glGetdoublev(GL_PROJECTION_MATRIX,@proj);
glGetIntegerv(GL_VIEWPORT,@viewport);

glFeedbackBuffer(1024,GL_3D,@FeedbackBuf);
glRenderMode(GL_FEEDBACK);
//glInitNames;
//glpushName(0);

//glMatrixMode(GL_PROJECTION);
//glLoadIdentity;
//拾取图元
glPushMatrix;
gluPickMatrix(X,Viewport[3]-Y,1,1,Viewport);
DrawCube(GL_FEEDBACK);
glPopMatrix;
glFinish;
hits:=glRenderMode(GL_RENDER);

i:=hits;
n:=hits;
while i<>0 do
begin
token:=FeedbackBuf[n-i];
DEC(i);
if token=GL_PASS_THROUGH_TOKEN then
begin
Memo1.Lines.Add('');
Memo1.Lines.Add(Format('通过值:%.1f,',[FeedbackBuf[n-i]]));
DEC(i);
end
else if token=GL_POLYGON_TOKEN then
begin
vcount:=Round(FeedbackBuf[n-i]);
Memo1.Lines.Add(Format('多边形—%d 个顶点(XYZ ):',[vCount]));
DEC(i);
for k:=1 to Vcount do
begin
vert:='';
//希望将图元的顶点的窗口坐标值转换为世界坐标下的值
//例如反馈回来(0,0,0),(0,0,1),(1,1,1)等。
gluUnproject(FeedbackBuf[n-i],FeedbackBuf[n-i+1],FeedbackBuf[n-i+2],mview,proj,viewport,@px,@py,@pz);
i:=i-3;
vert:=vert+Format('%.1f ,%.1f ,%.1f ,',[px,py,pz]);
{ for j:=0 to 2 do
begin
vert:=vert+Format('%.1f ,',[FeedbackBuf[n-i]]);
DEC(i);
end;
}
//显示图元的坐标值
Memo1.Lines.Add(Vert);
end;
end;
end;
end;
end;

end.
 
后退
顶部