新浪 透视java_(JAVA)MyColorCube7(透视效果)

(JAVA)MyColorCube7(透视效果)

实现功能:显示一个有颜色的正方体,

拖动鼠标时,正方体绕中心点转动.此正方体具有透视的效果.(近处的面大,线长;远处的面小,线短)

本例是在MyColorCube5(MyColorCube5是在MyColorCube2基础上更换了一个新的三维矩阵类)的基础上实现一个新功能:透视.

一)本例透视效果的实现方法:

1)添加两个变量(ColorCube类的变量成员):

private double Zeye = 10;

private

double persp;

2)实现"透视"功能的关键处(在CalcScrPts()方法中):

将下面原来的两句:

scrPts[p][0] = (int)(rotPts[p][0]*scale+x);

scrPts[p][1] = (int)(rotPts[p][1]*scale+y);

改为以下三句:

persp = (Zeye -

rotPts[p][2])/(scale*Zeye);//rotPts[p][2]为该点的Z坐标

scrPts[p][0] = (int)(rotPts[p][0]/persp+x);

scrPts[p][1] = (int)(rotPts[p][1]/persp+y);

设scale=100时:

若rotPts[p][0]=1, 则persp=9/1000, 其倒数1/persp =

111

若rotPts[p][0]=-1, 则persp=11/1000, 其倒数1/persp =

99

即,靠前的点,放大倍数大;靠后的点, 放大倍数小.

(注意,坐标原点的须位于物体的中心,否则将产生位移,详见"计算机图形学与矩阵"中的"变比")

二)实现透视效果后的面消隐

调试中发现:实现透视效果后,面消隐受到影响.可能是由于精度损失的原因.

将 faceUp()方法中的:

(rotPts[f][2]>0.0f)

改为:

(rotPts[f][2]>0.1f)

问题基本得以解决.

注意这里,在"MyColorCube5"中 rotPts[f][2]小于0可见,这里是大于0可见.

可能是由于计算透视时用的坐标系不同而造成的. (左手系? 右手系? 有空再来分析)

*/

mport java.awt.Color;

import java.awt.Graphics;

import java.awt.Graphics2D;

//import java.awt.Color;

//import java.awt.Event;

import java.awt.event.*;

import java.applet.*;

import java.awt.*;

public class MyColorCube7

extends Applet implements MouseListener,

MouseMotionListener {

public Image bgImage;

public Graphics bg;

public ColorCube obj;

static final double PI=3.1416;

int

prevX,prevY;//按下鼠标时,光标的坐标

//Matrix3D

mat,matRot;

int

h,w;

float

f;

public void init(){

w = this.getWidth();

h = this.getHeight();

obj = new ColorCube(w,h);

addMouseListener(this);

addMouseMotionListener(this);

}

public void start(){

//obj.matRot.xrot(-15);//

//obj.matRot.yrot(15);

}

public void update (Graphics g) {

Graphics2D g2 =(Graphics2D) g;

if (bgImage == null){

bgImage = createImage (this.getSize().width,

this.getSize().height);

bg = bgImage.getGraphics ();

}

Graphics2D bg2D =(Graphics2D) bg;//用Image.getGraphics

()得到的是Graphics类,

//需要将其转换为Graphics2D类,才能完成以后绘制

// 后台清屏,

bg.setColor (getBackground ());

bg2D.fillRect(0, 0, w, h);

// bg.fillRect(0, 0, w, h);

//以下在后台绘制

if

(obj != null) {

//objs[i].render(g2);

obj.MyDraw(bg2D,w,h);//调用ColorCube的MyDraw方法,绘制转动变化后的图形

}

g2.drawImage (bgImage, 0, 0, null);

}//end

update

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D)g;

obj.MyDraw(g2,w,h);

}

public void mouseClicked(MouseEvent

e) {

}

public void mousePressed(MouseEvent

e) {

prevX = e.getX();

prevY = e.getY();

e.consume();//不再执行原来(父类)的方法

}

public void

mouseReleased(MouseEvent e) {

//松开鼠标时发生

}

public void mouseEntered(MouseEvent

e) {

//进入显示区时发生

}

public void mouseExited(MouseEvent

e) {

//离开显示区域时发生

}

