如何绘制一个物体并在倾斜正面投影中旋转它
How to draw an object and rotate it in oblique frontal projection
如何在倾斜正面(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.
你可以使用WASDQER键旋转对象。
因此,正如您可能会在下面的动画中注意到的那样,当您查看它时会出现一些问题,它会稍微拉长:
不应该像下面这样吗?:
我试图将 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 等函数(旋转* )正确吗?
顺便说一句,我认为主要问题是 LineXYZ() 函数(y 坐标部分)。
如何在这种投影中绘制对象?
万分感谢,正需要
此致,
V7
Isn't it should look like one below?
不是,下面的gif是90-90投影,而你的轴是135-90
您的代码是正确的,除了两点:
- 你的X轴方向错误
- 您使用
sin
而不是 cos
,而角度是 pi/4
它们是相同的,但是如果您打算改变角度...
您的代码:
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;
应该是:
x1 := -sp_t.x - cos( pi / 4 ) * sp_t.y / 2;
y1 := sp_t.z - sin( pi / 4 ) * sp_t.y / 2;
x2 := -ep_t.x - cos( pi / 4 ) * ep_t.y / 2;
y2 := ep_t.z - sin( pi / 4 ) * ep_t.y / 2;
在休息时,您的渲染是正确的。
关于@lurker笔记:
没有理由在这里修复透视错觉(这是人格化的东西 - 不可能为所有观众平等地补偿它)。
这张gif只是展示了这种错觉效果:
如何在倾斜正面(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.
你可以使用WASDQER键旋转对象。
因此,正如您可能会在下面的动画中注意到的那样,当您查看它时会出现一些问题,它会稍微拉长:
不应该像下面这样吗?:
我试图将 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 等函数(旋转* )正确吗? 顺便说一句,我认为主要问题是 LineXYZ() 函数(y 坐标部分)。 如何在这种投影中绘制对象?
万分感谢,正需要
此致, V7
Isn't it should look like one below?
不是,下面的gif是90-90投影,而你的轴是135-90
您的代码是正确的,除了两点:
- 你的X轴方向错误
- 您使用
sin
而不是cos
,而角度是pi/4
它们是相同的,但是如果您打算改变角度...
您的代码:
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;
应该是:
x1 := -sp_t.x - cos( pi / 4 ) * sp_t.y / 2;
y1 := sp_t.z - sin( pi / 4 ) * sp_t.y / 2;
x2 := -ep_t.x - cos( pi / 4 ) * ep_t.y / 2;
y2 := ep_t.z - sin( pi / 4 ) * ep_t.y / 2;
在休息时,您的渲染是正确的。
关于@lurker笔记:
没有理由在这里修复透视错觉(这是人格化的东西 - 不可能为所有观众平等地补偿它)。
这张gif只是展示了这种错觉效果: