已知:
v = (-1, -1, -1)(歸一化後)。y = 0),法向量 n = (0, 1, 0),過原點。P = (x₀, y₀, z₀)。光線參數方程:P + t·v。與平面 y = 0 交點:
y₀ + t·v.y = 0 → t = -y₀ / v.y
投影座標:
x = x₀ + v.x * (-y₀ / v.y)
z = z₀ + v.z * (-y₀ / v.y)
代碼中簡化為 shadow.set(vertex.x - (vertex.y - height), height + 0.0001f, vertex.z - (vertex.y - height)),其中 height = -0.5f 為地面 Y 座標,0.0001f 偏移避免 Z-fighting。
import java.applet.Applet;
import java.awt.BorderLayout;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class SimpleShadow extends Applet {
// 三角形平面(可見物體)
public class TriPlane extends Shape3D {
public TriPlane(Point3f A, Point3f B, Point3f C) {
setGeometry(createGeometry3(A,B,C));
setAppearance(createAppearance());
}
private Geometry createGeometry3(Point3f A, Point3f B, Point3f C) {
TriangleArray ta = new TriangleArray(3,
GeometryArray.COORDINATES | GeometryArray.NORMALS);
ta.setCoordinate(0, A); ta.setCoordinate(1, B); ta.setCoordinate(2, C);
Vector3f a = new Vector3f(A.x-B.x, A.y-B.y, A.z-B.z);
Vector3f b = new Vector3f(C.x-B.x, C.y-B.y, C.z-B.z);
Vector3f n = new Vector3f(); n.cross(b, a); n.normalize();
ta.setNormal(0, n); ta.setNormal(1, n); ta.setNormal(2, n);
return ta;
}
private Appearance createAppearance() {
Appearance ap = new Appearance();
ap.setMaterial(new Material());
return ap;
}
}
// 四邊形平面(地面/投影面)
public class QuadPlane extends Shape3D {
public QuadPlane(Point3f A, Point3f B, Point3f C, Point3f D) {
setGeometry(createGeometry4(A,B,C,D));
setAppearance(createAppearance());
}
private Geometry createGeometry4(Point3f A, Point3f B, Point3f C, Point3f D) {
QuadArray qa = new QuadArray(4,
GeometryArray.COORDINATES | GeometryArray.NORMALS);
qa.setCoordinate(0, A); qa.setCoordinate(1, B);
qa.setCoordinate(2, C); qa.setCoordinate(3, D);
Vector3f a = new Vector3f(A.x-B.x, A.y-B.y, A.z-B.z);
Vector3f b = new Vector3f(C.x-B.x, C.y-B.y, C.z-B.z);
Vector3f n = new Vector3f(); n.cross(b, a); n.normalize();
for (int i=0;i<4;i++) qa.setNormal(i, n);
return qa;
}
private Appearance createAppearance() {
Appearance ap = new Appearance();
ap.setMaterial(new Material());
return ap;
}
}
// 陰影幾何體生成
public class Shadow3D extends Shape3D {
public Shadow3D(GeometryArray geom, Vector3f dir, Color3f color, float groundY) {
int vCount = geom.getVertexCount();
TriangleArray shadowGeom = new TriangleArray(vCount,
GeometryArray.COORDINATES | GeometryArray.COLOR_3);
Point3f vertex = new Point3f();
Point3f shadow = new Point3f();
for (int i=0; i
| 技術點 | 實現細節 |
|---|---|
| 幾何體建模 | TriangleArray/QuadArray + COORDINATES|NORMALS 支援光照 |
| 法向量計算 | 叉積 b × a → 歸一化,決定光照明暗 |
| Material 元件 | 必須設定 Appearance.setMaterial() 否則光照無效果 |
| 平行光 | DirectionalLight + 歸一化方向向量 |
| 陰影生成 | CPU 端逐頂點投影計算,生成新 TriangleArray,顏色設為深灰 |
| Z-fighting 避免 | 陰影 Y 座標 groundY + 0.0001f 微量抬高 |