📄 render3d.java
字号:
package myprojects.graph3dapp;
import java.awt.*;
import java.util.*;
import java.awt.image.*;
class RenderObject extends GraphObject3D {
protected Canvas3D canvas;
protected Vector3d vertexHeap[];
protected Facelet faceHeap[];
protected double cosvHeap[];
protected int vertexCount = 0;
protected int faceCount = 0;
public RenderObject(Canvas3D canvas) {
this.canvas = canvas;
}
public Vector3d getVertex(int index) {
return vertexHeap[index];
}
public int vertexCount() {
return vertexCount;
}
public Facelet getFace(int index) {
return faceHeap[index];
}
public double getCosv(int index) {
return cosvHeap[index];
}
public int faceCount() {
return faceCount;
}
protected void applyColor(int destIndex, Facelet dest, Facelet src) {
Matrix3d transMatrix = src.getObject().getTransMatrix();
Color ca = canvas.atmosphereColor;
Material mat = src.material;
Vector3d n = dest.normalize();
Vector3d vpn = canvas.camera.vpn;
vpn.normalize();
cosvHeap[destIndex] = vpn.dot(n);
Light light = canvas.light;
for(int i=0; i<src.vertexs.length; i++) {
Vector3d vex = dest.getVertex(i);
Vector3d l = Vector3d.sub(light.position, vex);
l.normalize();
Vector3d v = Vector3d.sub(canvas.camera.vrp, vex);
v.normalize();
Vector3d h = Vector3d.add(l, v);
h.scale(0.5f);
h.normalize();
double cosd = l.dot(n);
if(cosd < 0) cosd = 0;
double cossn = (double)Math.pow(h.dot(n), mat.kn);
int r = (int)Math.round(ca.getRed()*mat.ka.x +
light.color.getRed()*(mat.kd.x*cosd + mat.ks.x*cossn));
if(r < 0) r = 0;
if(r > 255) r = 255;
int g = (int)Math.round(ca.getGreen()*mat.ka.y +
light.color.getGreen()*(mat.kd.y*cosd + mat.ks.y*cossn));
if(g < 0) g = 0;
if(g > 255) g = 255;
int b = (int)Math.round(ca.getBlue()*mat.ka.z +
light.color.getBlue()*(mat.kd.z*cosd + mat.ks.z*cossn));
if(b < 0) b = 0;
if(b > 255) b = 255;
dest.colors[i] = new Color(r, g, b);
}
}
public void compile() {
int i;
LinkedList objectList = canvas.getObjectList();
ListIterator it = objectList.listIterator();
vertexCount = 0;
faceCount = 0;
while(it.hasNext()) {
GraphObject3D object = (GraphObject3D)(it.next());
vertexCount += object.vertexCount();
faceCount += object.faceCount();
}
vertexHeap = new Vector3d[vertexCount];
faceHeap = new Facelet[faceCount];
cosvHeap = new double[faceCount];
it = objectList.listIterator();
Camera camera = canvas.getCamera();
int vertexIndex = 0;
int faceIndex = 0;
while(it.hasNext()) {
GraphObject3D object = (GraphObject3D)(it.next());
for(i=0; i<object.vertexCount(); i++) {
vertexHeap[vertexIndex+i] = Vector3d.mulMatrix(object.getVertex(i),
object.getTransMatrix());
//vertexHeap[vertexIndex+i] = camera.project(object.getVertex(i),
// object.getTransMatrix());
//System.out.println(vertexHeap[vertexIndex+i]);
}
for(i=0; i<object.faceCount(); i++) {
Facelet f = object.getFace(i);
faceHeap[faceIndex+i] = new Facelet(this, f.vertexs[0]+vertexIndex,
f.vertexs[1]+vertexIndex,
f.vertexs[2]+vertexIndex);
applyColor(faceIndex+i, faceHeap[faceIndex+i], f);
}
for(i=0; i<object.vertexCount(); i++) {
vertexHeap[vertexIndex+i] = camera.project(vertexHeap[vertexIndex+i]);
}
vertexIndex += object.vertexCount();
faceIndex += object.faceCount();
}
}
}
/** 边Y桶数据项*/
class EdgeYItem {
public int minY; //较小端y值图像映射坐标
public int maxY; //较大端y值图像映射坐标
public double ddx; //x增量
public int cx; //y较小端x图像映射坐标
public double z; //y较小端在观察坐标系中的深度
public Vector3d color; //y较小端颜色
public Vector3d ddcolor;//颜色增量
public EdgeYItem() {
}
public EdgeYItem(int minY, int maxY, double ddx, int cx, double z,
Vector3d color, Vector3d ddcolor) {
this.minY = minY;
this.maxY = maxY;
this.ddx = ddx;
this.cx = cx;
this.z = z;
this.color = color;
this.ddcolor = ddcolor;
}
}
/** 边Y桶类*/
class EdgeYBucket {
protected Render3D render;
protected FaceYItem faceYItem;
protected LinkedList bucket[];
public EdgeYBucket(Render3D render, FaceYItem faceYItem) {
this.render = render;
this.faceYItem = faceYItem;
}
private void swapVector(Vector3d v0, Vector3d v1) {
double x = v0.x;
v0.x = v1.x;
v1.x = x;
double y = v0.y;
v0.y = v1.y;
v1.y = y;
double z = v0.z;
v0.z = v1.z;
v1.z = z;
}
private EdgeYItem createItem(int v0, int v1, int ci0, int ci1) {
Facelet face = faceYItem.face;
RenderObject object = (RenderObject)(face.getObject());
//注意:因为后面的操作可能会修改顶点的内容,所以必须构造新的对象,用新对象操作
Vector3d vex0 = new Vector3d(object.getVertex(v0));
vex0.x = Math.round(vex0.x);
vex0.y = Math.round(vex0.y);
vex0.z = -(faceYItem.a*vex0.x+faceYItem.b*vex0.y+faceYItem.d)/faceYItem.c;
Vector3d c0 = new Vector3d(face.colors[ci0].getRed(), face.colors[ci0].getGreen(),
face.colors[ci0].getBlue());
Vector3d vex1 = new Vector3d(object.getVertex(v1));
vex1.x = Math.round(vex1.x);
vex1.y = Math.round(vex1.y);
vex1.z = -(faceYItem.a*vex1.x+faceYItem.b*vex1.y+faceYItem.d)/faceYItem.c;
Vector3d c1 = new Vector3d(face.colors[ci1].getRed(), face.colors[ci1].getGreen(),
face.colors[ci1].getBlue());
//如果该边是水平的则无须加入此时ddx为无穷大
if((int)vex0.y == (int)vex1.y) return null;
if(vex0.y > vex1.y) {
swapVector(vex0, vex1);
swapVector(c0, c1);
}
//如果该边根本不在缓冲扫描范围内放弃
if((int)vex0.y > faceYItem.maxY) return null;
if((int)vex1.y < faceYItem.minY) return null;
double ddx = -(vex1.x-vex0.x)/(vex1.y-vex0.y);
Vector3d ddcolor = new Vector3d();
ddcolor.x = -(double)(c1.x-c0.x)/(vex1.y-vex0.y);
ddcolor.y = -(double)(c1.y-c0.y)/(vex1.y-vex0.y);
ddcolor.z = -(double)(c1.z-c0.z)/(vex1.y-vex0.y);
if((int)(vex0.y) < faceYItem.minY) {
double dy = faceYItem.minY-vex0.y;
vex0.x = Math.round(vex0.x-dy*ddx);
vex0.y = faceYItem.minY;
if((int)vex0.y >= (int)vex1.y) return null; //如果修正后端点重合则放弃该边
vex0.z = -(faceYItem.a*vex0.x+faceYItem.b*vex0.y+faceYItem.d)/faceYItem.c;
c0.x = c0.x-dy*ddcolor.x;
c0.y = c0.y-dy*ddcolor.y;
c0.z = c0.z-dy*ddcolor.z;
}
return new EdgeYItem((int)vex0.y, (int)vex1.y, ddx, (int)vex0.x, vex0.z,
c0, ddcolor);
}
public void compile() {
bucket = new LinkedList[faceYItem.maxY-faceYItem.minY+1];
Facelet face = faceYItem.face;
if(faceYItem.faceIndex == 1) {
faceYItem.faceIndex = 1;
}
EdgeYItem item = createItem(face.vertexs[0], face.vertexs[1], 0, 1);
if(item != null) {
int index = item.minY-faceYItem.minY;
if(bucket[index] == null) bucket[index] = new LinkedList();
bucket[index].addLast(item);
}
item = createItem(face.vertexs[1], face.vertexs[2], 1, 2);
if(item != null) {
int index = item.minY-faceYItem.minY;
if(bucket[index] == null) bucket[index] = new LinkedList();
bucket[index].addLast(item);
}
item = createItem(face.vertexs[2], face.vertexs[0], 2, 0);
if(item != null) {
int index = item.minY-faceYItem.minY;
if(bucket[index] == null) bucket[index] = new LinkedList();
bucket[index].addLast(item);
}
}
/** 根据扫描线y坐标返回桶中的边表*/
public LinkedList get(int scanY) {
return bucket[scanY-faceYItem.minY];
}
}
/** 多边形Y桶数据项*/
class FaceYItem {
public int faceIndex = 0;
public int minY = 0, maxY = 0;
public double minZ = 0, maxZ = 0;
public double a, b, c, d;
public EdgeYBucket edgeYBucket;
public Facelet face;
public FaceYItem() {
}
public String toString() {
return "("+String.valueOf(faceIndex)+", "+String.valueOf(minY)+", "+
String.valueOf(maxY)+", "+String.valueOf(a)+", "+
String.valueOf(b)+", "+String.valueOf(c)+", "+
String.valueOf(d)+")";
}
}
/** 多边形Y桶类*/
class FaceYBucket {
protected Render3D render;
protected LinkedList bucket[];
public FaceYBucket(Render3D render) {
this.render = render;
}
private FaceYItem createItem(Facelet face, int faceIndex, int minY, int maxY,
double minZ, double maxZ) {
Vector3d n = face.normalize();
if(Math.abs(n.z) < 0.0005) return null; //如果面垂直于XOY平面,简单起见放弃该面
FaceYItem item = new FaceYItem();
item.faceIndex = faceIndex;
item.minY = minY;
item.maxY = maxY;
item.a = n.x;
item.b = n.y;
item.c = n.z;
item.minZ = minZ;
item.maxZ = maxZ;
Vector3d v0 = face.getVertex(0);
item.d = -v0.x*n.x-v0.y*n.y-v0.z*n.z;
item.face = face;
item.edgeYBucket = new EdgeYBucket(render, item);
//item.edgeYBucket.compile(); //创建边Y桶
return item;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -