package framework.view3D; import java.util.ArrayList; import java.util.Enumeration; import javax.media.j3d.Appearance; import javax.media.j3d.DirectionalLight; import javax.media.j3d.DistanceLOD; import javax.media.j3d.Geometry; import javax.media.j3d.GraphicsContext3D; import javax.media.j3d.LOD; import javax.media.j3d.Light; import javax.media.j3d.Node; import javax.media.j3d.Shape3D; import javax.media.j3d.Transform3D; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3d; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.geometry.Cylinder; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.geometry.Sphere; import framework.model3D.BackgroundBox; import framework.model3D.BaseObject3D; import framework.model3D.BumpMapGenerator; import framework.model3D.FresnelsReflectionMapGenerator; import framework.model3D.IViewer3D; import framework.model3D.Object3D; import framework.model3D.ReflectionMapGenerator; public class Viewer3D implements IViewer3D { GraphicsContext3D graphicsContext3D = null; ReflectionMapShader reflectionMappingShader = null; FresnelsReflectionMapShader fresnelsReflectionMappingShader = null; Dot3BumpMapShader dot3BumpMappingShader = null; FlatDot3BumpMapShader flatDot3BumpMappingShader = null; ArrayList<Light> lights = null; BackgroundBox skyBox = null; Camera3D camera = null; // 以下は省メモリ化のため導入 static private Point3f center = new Point3f(); static private Point3f origin = new Point3f(); public Viewer3D(Camera3D camera) { this.camera = camera; reflectionMappingShader = new ReflectionMapShader(); fresnelsReflectionMappingShader = new FresnelsReflectionMapShader(); dot3BumpMappingShader = new Dot3BumpMapShader(); flatDot3BumpMappingShader = new FlatDot3BumpMapShader(); } @Override public void setGraphicsContext3D(GraphicsContext3D graphicsContext3D) { this.graphicsContext3D = graphicsContext3D; } @Override public void update(ArrayList<Light> lights, BackgroundBox skyBox) { // 光源の更新 if (this.lights != lights) { this.lights = lights; for (int n = 0; n < lights.size(); n++) { if (lights.get(n) instanceof DirectionalLight) { // 平行光源の場合 DirectionalLight dirlight = (DirectionalLight)lights.get(n); dot3BumpMappingShader.init(dirlight); flatDot3BumpMappingShader.init(dirlight); break; } } } // スカイボックスの更新 if (this.skyBox != skyBox) { this.skyBox = skyBox; reflectionMappingShader.init(skyBox); fresnelsReflectionMappingShader.init(skyBox); } } public void draw(BaseObject3D obj) { // GraphicsContext3D 内の光源の更新 if (lights != null && lights.size() != graphicsContext3D.numLights()) { for (int n = 0; n < lights.size(); n++) { graphicsContext3D.addLight(lights.get(n)); } } Enumeration<Node> primitives = obj.getPrimitiveNodes(); ReflectionMapGenerator reflectionMapGenerator = obj.getReflectionMappingInfo(); BumpMapGenerator bumpMapGenerator = obj.getBumpMappingInfo(); int n = 0; while (primitives.hasMoreElements()) { if (obj instanceof Object3D && ((Object3D)obj).isLODSet()) { // LOD の判定 LOD lodNode = ((Object3D)obj).getLOD(); if (lodNode instanceof DistanceLOD) { double nearSide = 0.0; double farSide = 0.0; DistanceLOD distanceLOD = ((DistanceLOD)lodNode); if (n > distanceLOD.numDistances()) break; if (n > 0) nearSide = distanceLOD.getDistance(n - 1); if (n < distanceLOD.numDistances()) farSide = distanceLOD.getDistance(n); distanceLOD.getPosition(center); Transform3D trans = new Transform3D(); graphicsContext3D.getModelTransform(trans); trans.transform(center); // オブジェクトの中心座標(世界座標上) trans = camera.getWorldToView(); trans.transform(center); // オブジェクトの中心座標(カメラ座標上) double distance = (double)center.distance(origin); if (distance < nearSide) { break; } else if (distance > farSide && n < distanceLOD.numDistances()) { n++; continue; } } } Node primitive = primitives.nextElement(); if (primitive instanceof Shape3D) { // Shape3Dをレンダリング Appearance ap = ((Shape3D)primitive).getAppearance(); if (bumpMapGenerator != null) { // obj にはバンプマッピングが設定されている if (!bumpMapGenerator.isHorizontal()) { dot3BumpMappingShader.updateAppearance(ap, bumpMapGenerator, camera); } else { // 水平のポリゴンに対しては、よりテクスチャユニットの消費量が少ない FlatDot3BumpMapShader を使う flatDot3BumpMappingShader.updateAppearance(ap, bumpMapGenerator, camera); } } if (reflectionMapGenerator != null) { // obj には反射マッピングが設定されている if (reflectionMapGenerator instanceof FresnelsReflectionMapGenerator) { // フレネル反射を使用 fresnelsReflectionMappingShader.updateAppearance(ap, (FresnelsReflectionMapGenerator)reflectionMapGenerator, camera); } else { reflectionMappingShader.updateAppearance(ap, reflectionMapGenerator, camera); } } if (((Shape3D)primitive).getGeometry() != null) { graphicsContext3D.draw((Shape3D)primitive); } } else if (primitive instanceof Primitive) { Appearance ap = ((Primitive)primitive).getAppearance(); if (bumpMapGenerator != null) { // obj にはバンプマッピングが設定されている if (!bumpMapGenerator.isHorizontal()) { dot3BumpMappingShader.updateAppearance(ap, bumpMapGenerator, camera); } else { // 水平のポリゴンに対しては、よりテクスチャユニットの消費量が少ない FlatDot3BumpMapShader を使う flatDot3BumpMappingShader.updateAppearance(ap, bumpMapGenerator, camera); } } if (reflectionMapGenerator != null) { // obj には反射マッピングが設定されている if (reflectionMapGenerator instanceof FresnelsReflectionMapGenerator) { // フレネル反射を使用 fresnelsReflectionMappingShader.updateAppearance(ap, (FresnelsReflectionMapGenerator)reflectionMapGenerator, camera); } else { reflectionMappingShader.updateAppearance(ap, reflectionMapGenerator, camera); } } graphicsContext3D.setAppearance(ap); if (primitive instanceof Cone) { // Coneをレンダリング Geometry g = ((Cone)primitive).getShape(Cone.BODY).getGeometry(); graphicsContext3D.draw(g); g = ((Cone)primitive).getShape(Cone.CAP).getGeometry(); graphicsContext3D.draw(g); } else if (primitive instanceof Cylinder) { // Cylinderをレンダリング Geometry g = ((Cylinder)primitive).getShape(Cylinder.BODY).getGeometry(); graphicsContext3D.draw(g); g = ((Cylinder)primitive).getShape(Cylinder.TOP).getGeometry(); graphicsContext3D.draw(g); g = ((Cylinder)primitive).getShape(Cylinder.BOTTOM).getGeometry(); graphicsContext3D.draw(g); } else if (primitive instanceof Box) { // Boxをレンダリング Geometry g = ((Box)primitive).getShape(Box.TOP).getGeometry(); graphicsContext3D.draw(g); g = ((Box)primitive).getShape(Box.BOTTOM).getGeometry(); graphicsContext3D.draw(g); g = ((Box)primitive).getShape(Box.FRONT).getGeometry(); graphicsContext3D.draw(g); g = ((Box)primitive).getShape(Box.BACK).getGeometry(); graphicsContext3D.draw(g); g = ((Box)primitive).getShape(Box.LEFT).getGeometry(); graphicsContext3D.draw(g); g = ((Box)primitive).getShape(Box.RIGHT).getGeometry(); graphicsContext3D.draw(g); } else if (primitive instanceof Sphere) { // Sphereをレンダリング Geometry g = ((Sphere)primitive).getShape().getGeometry(); graphicsContext3D.draw(g); } } n++; } } @Override public void setModelTransform(Transform3D t) { graphicsContext3D.setModelTransform(t); } }