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*/ 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: " + 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("---- Translation vector = " + position.getTranslation()); 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-camera coordinate transformation. 094 final Model model1 = Model2Camera.model2camera(position); 095 096 logVertexList("1. Camera ", model1); 097 098 // 2. Apply the Camera's projection transformation. 099 final Model model2 = Projection.project(model1, 100 scene.camera); 101 102 logVertexList("2. Projected ", model2); 103 104 // 3. Apply the image-plane to pixel-plane transformation. 105 final Model model3 = Viewport.imagePlane2pixelPlane(model2, 106 vp); 107 108 logVertexList("3. Pixel-plane", model3); 109 logPrimitiveList("3. Pixel-plane", model3); 110 logColorList("3. Pixel-plane", model3); 111 112 // 4. Rasterize and clip every visible primitive into pixels. 113 Rasterize.rasterize(model3, vp); 114 115 logMessage("====== End model: " 116 + position.getModel().name + " ======"); 117 } 118 else 119 { 120 logMessage("====== Hidden model: " 121 + position.getModel().name + " ======"); 122 } 123 124 logMessage("==== End position: " + position.name + " ===="); 125 } 126 else 127 { 128 logMessage("==== Hidden position: " + position.name + " ===="); 129 } 130 } 131 logMessage("== End Rendering of Scene =="); 132 } 133 134 135 136 // Private default constructor to enforce noninstantiable class. 137 // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch. 138 private Pipeline() { 139 throw new AssertionError(); 140 } 141}