【发布时间】:2018-04-18 21:25:36
【问题描述】:
如何在倾斜正面(dimetric)投影中正确地绘制对象并旋转它?
投影示意图:
我已经编写了一个程序(Pascal with Graph unit),但我认为它绘制的对象不正确。
program p7test;
uses PtcCrt, PtcGraph;
type
TPixel = record
x, y, z: real;
end;
TModel = record
p: array [ 1..8 ] of TPixel;
end;
TCenter = record
xc, zc: integer;
end;
var
Driver, Mode: integer;
c: char;
s: string;
ns, rx, ry, rz, ra, m_l, m_w, m_h, m_l_d, m_w_d, m_h_d: integer;
model_d, model: TModel;
center: TCenter;
procedure LineXYZ( sp_t, ep_t: TPixel; center_t: TCenter );
var
x1, y1, x2, y2: real;
begin
x1 := sp_t.x - sin( pi / 4 ) * sp_t.y / 2;
y1 := sp_t.z - sin( pi / 4 ) * sp_t.y / 2;
x2 := ep_t.x - sin( pi / 4 ) * ep_t.y / 2;
y2 := ep_t.z - sin( pi / 4 ) * ep_t.y / 2;
Line(
round( center_t.xc - x1 ),
round( center_t.zc - y1 ),
round( center_t.xc - x2 ),
round( center_t.zc - y2 )
);
end;
procedure DrawModel( model_t: TModel; center_t: TCenter );
var
i: integer;
begin
LineXYZ( model_t.p[ 1 ], model_t.p[ 2 ], center_t );
LineXYZ( model_t.p[ 2 ], model_t.p[ 3 ], center_t );
LineXYZ( model_t.p[ 3 ], model_t.p[ 4 ], center_t );
LineXYZ( model_t.p[ 4 ], model_t.p[ 1 ], center_t );
LineXYZ( model_t.p[ 5 ], model_t.p[ 6 ], center_t );
LineXYZ( model_t.p[ 6 ], model_t.p[ 7 ], center_t );
LineXYZ( model_t.p[ 7 ], model_t.p[ 8 ], center_t );
LineXYZ( model_t.p[ 8 ], model_t.p[ 5 ], center_t );
LineXYZ( model_t.p[ 1 ], model_t.p[ 5 ], center_t );
LineXYZ( model_t.p[ 2 ], model_t.p[ 6 ], center_t );
LineXYZ( model_t.p[ 3 ], model_t.p[ 7 ], center_t );
LineXYZ( model_t.p[ 4 ], model_t.p[ 8 ], center_t );
end;
function RotateZ( model_t: TModel; angle: real ): TModel;
var
x, y: real;
i: integer;
begin
angle := angle * pi / 180;
for i := 1 to 8 do
begin
x := model_t.p[ i ].x;
y := model_t.p[ i ].y;
model_t.p[ i ].x := x * cos( angle ) - y * sin( angle );
model_t.p[ i ].y := y * cos( angle ) + x * sin( angle );
end;
RotateZ := model_t;
end;
function RotateY( model_t: TModel; angle: real ): TModel;
var
x, z: real;
i: integer;
begin
angle := angle * pi / 180;
for i := 1 to 8 do
begin
x := model_t.p[ i ].x;
z := model_t.p[ i ].z;
model_t.p[ i ].x := x * cos( angle ) - z * sin( angle );
model_t.p[ i ].z := z * cos( angle ) + x * sin( angle );
end;
RotateY := model_t;
end;
function RotateX( model_t: TModel; angle: real ): TModel;
var
y, z: real;
i: integer;
begin
angle := angle * pi / 180;
for i := 1 to 8 do
begin
y := model_t.p[ i ].y;
z := model_t.p[ i ].z;
model_t.p[ i ].y := y * cos( angle ) - z * sin( angle );
model_t.p[ i ].z := z * cos( angle ) + y * sin( angle );
end;
RotateX := model_t;
end;
function RotateXYZ( model_t: TModel; rx_t, ry_t, rz_t: integer ): TModel;
begin
model_t := RotateX( model_t, rx_t );
model_t := RotateY( model_t, ry_t );
model_t := RotateZ( model_t, rz_t );
RotateXYZ := model_t;
end;
begin
Driver := D8bit;
Mode := m800x600;
InitGraph( Driver, Mode, '' );
ra := 2;
if ( GraphResult <> GrOk ) then WriteLn( '640x480x256''s not supported' ) else
begin
ClearDevice;
center.xc := ( GetMaxX div 2 ) + 1;
center.zc := ( GetMaxY div 2 ) + 1;
m_l_d := 200; m_w_d := 200; m_h_d := 200;
m_l := m_l_d; m_w := m_w_d; m_h := m_h_d;
rx := -26; ry := 6; rz := 16;
model_d.p[ 1 ].x := - m_l / 2; model_d.p[ 1 ].y := - m_w / 2; model_d.p[ 1 ].z := - m_h / 2;
model_d.p[ 2 ].x := - m_l / 2; model_d.p[ 2 ].y := m_w / 2; model_d.p[ 2 ].z := - m_h / 2;
model_d.p[ 3 ].x := m_l / 2; model_d.p[ 3 ].y := m_w / 2; model_d.p[ 3 ].z := - m_h / 2;
model_d.p[ 4 ].x := m_l / 2; model_d.p[ 4 ].y := - m_w / 2; model_d.p[ 4 ].z := - m_h / 2;
model_d.p[ 5 ].x := - m_l / 2; model_d.p[ 5 ].y := - m_w / 2; model_d.p[ 5 ].z := m_h / 2;
model_d.p[ 6 ].x := - m_l / 2; model_d.p[ 6 ].y := m_w / 2; model_d.p[ 6 ].z := m_h / 2;
model_d.p[ 7 ].x := m_l / 2; model_d.p[ 7 ].y := m_w / 2; model_d.p[ 7 ].z := m_h / 2;
model_d.p[ 8 ].x := m_l / 2; model_d.p[ 8 ].y := - m_w / 2; model_d.p[ 8 ].z := m_h / 2;
model := RotateXYZ( model_d, rx, ry, rz );
SetColor( 2 ); DrawModel( model, center );
SetColor( 12 );
Str( rx, s ); OutTextXY( 2, 2, 'rx=' + s );
Str( ry, s ); OutTextXY( 2, 12, 'ry=' + s );
Str( rz, s ); OutTextXY( 2, 22, 'rz=' + s );
repeat Delay( 100 ) until KeyPressed;
if ns = 0 then ns := 1 else ns := 0;
ReadKey;
repeat
c := ReadKey;
case c of
#113: begin rx := rx - ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#101: begin rx := rx + ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#119: begin ry := ry - ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#115: begin ry := ry + ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#97: begin rz := rz - ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#100: begin rz := rz + ra; model := RotateXYZ( model_d, rx, ry, rz ); end;
#117: begin
rx := 0; ry := 0; rz := 0;
model := RotateXYZ( model_d, rx, ry, rz );
end;
end;
ClearDevice;
SetColor( 2 ); DrawModel( model, center );
SetColor( 12 );
Str( rx, s ); OutTextXY( 2, 2, 'rx=' + s );
Str( ry, s ); OutTextXY( 2, 12, 'ry=' + s );
Str( rz, s ); OutTextXY( 2, 22, 'rz=' + s );
if ns = 0 then
begin
SetActivePage(0);
SetVisualPage(1)
end
else
begin
SetActivePage(1);
SetVisualPage(0)
end;
if ns = 0 then ns := 1 else ns := 0;
until c = #27;
CloseGraph;
end;
end.
您可以使用 WASDQE R 键旋转对象。
因此,正如您在下面的动画中可能注意到的那样,当您查看它时会出现一些问题并且它略微拉长:
它不应该像下面这样吗?:
我尝试将LineXYZ() 代码行更改为:
x1 := sp_t.x - ( sp_t.y / 2 );
y1 := sp_t.z - ( sp_t.y / 2 );
x2 := ep_t.x - ( ep_t.y / 2 );
y2 := ep_t.z - ( ep_t.y / 2 );
,但也可能不正确。
我是否正确旋转 x、y、z 与 (Rotate*) 等函数的坐标? 顺便说一句,我认为主要问题是 LineXYZ() 函数(y 坐标部分)。 这种投影如何绘制物体?
非常感谢,有需要的。
最好的问候, V7
【问题讨论】:
-
轻微的拉长当然是一种视觉错觉。您需要使用"perspective" drawing 技术并选择虚构的焦点并使用该修改计算您的坐标。
-
亲爱的@lurker,正如您在此处看到的media.giphy.com/media/3ohs85jCAleB5LwHUQ/giphy.gif,没有错觉。不是吗?那么为什么它在我的代码中呢?是因为 y / 2 吗?所以..我认为这不是错觉。试着只评价它正确,你就会看到会发生什么。
-
我说这是一种错觉,因为看起来更长的后边缘实际上与前景边缘的长度(在屏幕上)相同。我拍了你的照片并测量了它。但是由于透视,后边缘显得更长。眼睛/大脑将对象解释为 3D 立方体,但长度看起来不适合支持该概念。您需要使用我提供的链接中描述的透视技术创建适当深度和比例的错觉。
-
非常感谢@lurker,但是在这种类型的投影中透视是否有必要?我的意思是……这个投影不是正交的吗?
-
如果你不想让背景边看起来比前景边长,你必须应用某种透视元素。在正交投影中,投影线与投影表面(或本例中的视平面)正交。当您在 3D 中感知时,它不会提供您正在寻找的正确尺寸的错觉。
标签: math 3d rotation pascal projection-matrix