📄 polygon3d.java
字号:
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
public class polygon3D{
public vector[] tempVertix;
public vector[] vertix2D;
public vector[] vertix3D;
public int[] vertixSpecular;
public vector[] vertixNormals;
public vector[] temp_vertixNormals;
public static vector[] tempVectors;
public vector normal, realNormal;
public vector centre, realCentre;
public static int[] xLow, xHigh, s_left, s_right, xChange_left, xChange_right;
public int[] xLow_transprent, xHigh_transprent;
public int height;
public int topIndex;
public boolean visible;
public Rectangle bound;
public double zMax, zMin;
public texture myTexture;
public double textureScaleX, textureScaleY;
public vector W, O, V, U, A, B, C;
public double aDotW, bDotW, cDotW;
public double scaleX = 1, scaleY = 1;
public int textureWidth, textureHeight, heightMask, widthMask, widthBits, heightBits;
public int X, Y, X1, Y1, dx, dy, textureIndex;
public int visibleCount;
public vector origin, rightEnd, bottomEnd;
public int L;
public vector view = new vector(0,0,1);
public int end = 0;
public int start = 479;
public boolean isLightMap;
public int[] Texture;
public int Z_length;
public double A_offset, B_offset, C_offset;
public boolean faceVerticalPolygon;
public int BigX, BigY, BigDx, BigDy;
public boolean gouraudShading;
public int diffuse_I;
public int ambient_I;
public int roughness;
public boolean waterSurface;
public polygon3D(vector[] vertix3D, vector origin, vector rightEnd, vector bottomEnd, texture myTexture){
L = vertix3D.length;
Z_length = vector.Z_length;
tempVectors = new vector[4];
for(int i = 0; i < tempVectors.length; i++)
if(tempVectors[i] == null)
tempVectors[i] = new vector();
this.vertix3D = vertix3D;
tempVertix = new vector[L];
for(int i = 0; i < L; i++){
tempVertix[i] = new vector();
tempVertix[i].set(vertix3D[i]);
}
centre = new vector(0,0,0);
testVisibility();
if(Math.abs(normal.y) > 0.99)
faceVerticalPolygon = true;
else
faceVerticalPolygon = false;
realNormal = new vector(0,0,0);
realNormal.set(normal);
realCentre = new vector(0,0,0);
realCentre.set(centre);
this.myTexture = myTexture;
if(myTexture == null)
return;
ambient_I = 60;
findDiffuse();
Texture = myTexture.Texture;
this.origin = origin;
this.rightEnd = rightEnd;
this.bottomEnd = bottomEnd;
textureWidth = myTexture.width;
textureHeight = myTexture.height;
heightMask = myTexture.heightMask;
widthMask = myTexture.widthMask;
widthBits = myTexture.widthBits;
heightBits = myTexture.heightBits;
findTextureScale();
W = new vector(); O = new vector(); V = new vector(); U = new vector(); A = new vector(); B = new vector(); C = new vector();
vertix2D = new vector[L+1];
for(int i = 0; i < vertix2D.length; i++)
vertix2D[i] = new vector(0,0,0);
vertixSpecular = new int[L+1];
temp_vertixNormals = new vector[L+1];
for(int i = 0; i < L+1; i++)
temp_vertixNormals[i] = new vector(0,0,0);
vertixNormals = new vector[L];
for(int i = 0; i < L; i++)
vertixNormals[i] = new vector(0,0,0);
if(xLow == null){
xLow = new int[480];
xHigh = new int[480];
s_left= new int[480];
s_right = new int[480];
xChange_left = new int[480];
xChange_right = new int[480];
}
}
public final void findTextureScale(){
tempVectors[0].set(origin);
tempVectors[0].subtract(rightEnd);
double l = tempVectors[0].getLength();
textureScaleX = l/myTexture.width;
tempVectors[0].set(origin);
tempVectors[0].subtract(bottomEnd);
l = tempVectors[0].getLength();
textureScaleY = l/myTexture.height;
}
public static polygon3D createPolygon(vector[] vertix3D, vector origin, vector rightEnd, vector bottomEnd, texture myTexture, double textureX, double textureY, double scaleX, double scaleY){
vector x = origin.myClone();
x.subtract(rightEnd);
x.scale(textureX);
vector y = origin.myClone();
y.subtract(bottomEnd);
y.scale(textureY);
origin.add(x);
bottomEnd.add(x);
rightEnd.add(x);
origin.add(y);
bottomEnd.add(y);
rightEnd.add(y);
polygon3D p = new polygon3D(vertix3D, origin, rightEnd, bottomEnd, myTexture);
p.scaleX = scaleX;
p.scaleY = scaleY;
return p;
}
public final void update(){
for(int i = 0; i < L; i++){
tempVertix[i].set(vertix3D[i]);
tempVertix[i].subtract(camera.position);
tempVertix[i].rotate_XZ();
tempVertix[i].rotate_YZ();
tempVertix[i].updateLocation();
}
testVisibility();
}
public final void findDiffuse(){
tempVectors[0].set(LightSource.s1_);
tempVectors[0].subtract(realCentre);
tempVectors[0].unit();
double temp = tempVectors[0].dot(realNormal);
if(temp <= -0.5)
diffuse_I = ambient_I;
else
diffuse_I = ambient_I + (int)(128*(temp+0.5));
}
public final void findSpecular(){
if(diffuse_I == ambient_I){
for(int i = 0; i < vertixSpecular.length; i ++)
vertixSpecular[i] = 0;
return;
}
for(int i = 0; i < visibleCount; i++){
tempVectors[2].set(temp_vertixNormals[i]);
tempVectors[2].rotate_XZ();
tempVectors[2].rotate_YZ();
tempVectors[0].set(LightSource.s1);
tempVectors[0].subtract(vertix2D[i]);
tempVectors[0].unit();
tempVectors[1].set(tempVectors[2]);
tempVectors[1].scale(2*tempVectors[0].dot(tempVectors[1]));
tempVectors[0].subtract(tempVectors[1]);
tempVectors[0].scale(-1);
tempVectors[1].set(0,0,0);
tempVectors[1].subtract(vertix2D[i]);
tempVectors[1].unit();
double temp = tempVectors[1].dot(tempVectors[0]);
if(temp < 0)
temp = 0;
else{
for(int j = 0; j < roughness; j++)
temp*=temp;
}
vertixSpecular[i] = (int)(176 * temp) << 16;
}
}
public final void findVectorOUV(){
O.set(origin);
O.subtract(camera.position);
O.rotate_XZ(-camera.look_right);
O.rotate_YZ(camera.look_up);
U.set(rightEnd);
U.subtract(camera.position);
U.rotate_XZ(-camera.look_right);
U.rotate_YZ(camera.look_up);
V.set(bottomEnd);
V.subtract(camera.position);
V.rotate_XZ(-camera.look_right);
V.rotate_YZ(camera.look_up);
U.subtract(O);
U.unit();
U.scale(textureScaleX/scaleX);
V.subtract(O);
V.unit();
V.scale(textureScaleY/scaleY);
A = V.cross(O);
B = O.cross(U);
C = U.cross(V);
}
public final void testVisibility(){
visible = false;
//find normal vector
tempVectors[0].set(tempVertix[1]);
tempVectors[0].subtract(tempVertix[0]);
tempVectors[1].set(tempVertix[2]);
tempVectors[1].subtract(tempVertix[1]);
normal = tempVectors[0].cross(tempVectors[1]);
normal.unit();
//find centre
findCentre();
//test whether all vertix is in front of viwer's plane
for(int i = 0; i < tempVertix.length; i++){
if(tempVertix[i].z > 0){
visible = true;
break;
}
}
//test whether the polygon is within view angle
if(visible){
if(view.dot(normal) >= 0.6)
visible = false;
}
//test whether this polygon is facing toward viewer
if(visible){
tempVectors[0].set(tempVertix[0]);
if(tempVectors[0].dot(normal) >= 0)
visible = false;
}
//test whether this polygon is inside the screen
if(visible){
find_zMax_zMin();
visible = camera.screen.intersects(bound);
}
}
public final void findCentre(){
centre.reset();
for(int i = 0; i < tempVertix.length; i++)
centre.add(tempVertix[i]);
centre.scale(1.0/tempVertix.length);
}
public final void find_zMax_zMin(){
int xMax = tempVertix[0].screenX;
int xMin = xMax;
int yMax = tempVertix[0].screenY;
int yMin = yMax;
zMax = tempVertix[0].z;
zMin = zMax;
for(int i = 1; i < tempVertix.length; i++){
xMax = Math.max(xMax, tempVertix[i].screenX);
xMin = Math.min(xMin, tempVertix[i].screenX);
yMax = Math.max(yMax, tempVertix[i].screenY);
yMin = Math.min(yMin, tempVertix[i].screenY);
zMax = Math.max(zMax, tempVertix[i].z);
zMin = Math.min(zMin, tempVertix[i].z);
}
bound = new Rectangle(xMin, yMin, xMax-xMin, yMax-yMin);
}
public final void findClipping(){
visibleCount = 0;
for(int i = 0; i < L; i++){
if(tempVertix[i].z >= 0.01){
vertix2D[visibleCount].set(tempVertix[i]);
vertix2D[visibleCount].updateLocation();
temp_vertixNormals[visibleCount].set(vertixNormals[i]);
visibleCount++;
} else{
int index = (i+L - 1)%L;
if(tempVertix[index].z >= 0.01){
approximatePoint(visibleCount, tempVertix[i], tempVertix[index]);
temp_vertixNormals[visibleCount].set(vertixNormals[index]);
visibleCount++;
}
index = (i+1)%L;
if(tempVertix[index].z >= 0.01){
approximatePoint(visibleCount, tempVertix[i], tempVertix[index]);
temp_vertixNormals[visibleCount].set(vertixNormals[index]);
visibleCount++;
}
}
}
}
public final void approximatePoint(int index, vector behindPoint, vector frontPoint){
tempVectors[0].set(frontPoint.x - behindPoint.x, frontPoint.y - behindPoint.y, frontPoint.z - behindPoint.z);
tempVectors[0].scale(frontPoint.z/tempVectors[0].z);
vertix2D[index].set(frontPoint.x, frontPoint.y, frontPoint.z);
vertix2D[index].subtract(tempVectors[0]);
vertix2D[index].add(0,0,0.01);
vertix2D[index].updateLocation();
}
public final void scanPolygon(){
int minX = 0;
int maxX = 639;
int minY = 0;
int maxY = 479;
start = 479;
end = 0;
double temp_ = 0;
for(int i = 0; i < visibleCount; i++){
vector v1 = vertix2D[i];
int s1 = vertixSpecular[i];
vector v2;
int s2;
if(i == visibleCount -1 ){
v2 = vertix2D[0];
s2 = vertixSpecular[0];
}else{
v2 = vertix2D[i+1];
s2 = vertixSpecular[i+1];
}
boolean downwards = false;
//ensure v1.y < v2.y;
if (v1.screenY> v2.screenY) {
downwards = true;
vector temp = v1;
int temp1 = s1;
v1 = v2;
s1 = s2;
v2 = temp;
s2 = temp1;
}
int dy = v2.screenY - v1.screenY;
// ignore horizontal lines
if (dy == 0) {
continue;
}
int ds = (s2 - s1)/dy;
int startY = Math.max(v1.screenY, minY);
int endY = Math.min(v2.screenY, maxY);
int startS = s1 + (startY - v1.screenY) * ds;
if(startY < start )
start = startY;
if(endY > end)
end = endY;
double dx = v2.screenX - v1.screenX;
double gradient = dx / dy;
int temp_x, x;
temp_ = v1.screenX + (startY - v1.screenY) * gradient;
// scan-convert this edge (line equation)
for (int y=startY, s=startS; y<=endY; y++, s+=ds) {
temp_x = ceil(temp_);
temp_+=gradient;
// ensure x within view bounds
x = Math.min(maxX+1, Math.max(temp_x, minX));
if(downwards){
xLow[y] = x;
s_left[y] = s;
xChange_left[y] = x - temp_x;
}else{
xHigh[y] = x;
s_right[y] = s;
xChange_right[y] = x - temp_x;
}
}
}
int ds, l;
for(int i = start; i <= end; i++){
l = (xHigh[i] - xChange_right[i]) - (xLow[i] - xChange_left[i]);
if(l == 0)
continue;
ds = (s_right[i] - s_left[i])/l;
s_left[i] = s_left[i] + xChange_left[i]*ds;
s_right[i] = s_right[i] + xChange_right[i]*ds;
}
}
public final int ceil(double f) {
if (f > 0) {
return (int)f + 1;
}
else {
return (int)f;
}
}
public final void drawTransparent(){
if(!visible)
return;
int texel = 0;
int r = 0;
int g = 0;
int b = 0;
int temp = 0;
int theIndex = 0;
int i = 0;
int j = 0;
int k = 0;
double length = centre.getLength();
if(length > 10){
int scale = 2;
if(length > 25)
scale = 3;
double cDotWInverse;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -