-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTriangle.java
More file actions
330 lines (266 loc) · 10.9 KB
/
Triangle.java
File metadata and controls
330 lines (266 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
import java.util.ArrayList;
import java.util.List;
import java.awt.Color;
import java.awt.Polygon;
public class Triangle {
private Vertex3D v1;
private Vertex3D v2;
private Vertex3D v3;
private Vertex3D newV1;
private Vertex3D newV2;
private Vertex3D newV3;
private Vertex3D newV4;
private UV uv1;
private UV uv2;
private UV uv3;
private Normal triangleNormal;
private Vertex2D p1;
private Vertex2D p2;
private Vertex2D p3;
private Vertex2D p4;
private Texture texture;
private float colorIntensity;
private double depthFromCamera;
private int numVertices = 3;
private boolean isValid = true;
public Triangle (Vertex3D v1, Vertex3D v2, Vertex3D v3, UV uv1, UV uv2, UV uv3, Normal normal1, Normal normal2, Normal normal3, int materialIndex) {
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.uv1 = uv1;
this.uv2 = uv2;
this.uv3 = uv3;
this.newV1 = new Vertex3D(0, 0, 0);
this.newV2 = new Vertex3D(0, 0, 0);
this.newV3 = new Vertex3D(0, 0, 0);
this.newV4 = new Vertex3D(0, 0, 0);
this.triangleNormal = normal1.averageNormals(normal2, normal3);
this.texture = GamePanel.texturess.getTexture(materialIndex-1);
computeShade();
}
public void update() {
this.isValid = true;
this.numVertices = 3;
newV1.setUV(this.uv1);
newV2.setUV(this.uv2);
newV3.setUV(this.uv3);
this.newV1.setNewCords(v1.getNewX(), v1.getNewY(), v1.getNewZ(), this.newV1.getUV());
this.newV2.setNewCords(v2.getNewX(), v2.getNewY(), v2.getNewZ(), this.newV2.getUV());
this.newV3.setNewCords(v3.getNewX(), v3.getNewY(), v3.getNewZ(), this.newV3.getUV());
backfaceCulling();
checkClipping();
if (this.isValid) {
calculateDepthFromCamera();
projectToScreen();
}
}
public void projectToScreen() {
p1 = newV1.castToScreen();
p2 = newV2.castToScreen();
p3 = newV3.castToScreen();
p4 = newV4.castToScreen();
}
private void checkClipping() {
// list of vertices behind the clipping plane
int behindCount = 0;
Vertex3D[] behind = new Vertex3D[3];
// list of vertices in front of the clipping plane
int inFrontCount = 0;
Vertex3D[] inFront = new Vertex3D[3];
// classify the vertices into front and back of the clipping plane
if (this.newV1.getNewX() <= GamePanel.NEAR_PLANE_X) behind[behindCount++] = this.newV1; else inFront[inFrontCount++] = this.newV1;
if (this.newV2.getNewX() <= GamePanel.NEAR_PLANE_X) behind[behindCount++] = this.newV2; else inFront[inFrontCount++] = this.newV2;
if (this.newV3.getNewX() <= GamePanel.NEAR_PLANE_X) behind[behindCount++] = this.newV3; else inFront[inFrontCount++] = this.newV3;
// handle cases
if (behindCount == 0) {
// all vertices in front, draw the triangle as-is
} else if (behindCount == 1) {
// one vertex behind, clip into two triangles
// interpolate the vertices to the clipping plane to create a quad
Vertex3D P1 = interpolate(behind[0], inFront[0], GamePanel.NEAR_PLANE_X);
Vertex3D P2 = interpolate(behind[0], inFront[1], GamePanel.NEAR_PLANE_X);
this.newV1.setNewCords(inFront[0].getNewX(), inFront[0].getNewY(), inFront[0].getNewZ(), inFront[0].getUV());
this.newV2.setNewCords(inFront[1].getNewX(), inFront[1].getNewY(), inFront[1].getNewZ(), inFront[1].getUV());
this.newV3.setNewCords(P2.getX(), P2.getY(), P2.getZ(), P2.getUV());
this.newV4.setNewCords(P1.getX(), P1.getY(), P1.getZ(), P1.getUV());
this.numVertices = 4;
} else if (behindCount == 2) {
// two vertices behind the clipping plane
// interpolate the vertices to the clipping plane to create a quad
// create
Vertex3D P1 = interpolate(behind[0], inFront[0], GamePanel.NEAR_PLANE_X);
Vertex3D P2 = interpolate(behind[1], inFront[0], GamePanel.NEAR_PLANE_X);
this.newV1.setNewCords(inFront[0].getNewX(), inFront[0].getNewY(), inFront[0].getNewZ(), inFront[0].getUV());
this.newV2.setNewCords(P2.getX(), P2.getY(), P2.getZ(), P2.getUV());
this.newV3.setNewCords(P1.getX(), P1.getY(), P1.getZ(), P1.getUV());
} else {
// all vertices behind the clipping plane
// discard triangle
this.isValid = false;
}
}
// finds the intersection point between a vertex and the clipping plane
private Vertex3D interpolate(Vertex3D from, Vertex3D to, float nearPlaneX) {
// calculate the interpolation factor
float t = (nearPlaneX - from.getNewX()) / (to.getNewX() - from.getNewX());
// calculate the new x y z coordinates
float newY = from.getNewY() + t * (to.getNewY() - from.getNewY());
float newZ = from.getNewZ() + t * (to.getNewZ() - from.getNewZ());
// calculate the new u v coordinates
float newU = from.getUV().getU() + t * (to.getUV().getU() - from.getUV().getU());
float newV = from.getUV().getV() + t * (to.getUV().getV() - from.getUV().getV());
return new Vertex3D(nearPlaneX, newY, newZ, newU, newV);
}
private void calculateDepthFromCamera() {
double distance1 = distanceToCamera(newV1);
double distance2 = distanceToCamera(newV2);
double distance3 = distanceToCamera(newV3);
this.depthFromCamera = Math.max(distance1, Math.max(distance2, distance3));
}
private double distanceToCamera(Vertex3D v) {
double x = v.getNewX();
double y = v.getNewY();
double z = v.getNewZ();
return Math.sqrt(x * x + y * y + z * z);
}
private void backfaceCulling() {
// Calculate vectors from v1 to v2 and v1 to v3
float vectorAX = v2.getNewX() - v1.getNewX();
float vectorAY = v2.getNewY() - v1.getNewY();
float vectorAZ = v2.getNewZ() - v1.getNewZ();
float vectorBX = v3.getNewX() - v1.getNewX();
float vectorBY = v3.getNewY() - v1.getNewY();
float vectorBZ = v3.getNewZ() - v1.getNewZ();
// Calculate the normal of the triangle using the cross product
float normalX = vectorAY * vectorBZ - vectorAZ * vectorBY;
float normalY = vectorAZ * vectorBX - vectorAX * vectorBZ;
float normalZ = vectorAX * vectorBY - vectorAY * vectorBX;
// Calculate the vector from the camera to the triangle
float viewVectorX = v1.getNewX();
float viewVectorY = v1.getNewY();
float viewVectorZ = v1.getNewZ();
// Calculate the dot product of the normal and the view vector
float dotProduct = normalX * viewVectorX + normalY * viewVectorY + normalZ * viewVectorZ;
// If the dot product is positive, the triangle is facing away from the camera
if (dotProduct < 0) {
this.isValid = false;
}
}
private void computeShade() {
float ambientLight = 0.8f; // Increase ambient light to make everything brighter
// Light intensities for each axis
float lightIntensityX = 1.2f; // Increase light intensity
float lightIntensityY = 1.5f; // Increase light intensity
float lightIntensityZ = 1.3f; // Increase light intensity
// Light directions for each axis
float lightX = 1;
float lightY = 1;
float lightZ = 1;
// Normalize the light directions
float lengthX = (float)Math.sqrt(lightX * lightX);
float lengthY = (float)Math.sqrt(lightY * lightY);
float lengthZ = (float)Math.sqrt(lightZ * lightZ);
lightX /= lengthX;
lightY /= lengthY;
lightZ /= lengthZ;
// Calculate the dot product of the normal and the light directions
float dotProductX = triangleNormal.getX() * lightX;
float dotProductY = triangleNormal.getY() * lightY;
float dotProductZ = triangleNormal.getZ() * lightZ;
// Calculate the final intensity for each axis
float intensityX = Math.max(ambientLight, lightIntensityX * dotProductX);
float intensityY = Math.max(ambientLight, lightIntensityY * dotProductY);
float intensityZ = Math.max(ambientLight, lightIntensityZ * dotProductZ);
// Average the intensities
this.colorIntensity = (intensityX + intensityY + intensityZ) / 3;
this.colorIntensity = Math.min(this.colorIntensity, 1);
}
// getters and setters
public int getNumberOfVertices() {
return numVertices;
}
public Polygon toPolygon() {
int[] xPoints = {(int)this.p1.getX(), (int)this.p2.getX(), (int)this.p3.getX()};
int[] yPoints = {(int)this.p1.getY(), (int)this.p2.getY(), (int)this.p3.getY()};
Polygon p = new Polygon(xPoints, yPoints, 3);
return p;
}
public int[] xPoints() {
if (this.getNumberOfVertices() == 3) {
int[] xPoints = {(int)this.p1.getX(), (int)this.p2.getX(), (int)this.p3.getX()};
return xPoints;
} else {
int[] xPoints = {(int)this.p1.getX(), (int)this.p2.getX(), (int)this.p3.getX(), (int)this.p4.getX()};
return xPoints;
}
}
public int[] yPoints() {
if (this.getNumberOfVertices() == 3) {
int[] yPoints = {(int)this.p1.getY(), (int)this.p2.getY(), (int)this.p3.getY()};
return yPoints;
} else {
int[] yPoints = {(int)this.p1.getY(), (int)this.p2.getY(), (int)this.p3.getY(), (int)this.p4.getY()};
return yPoints;
}
}
public Vertex3D getV1() {
return this.v1;
}
public Vertex3D getV2() {
return this.v2;
}
public Vertex3D getV3() {
return this.v3;
}
public UV getUV1() {
return this.newV1.getUV();
}
public UV getUV2() {
return this.newV2.getUV();
}
public UV getUV3() {
return this.newV3.getUV();
}
public UV getUV4() {
return this.newV4.getUV();
}
public Vertex3D getNewV1() {
return this.newV1;
}
public Vertex3D getNewV2() {
return this.newV2;
}
public Vertex3D getNewV3() {
return this.newV3;
}
public Vertex3D getNewV4() {
return this.newV4;
}
public Vertex2D getP1() {
return this.p1;
}
public Vertex2D getP2() {
return this.p2;
}
public Vertex2D getP3() {
return this.p3;
}
public Vertex2D getP4() {
return this.p4;
}
public double getDepthFromCamera() {
return this.depthFromCamera;
}
public Texture gTexture() {
return this.texture;
}
public float getColorIntensity() {
return this.colorIntensity;
}
public boolean isValid() {
return this.isValid;
}
public Normal getNormal() {
return this.triangleNormal;
}
}