public void mouseDragged(MouseEvent

e) {

//拖动鼠标时发生

int x

= e.getX();

int y = e.getY();

//鼠标左右移动(x轴坐标改变),绕Y轴转动.

鼠标移动的距离等于显示区域宽度时,转动180度

double thetaY = (x-prevX) * 180.0f / getSize().width;

//鼠标上下移动(Y轴坐标改变),绕X轴转动 .鼠标移动的距离等于显示区域高度时,转动180度

double thetaX = (y-prevY) * 180.0f / getSize().height;

obj.CubeRotate(thetaX, thetaY, 0);

obj.CalcScrPts((double) w/2,(double) h/2, 0);

//obj.matRot.xrot(-thetaX);//可能是由于屏幕坐标系与局部坐标系的差异,这里须加负号,转动的方向才是所希望的

// obj.matRot.yrot(thetaY);

prevX = x; //此两句很关键,每计算完一次,都须将当前点作为起始点

prevY =

y;

repaint();

e.consume();

}

public void mouseMoved(MouseEvent

e) {

}

public void destroy() {

removeMouseListener(this);

removeMouseMotionListener(this);

}

}

class ColorCube {

//本例用绘制多边形的方法(fillPolygon()与drawPolygon())来绘制几何体的棱(边)

private static final int[][]

polygons =

// Solid cube 正方体(每面一种颜色)

{{5, 0, 6, 10, 13, 9, 6},

{5, 1, 7, 11, 12, 8, 7},

{5, 2, 6, 7, 8, 9, 6},

{5, 3, 10, 11, 12, 13, 10},

{5, 4, 6, 7, 11, 10, 6},

{5, 5, 8, 9, 13, 12, 8}};

//以下数据与点坐标有关

private static final double[][]

points =

// Points

for solid cube & polygonal faces cube

{{1, 0, 0}, {-1, 0, 0}, {0, 1,

0},

{0, -1, 0}, {0, 0, 1}, {0, 0, -1},

{1, 1, 1}, {-1, 1, 1}, {-1, 1, -1},{1, 1,

-1},

{1, -1, 1}, {-1, -1, 1}, {-1, -1, -1},{1, -1, -1}};

//以下数据与面有关

private static final int[][]

faces =

// Solid

cube

{{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}};

private int npoly;

private int npoints;

private int nfaces;

private int ncolors = 6;

public double rotPts[][];

public double scrPts[][];

public int xx[],yy[];

public Color[] colors = new

Color[ncolors];

private double

angleX,angleY,angleZ;

public Matrix3D orient, tmp, tmp2, tmp3;

private double scale;

private int p;

private double Zeye = 10;

private double persp;

ColorCube(

int w,

int h) {

npoly =

polygons.length;// 若前移(作为变量成员),出错.npoly=6; ;

npoints =

points.length;// npoint=14;

nfaces =

faces.length; // nface=6

double len;

// red

colors[0]=

new Color(255,0,0);

// green

colors[1]=

new Color(0,255,0);

// blue

colors[2]=

new Color(0,0,255);

//

yellow

colors[3]=

new Color(255,255,0);

// cyan

colors[4]=

new Color(0, 255 ,255);

//

magenta

colors[5]=

new Color(255 , 0,255);

rotPts =

new double[npoints][3];

scrPts = new double[npoints][3];

xx = new int[5];

yy = new int[5];

orient = new Matrix3D();

tmp =

new Matrix3D();

tmp2 =

new Matrix3D();

tmp3 =

new Matrix3D();

angleX=20;angleY=20; angleZ=10;

CubeRotate(1,1,1);

double max = 0;

for (int i = 0; i < npoints; i++)

{

len = Math.sqrt(points[i][0]*points[i][0]

+

points[i][1]*points[i][1] +

points[i][2]*points[i][2]);

if (len >max) {

max = len;

}

}

scale = Math.min(w/2/max/1.2, h/2/max/1.2); //计算放大比例

CalcScrPts((double) w/2,(double) h/2, 0);

//此方法将先计算转动后的坐标, 再将其转换为屏幕坐标

}

public void

CubeRotate(double rotX,double rotY,double

rotZ){

angleX += rotX;

angleY += rotY;

angleZ += rotZ;

tmp.Rotation(1,2,Math.PI*angleX/180);//绕y轴旋转50度(前两个参数决定旋转所围绕的轴以及旋转的方向,详见后面Matrix3D类的Rotation())

tmp2.Rotation(0, 2, Math.PI*angleY/180);

tmp3.Rotation(0, 1, Math.PI*angleZ/180);

orient.M =

tmp3.Times(tmp2.Times(tmp.M));

}

//以下先将点乘以矩阵,计算出转动后的坐标, 再将其转换为屏幕坐标

public void CalcScrPts(double x, double

y, double z) {

for (p = 0; p < npoints; p++)

{ //将各点转换为转动后的坐标

rotPts[p][2] = points[p][0]*orient.M[2][0] +

points[p][1]*orient.M[2][1] +

points[p][2]*orient.M[2][2];

rotPts[p][0] = points[p][0]*orient.M[0][0] +

points[p][1]*orient.M[0][1] +

points[p][2]*orient.M[0][2];

rotPts[p][1] = -points[p][0]*orient.M[1][0] -

points[p][1]*orient.M[1][1] -

points[p][2]*orient.M[1][2];

}

//以下将转动后的各点转换为屏幕坐标

for (p = nfaces; p < npoints; p++)

{ //注意P的初值.(只转换后八个点,前6个点为各面的中心点,无须转换

//以下三句是实现"透视"功能的关键句

persp = (Zeye -

rotPts[p][2])/(scale*Zeye);//persp有大小随点的Z坐标不同而不同(rotPts[p][2]为该点的Z坐标

scrPts[p][0] =

(int)(rotPts[p][0]/persp+x);

scrPts[p][1] = (int)(rotPts[p][1]/persp+y);

//以下两句没有"透视"功能

// scrPts[p][0] =

(int)(rotPts[p][0]*scale+x);

// scrPts[p][1] =

(int)(rotPts[p][1]*scale+y);

}

}

private boolean faceUp(int

f) {

return (rotPts[f][2]>0.1f);

}

void MyDraw(Graphics2D g2,int

w,int h){

for(int f =0; f

if (faceUp(f))

DrawPoly( g2, f);

}

}

void DrawPoly(Graphics2D g2, int

nf){

for

(int p=0; p < polygons[nf][0];

p++){

xx[p]=(int)scrPts[polygons[nf][p+2]][0];

yy[p]=(int)scrPts[polygons[nf][p+2]][1];

}

g2.setColor(colors[nf]);

g2.fillPolygon(xx,yy,polygons[nf][0]);//也可将polygons[nf][0]改作4;(polygons[nf][0]==5)

g2.setColor(Color.black);

g2.drawPolygon(xx,yy,polygons[nf][0]);//也可将polygons[nf][0]改作4;(polygons[nf][0]==5)

}

}

