3d测试:绕竖直轴旋转的几个三角形

这是一个用空间几何计算实现点的坐标变换、模拟视觉的例子。将2个java文件放在同一个包里。

主文件:


package com.baobao.sayhello;

import android.app.*;
import android.content.*;
import android.graphics.*;
import android.os.*;
import android.view.*;
import android.widget.*;
import java.util.*;


public class MainActivity extends Activity 
{

    mview view;
    int winx,winy,bmx,bmy,ct=8;
    Bitmap bm;
    Handler mHandler;
    ArrayList t=new ArrayList();
    tri3d.Point p=new tri3d.Point(0,-10,0);
    class mview extends View{//自定义一个叫mview的新类型,继承View
        public mview(Context con){//构造(初始化)函数
            super(con);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh)
        {
            //窗口大小改变时触发
            super.onSizeChanged(w, h, oldw, oldh);
            winx=w;winy=h;bmx=winx/16;bmy=winy/16;
            Random r=new Random();
            int i;
            for(i=0;i b=new ArrayList();
            for(i=0;i ll=new ArrayList();
                    tri3d.Point p1=new tri3d.Point((ix-bmx/2.0)*4/bmx,0,(bmy/2.0-iy)*6/bmy);
                    for(i=0;i0&&((tri3d.Point)l.get(1)).y>0&&((tri3d.Point)l.get(1)).x+((tri3d.Point)l.get(1)).y<1){
                            min=l.get(2);
                            k=i;
                        }
                        ll.add(l);
                    }
                    tri3d.Point p2=(tri3d.Point)ll.get(k).get(1);
                    bm.setPixel(ix,iy,((boolean)ll.get(k).get(0)&&p2.x>0&&p2.y>0&&p2.x+p2.y<1)?Color.rgb((int)(p2.y*10)%2==0?255:127,(int)(255-((double)ll.get(k).get(2)-7)*256/6),0):Color.BLACK);//设置图片每个像素
                }
            canvas.drawBitmap(bm,null,new RectF(0,0,winx,winy),paint);//把图片贴到屏幕
        }
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            //触控屏幕时触发
            if(event.getAction()==MotionEvent.ACTION_DOWN){
                //如果事件类型为按下

            }

            return true;//返回真,表示已处理消息
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        view=new mview(this);//新建一个叫view的mview
        setContentView(view);//把view设为整个界面
    }
}

3d计算库:

package com.baobao.sayhello;
import java.util.*;

