001/* 002 * Renderer 4. 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.util.CheckModel; 011import renderer.framebuffer.*; 012import static renderer.pipeline.PipelineLogger.*; 013 014import java.awt.Color; 015 016/** 017 This renderer takes as its input a {@link Scene} data structure 018 and a {@link FrameBuffer.Viewport} within a {@link FrameBuffer} 019 data structure. This renderer mutates the {@link FrameBuffer.Viewport} 020 so that it is filled in with the rendered image of the geometric 021 scene represented by the {@link Scene} object. 022<p> 023 This implements our third rendering pipeline. This pipeline can 024 process the colors stored in each {@link Model}. This renderer 025 has the same four pipeline stages but {@link Vertex} colors 026 are now interpolated to pixels by the raterization stage. 027<p> 028 This second version of the rendering pipeline does each stage 029 of the pipeline on the entire scene before it moves on to the 030 next stage. So each stage of the pipeline produces a new Scene 031 object that is the transformation of the Scene object from the 032 previous stage. 033*/ 034public final class Pipeline2 035{ 036 // Mostly for compatibility with renderers 1 through 3. 037 public static Color DEFAULT_COLOR = Color.white; 038 039 // Make the three intermediate Scene objects 040 // available for special processing. 041 public static Scene scene1 = null; // Will hold the result of stage 1. 042 public static Scene scene2 = null; // Will hold the result of stage 2. 043 public static Scene scene3 = null; // Will hold the result of stage 3. 044 045 /** 046 Mutate the {@link FrameBuffer}'s default {@link FrameBuffer.Viewport} 047 so that it holds the rendered image of the {@link Scene} object. 048 049 @param scene {@link Scene} object to render 050 @param fb {@link FrameBuffer} to hold rendered image of the {@link Scene} 051 */ 052 public static void render(final Scene scene, final FrameBuffer fb) 053 { 054 render(scene, fb.vp); // render into the default viewport 055 } 056 057 058 /** 059 Mutate the {@link FrameBuffer}'s given {@link FrameBuffer.Viewport} 060 so that it holds the rendered image of the {@link Scene} object. 061 062 @param scene {@link Scene} object to render 063 @param vp {@link FrameBuffer.Viewport} to hold rendered image of the {@link Scene} 064 */ 065 public static void render(final Scene scene, final FrameBuffer.Viewport vp) 066 { 067 PipelineLogger.debugScene = scene.debug; 068 069 logMessage("\n== Begin Rendering of Scene (Pipeline 2): " + scene.name + " ="); 070 071 logMessage("-- Current Camera:\n" + scene.camera); 072 073 // 1. Apply each Position's model-to-camera coordinate transformation. 074 scene1 = new Scene(scene.name, scene.camera); 075 076 logMessage("=== 1. Begin model-to-camera transformation of Scene ===="); 077 for (final Position position : scene.positionList) 078 { 079 PipelineLogger.debugPosition = position.debug; 080 081 if ( position.visible ) 082 { 083 logMessage("===== 1. Render position: " + position.name + " ===="); 084 085 logMessage("----- Translation vector = " + position.getTranslation()); 086 087 if ( position.getModel().visible ) 088 { 089 logMessage("===== 1. Model-to-camera transform of: " 090 + position.getModel().name + " ===="); 091 092 CheckModel.check(position.getModel()); 093 094 // Mostly for compatibility with renderers 1 through 3. 095 if ( position.getModel().colorList.isEmpty() 096 && !position.getModel().vertexList.isEmpty()) 097 { 098 for (int i = 0; i < position.getModel().vertexList.size(); ++i) 099 { 100 position.getModel().addColor( DEFAULT_COLOR ); 101 } 102 System.err.println("***WARNING: Added default color to model: " 103 + position.getModel().name + "."); 104 } 105 106 logVertexList("0. Model ", position.getModel()); 107 108 final Model tempModel = Model2Camera.model2camera(position); 109 110 logVertexList("1. Camera ", tempModel); 111 112 scene1.addPosition( new Position(tempModel) ); 113 114 logMessage("===== 1. End Model: " 115 + tempModel.name + " ===="); 116 } 117 else 118 { 119 logMessage("===== 1. Hidden model: " 120 + position.getModel().name + " ===="); 121 } 122 123 logMessage("===== 1. End position: " 124 + position.name + " ===="); 125 } 126 else 127 { 128 logMessage("===== 1. Hidden position: " 129 + position.name + " ===="); 130 } 131 } 132 logMessage("=== 1. End model-to-camera transformation of Scene ===="); 133 134 135 // 2. Apply the Camera's projection transformation. 136 scene2 = new Scene(scene.name, scene.camera); 137 138 logMessage("=== 2. Begin projection transformation of Scene ===="); 139 for (final Position position : scene1.positionList) 140 { 141 logMessage("===== 2. Project model: " 142 + position.getModel().name + " ===="); 143 144 final Model tempModel = Projection.project(position.getModel(), 145 scene.camera); 146 147 logVertexList("2. Projected", tempModel); 148 logPrimitiveList("2. Projected ", tempModel); 149 150 scene2.addPosition( new Position(tempModel) ); 151 152 logMessage("===== 2. End Model: " + tempModel.name + " ===="); 153 } 154 logMessage("=== 2. End projection transformation of Scene ===="); 155 156 157 // 3. Apply the image-plane to pixel-plane transformation. 158 scene3 = new Scene(scene.name, scene.camera); 159 160 logMessage("=== 3. Begin image-plane to pixel-plane transformation of Scene ===="); 161 for (final Position position : scene2.positionList) 162 { 163 logMessage("===== 3. Transform model: " 164 + position.getModel().name + " ===="); 165 166 final Model tempModel = Viewport.imagePlane2pixelPlane(position.getModel(), 167 vp); 168 169 logVertexList("3. Pixel-plane", tempModel); 170 logPrimitiveList("3. Pixel-plane ", tempModel); 171 172 scene3.addPosition( new Position(tempModel) ); 173 174 logMessage("===== 3. End Model: " + tempModel.name + " ===="); 175 } 176 logMessage("=== 3. End image-plane to pixel-plane transformation of Scene ===="); 177 178 179 // 4. Rasterize and clip every visible primitive into pixels. 180 logMessage("=== 4. Begin rasterization of Scene ===="); 181 for (final Position position : scene3.positionList) 182 { 183 logMessage("===== 4. Rasterize model: " 184 + position.getModel().name + " ===="); 185 186 Rasterize.rasterize(position.getModel(), vp); 187 188 logMessage("===== 4. End Model: " 189 + position.getModel().name + " ===="); 190 } 191 logMessage("=== 4. End rasterization of Scene ===="); 192 193 logMessage("== End Rendering of Scene (Pipeline 2) =="); 194 } 195 196 197 198 // Private default constructor to enforce noninstantiable class. 199 // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch. 200 private Pipeline2() { 201 throw new AssertionError(); 202 } 203}