class

Matrix3D {

//以下定义一个3*3的单位矩阵,修改其中元素数值对程序运行并无影响.

//因为每次进行矩阵运算时,都先对这个矩阵进行初始化.见Rotation()中的代码.

public double[][] M = { { 1, 0, 0 },

{ 0, 1, 0 },

{ 0, 0, 1 } };

private double[][] tmp = new

double[3][3];

private int row, col, k;

//以下Rotation将根据传入参数i,j的不同,分别实现绕x轴,y轴,z轴的顺时针或反时针的旋转.

//如:

i=0,j=1时,绕Z轴顺时针; i=1,j=0时,绕Y轴反时针,

//如:

i=1,j=2时,绕X轴顺时针; i=2,j=1时,绕Y轴反时针,

//如: i=0,j=2时,绕Y轴顺时针; i=2,j=0时,绕Y轴反时针,

//参见"计算机图形学与矩阵"

public void Rotation(int i, int j,

double angle) {

//以下for循环对矩阵M进行初始化

for

(row = 0; row < 3; row++) {

for (col = 0; col <3; col++) {

if (row != col) {

M[row][col] = 0.0;

} else {

M[row][col] = 1.0;

}

}

}

M[i][i] = Math.cos(angle);

M[j][j] = Math.cos(angle);

M[i][j] = Math.sin(angle);

M[j][i] = -Math.sin(angle);

}

public double[][] Times(double[][] N) {

for (row = 0; row < 3; row++) {

for (col = 0; col < 3; col++) {

tmp[row][col] = 0.0;

for

(k = 0; k < 3; k++) {

tmp[row][col] += M[row][k] * N[k][col];

}

}

}

return tmp;

}

} // End Matrix3D

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值