001/* 002 * Renderer 9. 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 seventh rendering pipeline. It converts the 024 transformation stage {@link Model2World} to use {@link Matrix} 025 transformations instead of just using {@link Vector} translations. 026 There are still seven pipeline stages. 027*/ 028public final class Pipeline 029{ 030 // Mostly for compatibility with renderers 1 through 3. 031 public static Color DEFAULT_COLOR = Color.white; 032 033 /** 034 Mutate the {@link FrameBuffer}'s default {@link FrameBuffer.Viewport} 035 so that it holds the rendered image of the {@link Scene} object. 036 037 @param scene {@link Scene} object to render 038 @param fb {@link FrameBuffer} to hold rendered image of the {@link Scene} 039 */ 040 public static void render(final Scene scene, final FrameBuffer fb) 041 { 042 render(scene, fb.vp); // render into the default viewport 043 } 044 045 046 /** 047 Mutate the {@link FrameBuffer}'s given {@link FrameBuffer.Viewport} 048 so that it holds the rendered image of the {@link Scene} object. 049 050 @param scene {@link Scene} object to render 051 @param vp {@link FrameBuffer.Viewport} to hold rendered image of the {@link Scene} 052 */ 053 public static void render(final Scene scene, final FrameBuffer.Viewport vp) 054 { 055 PipelineLogger.debugScene = scene.debug; 056 057 logMessage("\n== Begin Rendering of Scene (Pipeline 1): " + scene.name + " =="); 058 059 logMessage("-- Current Camera:\n" + scene.camera); 060 061 // For every Position in the Scene, render the Position's Model. 062 for (final Position position : scene.positionList) 063 { 064 PipelineLogger.debugPosition = position.debug; 065 066 if ( position.visible ) 067 { 068 logMessage("==== Render position: " + position.name + " ===="); 069 070 logMessage("---- Transformation matrix = " + position.getMatrix()); 071 072 if ( position.getModel().visible ) 073 { 074 logMessage("====== Render model: " 075 + position.getModel().name + " ======"); 076 077 CheckModel.check(position.getModel()); 078 079 // Mostly for compatibility with renderers 1 through 3. 080 if ( position.getModel().colorList.isEmpty() 081 && !position.getModel().vertexList.isEmpty()) 082 { 083 for (int i = 0; i < position.getModel().vertexList.size(); ++i) 084 { 085 position.getModel().addColor( DEFAULT_COLOR ); 086 } 087 System.err.println("***WARNING: Added default color to model: " 088 + position.getModel().name + "."); 089 } 090 091 logVertexList("0. Model ", position.getModel()); 092 093 // 1. Apply the Position's model-to-world coordinate transformation. 094 final Model model1 = Model2World.model2world(position); 095 096 logVertexList("1. World ", model1); 097 098 // 2. Apply the Camera's world-to-view coordinate transformation. 099 final Model model2 = World2View.world2view(model1, 100 scene.camera); 101 102 logVertexList("2. View ", model2); 103 104 // 3. Apply the Camera's normalizing view-to-camera coordinate transformation. 105 final Model model3 = View2Camera.view2camera(model2, 106 scene.camera); 107 108 logVertexList("3. Camera ", model3); 109 logColorList("3. Camera ", model3); 110 logPrimitiveList("3. Camera ", model3); 111 112 // 4. Clip primitives to the camera's near plane. 113 final Model model4 = NearClip.clip(model3, 114 scene.camera); 115 116 logVertexList("4. Near_Clipped", model4); 117 logColorList("4. Near_Clipped", model4); 118 logPrimitiveList("4. Near_Clipped", model4); 119 120 // 5. Apply the Camera's projection transformation. 121 final Model model5 = Projection.project(model4, 122 scene.camera); 123 124 logVertexList("5. Projected ", model5); 125 126 // 6. Clip primitives to the camera's view rectangle. 127 final Model model6 = Clip.clip(model5); 128 129 logVertexList("6. Clipped ", model6); 130 logColorList("6. Clipped ", model6); 131 logPrimitiveList("6. Clipped ", model6); 132 133 // 7. Rasterize every visible primitive into pixels. 134 Rasterize.rasterize(model6, vp); 135 136 logMessage("====== End model: " 137 + position.getModel().name + " ======"); 138 } 139 else 140 { 141 logMessage("====== Hidden model: " 142 + position.getModel().name + " ======"); 143 } 144 145 logMessage("==== End position: " + position.name + " ===="); 146 } 147 else 148 { 149 logMessage("==== Hidden position: " + position.name + " ===="); 150 } 151 } 152 logMessage("== End Rendering of Scene =="); 153 } 154 155 156 157 // Private default constructor to enforce noninstantiable class. 158 // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch. 159 private Pipeline() { 160 throw new AssertionError(); 161 } 162}