0
点赞
收藏
分享

微信扫一扫

JAVA三维软光栅渲染三角形

package com.alatus;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;

public class Rect extends JFrame {
    //    屏幕分辨率
    public static int screen_W = 1024;
    public static int screen_H = 682;
    public static int half_screen_W = screen_W / 2;
    public static int half_screen_H = screen_H / 2;
    //    记载当前已经绚烂的帧数
    public static int frameIndex;
    public static int screenSize = screen_W * screen_H;
    //    希望达到的每帧之间的间隔时间
    public static int frameInterval = 33;
    //    使用jPanel作为画板
    public static JPanel panel;
    //    使用一个int数组来存储屏幕像素数值
    public static int[] screen;
    //    图像缓冲区,提供了在内存中操作屏幕图像的方式
    public static BufferedImage screenBuffer;
    //    刷新率,计算刷新率所用的辅助参数
    public static int framePerSecond;
    public static long lastDraw;
    public static double lastTime,thisTime;
    //    cpu睡眠时间
    public static int sleepTime;
    public static void main(String[] args) {
        new Rect();
    }
    public Rect() {
//        弹出一个JPanel窗口, 设置窗口大小,并将它放置在屏幕中间
        setTitle("三角形矢量计算");
        panel = (JPanel) this.getContentPane();
        panel.setPreferredSize(new Dimension(screen_W, screen_H));
        panel.setMinimumSize(new Dimension(screen_W, screen_H));
        panel.setLayout(null);
        setResizable(false);
        pack();
        setVisible(true);
        Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
        setLocation(dimension.width / 2 - this.getSize().width / 2, dimension.height / 2 - screen_H / 2);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        使用TypeIntRGB来创建BufferedImage,然后把屏幕的像素数组指向BufferedImage中的DataBuffer
//        这样通过改变屏幕的像素数组中的数据就可以在屏幕上渲染出图象
        screenBuffer = new BufferedImage(screen_W, screen_H, BufferedImage.TYPE_INT_RGB);
        DataBuffer dest = screenBuffer.getRaster().getDataBuffer();
        screen = ((DataBufferInt)dest).getData();
//        初始化查找表
        LookupTable.init();
//        渲染
        while(true){
//        把图像发送到显存,这是唯一用到显卡的地方
            int r_skyBlue = 163, g_skyBlue = 216, b_skyBlue = 239;
            int r_orange = 255, g_orange = 128, b_orange = 0;
//            渲染为天蓝色
            screen[0] = (163 << 16) | (216 << 8) | b_skyBlue;//天蓝色
            for (int i = 0; i < screenSize; i++) {
//                arrayCopy是JAVA中为数不多的不适用JVM虚拟机而是直接使用系统资源计算的命令和方法,所以它的效率非常高
//                这里这一步等了超级久它才渲染出来,不知道为什么???
                System.arraycopy(screen,0,screen,i,screenSize - i >= i ? i : screenSize - i);
            }
//            loop每次运行,帧数+1
            frameIndex++;
//            计算当前的刷新率,并尽量让刷新率恒定不变
            if(frameIndex%30==0){
                double thisTime = System.currentTimeMillis();
                framePerSecond = (int) (1000 / ((thisTime - lastTime)/30));
                lastTime = thisTime;
            }
            sleepTime = 0;
            while(System.currentTimeMillis() - lastDraw < frameInterval){
                try{
                    Thread.sleep(1);
                    sleepTime++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            lastDraw = System.currentTimeMillis();
//            显示当前刷新率
            Graphics2D e2 = (Graphics2D) screenBuffer.getGraphics();
            e2.setColor(Color.BLACK);
            e2.drawString("FPS:"+framePerSecond+"ThreadSleep:"+sleepTime,5,15);
            panel.getGraphics().drawImage(screenBuffer, 0, 0, this);
        }
    }
}

package com.alatus;

public class Vector3D {
//    矢量在XYZ轴上的分量
    public float x,y,z;
//    构造函数,传入矢量的三个分类
    public Vector3D(float x,float y,float z){
        this.x = x;
        this.y = y;
        this.z = z;
    }
//    把XYZ轴上的分量设置为v
    public void set(Vector3D v){
        this.x = v.x;
        this.y = v.y;
        this.z = v.z;
    }
//    矢量加
    public void add(Vector3D v){
        this.x += v.x;
        this.y += v.y;
        this.z += v.z;
    }
//    矢量减
    public void sub(Vector3D v){
        this.x -= v.x;
        this.y -= v.y;
        this.z -= v.z;
    }
//    矢量点之和,结果代表两个矢量之间的相似程度,用来判断多边形的亮度
    public float dot(Vector3D v1,Vector3D v2){
        return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
    }
//    矢量叉积,求一个与这两个矢量都垂直的矢量,求多边形的法矢量
    public void cross(Vector3D v1,Vector3D v2){
        x = v1.y*v2.z-v1.z*v2.y;
        y = v1.z*v2.x-v1.x*v2.z;
        z = v1.x*v2.y-v1.y*v2.x;
    }
//    求矢量长度
    public float getLength(){
        return (float)Math.sqrt(x*x+y*y+z*z);
    }
//    将矢量单位化
    public void unit(){
        float l = getLength();
        x = x/l;
        y = y/l;
        z = z/l;
    }
//    将矢量乘以一个标量
    public void scale(float s){
        x *= s;
        y *= s;
        z *= s;
    }
//    绕Y轴旋转矢量,使其顺时针旋转指定角度
    public void rotate_Y(int angle){
        float sin = LookupTable.sin[angle];
        float cos = LookupTable.cos[angle];
        float old_X = x;
        float old_Z = z;
        x = old_X*cos-old_Z*sin;
        z = old_X*sin+old_Z*cos;
    }
//    绕X轴旋转矢量,使其顺时针旋转指定角度
    public void rotate_X(int angle){
        float sin = LookupTable.sin[angle];
        float cos = LookupTable.cos[angle];
        float old_Y = y;
        float old_Z = z;
        y = old_Y*cos-old_Z*sin;
        z = old_Y*sin+old_Z*cos;
    }
//    绕Z轴旋转矢量,使其顺时针旋转指定角度
    public void rotate_Z(int angle){
        float sin = LookupTable.sin[angle];
        float cos = LookupTable.cos[angle];
        float old_X = x;
        float old_Y = y;
        x = old_X*cos-old_Y*sin;
        y = old_X*sin+old_Y*cos;
    }
}

package com.alatus;

public class LookupTable {
    public static float[] sin;
    public static float[] cos;
    public static void init(){
        sin = new float[360];
        cos = new float[360];
        for (int i = 0; i < 360; i++) {
            sin[i] = (float)Math.sin(Math.PI*i/100);
            cos[i] = (float)Math.cos(Math.PI*i/100);
        }
    }
}

package com.alatus;

public class Rasterizer {
//    设置屏幕分辨率
    public static final int screen_w = Rect.screen_W;
    public static final int screen_h = Rect.screen_H;
    public static int half_screen_w = Rect.half_screen_W;
    public static int half_screen_h = Rect.half_screen_H;
//    屏幕的像素组
    public static int[] screen = Rect.screen;
//    视角的原点到屏幕的距离(以像素为单位)这个值越大视角就越狭窄,常用的值为屏幕的一半
    public static int screenDistance = screen_w/2;
//    用两个矢量数组来表示三角形的顶点坐标和变化后的顶点坐标
//    未经变换的三角形顶点
    public static Vector3D[] triangleVertices;
//    变化后的三角形顶点坐标
    public static Vector3D[] updatedVertices;
//    三角形的顶点个数,一般为3,但但三角形与视角z平面相切的时候有可能是4个
    public static int vertexCount = 3;
//    三角形变换后的顶点投影在屏幕上的2D坐标
    public static float[][] vertices2D = new float[4][2];
//    用于扫描三角形的两个数组,每行由两个值,分别表示描线的起点和终点的X坐标
    public static int[] xleft = new int[screen_h],xRight = new int[screen_h];
//    三角形扫描线最高和最低的位置
    public static int scanUpperPosition,scanLowerPosition;
//    三角形的颜色
    public static int triangleColor;
//    三角形的s形
    public static int renderType;
//    初始化光栅渲染器
    public static void init() {
//        初始化三角形变换后的顶点
        updatedVertices = new Vector3D[]{
                new Vector3D(0,0,0),
                new Vector3D(0,0,0),
                new Vector3D(0,0,0),
                new Vector3D(0,0,0),
        };
    }
//    光栅渲染器的入口
    public static void rasterizer(){
//        变换三角形的顶点
        transformVertices();
//        将三角形转为扫描线
        scanTriangle();
//        给三角形像素着色
        renderTriangle();
    }
//    变换三角形的顶点
    public static void transformVertices(){
//        当前演示是静态渲染的三角形,以此不做变换
        updatedVertices[0].set(triangleVertices[0]);
        updatedVertices[1].set(triangleVertices[1]);
        updatedVertices[2].set(triangleVertices[2]);
//        用投影公式求出顶点在屏幕上的2D坐标
        for (int i = 0; i < vertexCount; i++) {
            vertices2D[i][0] = half_screen_w + updatedVertices[i].x*screenDistance/updatedVertices[i].z;
            vertices2D[i][1] = half_screen_h - updatedVertices[i].y*screenDistance/updatedVertices[i].z;
        }
    }
//    将三角形转换为扫描线
    public static void scanTriangle(){

    }
}

举报

相关推荐

0 条评论