public class tri3d//空间几何计算库
{
    public static class Point{//点
        public double x,y,z;
        Point (double x,double y,double z){
            this.x=x;this.y=y;this.z=z;
        }
        public double length(){//和原点距离(长度)
            return Math.sqrt(x*x+y*y+z*z);
        }
        public Point unit(){//单位化
            return new Point(x/this.length(),y/this.length(),z/this.length());
        }
        public Point cross(Point p){//叉乘
            return new Point(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
        }
        public Point translate(Point p){//平移(矢量和)
            return new Point(x+p.x,y+p.y,z+p.z);
        }
        public Point vectorTo(Point p){//由p1指向p2的向量
            return new Point(p.x-x,p.y-y,p.z-z);
        }
        public Point scale(double k){//以原点为中心缩放k倍
            return new Point(x*k,y*k,z*k);
        }
        public Point scale(Point p,double k){//以p为中心缩放k倍
            return p.translate(p.vectorTo(this).scale(k));
        }
        public Point rotate(Line l,double rad){//以l为轴右手向旋转角度rad
            Point n=l.p.unit();
            double sin=Math.sin(rad),cos=Math.cos(rad),cos1=1-cos;
            double ax=x-l.p0.x,ay=y-l.p0.y,az=z-l.p0.z;
            double cx=n.x*sin,cy=n.y*sin,cz=n.z*sin;
            double bxy=n.x*n.y*cos1,byz=n.y*n.z*cos1,bzx=n.z*n.x*cos1;
            return new Point(
                ax*(n.x*n.x*cos1+cos)+ay*(bxy-cz)+az*(bzx+cy)+l.p0.x,
                ay*(n.y*n.y*cos1+cos)+az*(byz-cx)+ax*(bxy+cz)+l.p0.y,
                az*(n.z*n.z*cos1+cos)+ax*(bzx-cy)+ay*(byz+cx)+l.p0.z
            );
        }
        public Point fromBase(Base b){//从b坐标系的坐标转为默认坐标系的坐标
            return b.p0.
            translate(b.px.scale(this.x)).
            translate(b.py.scale(this.y)).
            translate(b.pz.scale(this.z));
        }
        public Point toBase(Base b){//从默认坐标系的坐标转为b坐标系的坐标
            double p1x=b.px.x,p2x=b.py.x,p3x=b.pz.x;
            double p1y=b.px.y,p2y=b.py.y,p3y=b.pz.y;
            double p1z=b.px.z,p2z=b.py.z,p3z=b.pz.z;
            double p0x=x-b.p0.x,p0y=y-b.p0.y,p0z=z-b.p0.z;
            double d=p1x*(p2y*p3z-p3y*p2z)+p1y*(p2z*p3x-p2x*p3z)+p1z*(p2x*p3y-p2y*p3x);
            double dx=p0x*(p2y*p3z-p3y*p2z)+p0y*(p2z*p3x-p2x*p3z)+p0z*(p2x*p3y-p2y*p3x);
            double dy=p0x*(p1z*p3y-p3z*p1y)+p0y*(p1x*p3z-p3x*p1z)+p0z*(p1y*p3x-p3y*p1x);
            double dz=p0x*(p1y*p2z-p2y*p1z)+p0y*(p1z*p2x-p2z*p1x)+p0z*(p1x*p2y-p2x*p1y);
            return new Point(dx/d,dy/d,dz/d);
        }
    }
    public static class Line{//点向式直线
        public Point p0,p;
        Line (Point p0,Point p){
            this.p0=p0;this.p=p;
        }
        public Line toBase(Base b){//转到坐标系b的坐标
            Point p1=p0.toBase(b);
            return new Line(p1,p1.vectorTo(p0.translate(p).toBase(b)));
        }
        public ArrayList shootAt(Base b){//获得直线与t坐标系xoy面的交点(t坐标系),in为是否朝向平面
            Line l=this.toBase(b);
            ArrayList list=new ArrayList();
            list.add(l.p.z<0&&l.p0.z>0||l.p.z>0&&l.p0.z<0?true:false);
            list.add(l.p0.translate(l.p).scale(l.p0,-l.p0.z/l.p.z));
            list.add(p0.vectorTo(((Point)list.get(1)).fromBase(b)).length());
            return list;
        }
    }
    public static class Base{//坐标系
        public Point p0,px,py,pz;
        Base(Point p0,Point px,Point py,Point pz){
            this.p0=p0;this.px=px;this.py=py;this.pz=pz;
        }
    }
    public static class Triangle{//三角形
        public Point px,po,py;
        Triangle(Point px,Point po,Point py){
            this.px=px;this.po=po;this.py=py;
        }
        public Base base(){
            Point vx=po.vectorTo(px),vy=po.vectorTo(py);
            return new Base(po,vx,vy,vx.cross(vy));
        }
        public Triangle translate(Point p){
            return new Triangle(px.translate(p),po.translate(p),py.translate(p));
        }
        public Triangle scale(Point p,double k){
            return new Triangle(px.scale(p,k),po.scale(p,k),py.scale(p,k));
        }
        public Triangle rotate(Line l,double rad){
            return new Triangle(px.rotate(l,rad),po.rotate(l,rad),py.rotate(l,rad));
        }
    }
}

设置文件:




    
        
            
                

                
            
        
    


效果

注意要把代码里的包名改成你的包名。

主文件里的bmx和bmy是绘制图片的宽高。图片越大质量越高但运行起来越卡。图片越小运行越流畅但接近马赛克。

这两个参数都是用屏幕宽高除以一个数计算的。可以改变除数值。除的越大图片宽和高就越小。

每个三角形三个顶点位置是随机的,每次运行一般不一样。

主要原理:

首先每一帧要计算出每个三角形所有点的坐标。
把眼睛当成一个点,从这个点向可视的方向引射线,就会和某些三角形内部相交。
由于遮挡关系,只能看到距离眼睛点最近的交点,根据这个交点在对应三角形平面上的位置来决定这个点是什么颜色。
对过眼睛点和每个屏幕像素点的射线,都枚举计算颜色,就能拼出一副3d图片。

你可能感兴趣的:(3d测试:绕竖直轴旋转的几个三角形)