001/* 002 * Renderer 7. The MIT License. 003 * Copyright (c) 2022 rlkraft@pnw.edu 004 * See LICENSE for details. 005*/ 006 007package renderer.pipeline; 008 009import renderer.scene.*; 010import renderer.scene.primitives.*; 011import static renderer.pipeline.PipelineLogger.*; 012 013import java.util.List; 014import java.util.ArrayList; 015import java.util.Optional; 016 017/** 018 Clip in camera space any {@link Primitive} that crosses 019 the camera's near clipping plane {@code z = -near}. 020*/ 021public class NearClip 022{ 023 public static boolean doNearClipping = true; 024 public static boolean debug = false; 025 026 /** 027 Start with a {@link Model} that contains {@link Primitive}s 028 that have been transformed into camera space. 029 <p> 030 If a transformed {@link Primitive} crosses the camera's 031 near plane, then replace that {@link Primitive}, in the 032 {@link Model}'s list of primitives, with one that has been 033 clipped so that it lies completely in the far side of the 034 camera's near plane (the side of the near plane away from 035 the camera). 036 <p> 037 If a transformed {@link Primitive} is completely in the 038 camera side of the near plane, then drop that 039 {@link Primitive} from the {@link Model}'s list of primitives. 040 <p> 041 Return a {@link Model} for which every {@link Primitive} is 042 completely on the far side of the camera's near plane. 043 044 @param model {@link Model} containing {@link Primitive}s transformed into camera space 045 @param camera {@link Camera} that determines the near clipping plane 046 @return a {@link Model} containing {@link Primitive}s clipped to the camera's near plane 047 */ 048 public static Model clip(final Model model, final Camera camera) 049 { 050 if (! doNearClipping) 051 { 052 return model; 053 } 054 055 // Replace the model's list of colors with a shallow copy. 056 final Model model2 = new Model(model.vertexList, 057 model.primitiveList, 058 new ArrayList<>(model.colorList), 059 model.name, 060 model.visible); 061 062 final List<Primitive> newPrimitiveList = new ArrayList<>(); 063 064 for (final Primitive p : model2.primitiveList) 065 { 066 logPrimitive("3. Near_Clipping", model2, p); 067 068 final Optional<Primitive> p_clipped = 069 (p instanceof LineSegment) 070 ? NearClip_Line.clip(model2, (LineSegment)p, camera) 071 : NearClip_Point.clip(model2, (Point)p, camera); 072 073 if ( p_clipped.isPresent() ) 074 { 075 // Keep the primitives that are visible. 076 newPrimitiveList.add( p_clipped.get() ); 077 logPrimitive("3. Near_Clipped (accept)", model2, p_clipped.get()); 078 } 079 else 080 { 081 // Discard the primitives that are not visible. 082 logPrimitive("3. Near_Clipped (reject)", model2, p); 083 } 084 } 085 086 // Replace the model's original list of line segments 087 // with the list of clipped line segments. 088 return new Model(model2.vertexList, // has been updated with clipped vertices 089 newPrimitiveList, // clipped primitives 090 model2.colorList, // has been updated with interpolated colors 091 model2.name, 092 model2.visible); 093 } 094 095 096 097 // Private default constructor to enforce noninstantiable class. 098 // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch. 099 private NearClip() { 100 throw new AssertionError(); 101 } 102}