Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
renderpass [2020/01/09 14:23] – [How to use] adminrenderpass [Unknown date] (current) – removed - external edit (Unknown date) 127.0.0.1
Line 1: Line 1:
-====== Renderpasses ====== 
  
-In the simplest rendering pipeline you have one rendering loop, where all scene elements are drawn.  
-But in many cases you need additional steps before or after this main loop to produce the visual result you want. 
-An example is a shadow mapping pre-rendering or a post-rendering blur effect. 
- 
-With Gorilla3D it is possible to easily build your own render pass and integrate it in your rendering pipeline. You can choose between 3 different moments of rendering: 
- 
-^ Type ^ Description ^ 
-| TRenderPassType.Pre | render-pass will be executed before main loop. | 
-| TRenderPassType.Intermediate | render-pass will be executed in between main loop (very ineffective - because executed each renderlist element) | 
-| TRenderPassType.Post | render-pass will be executed after main loop. | 
- 
-===== Rendering Method ===== 
- 
-You are allowed to configure a destination / method for your individual render pass. 
-A render destination is the place where computed image data is going to stored to. 
-  * Context 
-  * FrameBufferObject (FBO) 
- 
-While the context (aka. main texture or Default-FBO) is the default texture used for final rendering output, the FrameBufferObject (FBO) is a buffer created for each render pass instance. 
-The FrameBufferObject (FBO) can be used to temporarily store your rendering result and push it to another render pass. 
-For further information read down below. 
- 
-^ Type ^ Description ^ 
-| TRenderPassMethod.RenderListToContext | Will render all 3D objects in rendering list to context. If a render pass material exists it will be applied, otherwise it will use the 3D object specific material shader. | 
-| TRenderPassMethod.RenderListToFBO | Will render all 3D objects in rendering list to render pass specific FrameBufferObject (FBO) and its attached textures. | 
-| TRenderPassMethod.RectToContext | Will render a rectangle to context. The render pass need to have an individual material applied, otherwise an error occurs. Use this method for rendering //post effects//. | 
-| TRenderPassMethod.RectToFBO | Will render a rectangle to the render pass specific FrameBufferObject (FBO). The render pass need to have an individual material applied, otherwise an error occurs. Use this method for rendering //post effects// in a chain of post effects. | 
- 
-In the next step you have to decide, if a **one-for-all material shader** should be used //or// the **object specific material shaders**. 
-Because sometimes you want the full scene just to be rendered from another perspective (like reflection) or you want to store a specific value (like the depth-value in shadow mapping) in the FBO. 
- 
-===== Render-Pass Material ===== 
- 
-To create an individual material shader for your render-pass you need to extend **TGorillaRenderPassMaterialSource** and **TGorillaRenderPassMaterial**. 
- 
-<file pascal> 
-uses 
-  FMX.Types3D, 
-  FMX.Materials, 
-  FMX.MaterialSources, 
-  Gorilla.Controller; 
-   
-  TMyRenderPassMaterial = class(TGorillaRenderPassMaterial) 
-    protected 
-      procedure DoApply(const Context: TContext3D); override; 
-      procedure DoInitialize(); override; 
-    public 
-  end; 
- 
-  TMyRenderPassMaterialSource = class(TGorillaRenderPassMaterialSource) 
-    protected 
-      function CreateMaterial() : TMaterial; override; 
-    public 
-  end; 
-</file> 
- 
-Here you can have a look at this example of a render-pass material implementation. 
- 
-Notice: No multiple targets used here. We just write to default output buffer by gl_FragColor. 
- 
-<file pascal> 
-uses 
-  Gorilla.Context.GLES; 
-   
-  ResourceString SOURCE_VS = 
-    'attribute vec3 a_Position;' + 
-    '' + 
-    'uniform mat4 _ModelViewProjMatrix;' + 
-    '' + 
-    'varying vec4 v_position;' + 
-    '' + 
-    'void main( void ){' + 
-    '  vec4 fvPosition = vec4(a_Position.x, a_Position.y, a_Position.z, 1.0);' + 
-    '  v_position = _ModelViewProjMatrix * fvPosition;' + 
-    '  gl_Position = v_position;' + 
-    '}'; 
- 
-  ResourceString SOURCE_FS = 
-    'varying vec4 v_position;' + 
-    '' + 
-    'void main( void ){' + 
-    '  gl_FragColor = v_position;' + 
-    '}'; 
- 
-procedure TMyRenderPassMaterial.DoInitialize(); 
-var LOGLBytes : TArray<Byte>; 
-begin 
-  LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_VS); 
-  FVertexShader := TShaderManager.RegisterShaderFromData('MyRenderPass.fvs', TContextShaderKind.VertexShader, '', [ 
-    TContextShaderSource.Create(TContextShaderArch.GLSL, 
-      LOGLBytes, 
-      [ 
-      TContextShaderVariable.Create('ModelViewProjMatrix', TContextShaderVariableKind.Matrix, 0, 4) 
-      ] 
-    ) 
-  ]); 
- 
-  LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_FS); 
-  FPixelShader := TShaderManager.RegisterShaderFromData('MyRenderPass.fps', TContextShaderKind.PixelShader, '', [ 
-    TContextShaderSource.Create(TContextShaderArch.GLSL, 
-      LOGLBytes, 
-      [] 
-    ) 
-  ]); 
-end; 
- 
-{ TMyRenderPassMaterial } 
- 
-procedure TMyRenderPassMaterial.DoApply(const Context: TContext3D); 
-begin 
-  // activate shaders 
-  Context.SetShaders(FVertexShader, FPixelShader); 
-  // set model view projection matrix 
-  TCustomContextOpenGL(Context).SetShaderVariable('ModelViewProjMatrix', Context.CurrentModelViewProjectionMatrix, true); 
-end; 
- 
-{ TMyRenderPassMaterialSource } 
- 
-function TMyRenderPassMaterialSource.CreateMaterial() : TMaterial; 
-begin 
-  Result := TMyRenderPassMaterial.Create(Self); 
-end; 
-</file> 
- 
-You than have to overwrite the CreateMaterialSource() method and create your material source. 
-In case you'd like to use the element specific material shaders, return nil in the CreateMaterialSource() method. 
- 
-<file pascal> 
-function TMyRenderPass.CreateMaterialSource() : TGorillaRenderPassMaterialSource; 
-begin 
-  result := TMyRenderPassMaterialSource.Create(Self); 
-end; 
-</file> 
- 
-===== Start / End ===== 
- 
-The render-pass controller provides a callback event for the start and the end of each rendering cycle. Simply overwrite the protected DoOnRenderPass() method. 
- 
-Here you can change the view, projection matrices or re-configure OpenGL context. 
-But do not forget to reset your changes on "OnPassEnd", otherwise the main loop rendering may produce unexpected results. 
- 
-Here is a short example for a callback function. 
- 
-<file pascal> 
-var 
-  FPrevCamView : TMatrix3D; 
-   
-procedure TMyRenderPass.DoOnRenderPass(const AContext : TContext3D; 
-  const ACount : Integer; const AState : TRenderPassEventState; const APass : TRenderPass); 
-var LCtx : TCustomContextOpenGL; 
-begin 
-  inherited; 
- 
-  LCtx := TCustomContextOpenGL(AContext); 
-  case AState of 
-    OnPassBegin: 
-      begin         
-        // deactivate ZTest in OpenGL 
-        AContext.SetContextState(TContextState.csZTestOff); 
-         
-        // Set view matrix and angle of view 
-        FPrevCamView := AContext.CurrentCameraMatrix; 
-        AContext.SetCameraMatrix(GetViewMatrix(AContext)); 
-        AContext.SetCameraAngleOfView(Viewport.CurrentCamera.AngleOfView); 
-         
-        // rendering method for rendering pass 
-        FFBO.Clear(Point(AContext.Width, AContext.Height),  
-          [TRenderTarget.Color_0, TRenderTarget.Depth],  
-          TAlphaColorF.Create(0, 0, 0, 0), 0, 0); 
-           
-        // prepare framebufferobject for multiple render targets 
-        FFBO.Prepare([TRenderTarget.Color_0, TRenderTarget.Depth]);         
-      end; 
- 
-    OnPassEnd: 
-      begin         
-        AContext.SetCameraMatrix(FPrevCamView);    
-      end; 
-  end; 
-end; 
-</file> 
- 
- 
-===== Framebuffer-Object (FBO) ===== 
-Each render pass sets up a default framebuffer object (FFBO) with a default output texture (FFBOTexture), where the result is drawn to. Of course you can change it or apply further rendering targets. 
- 
-__Caution:__ Multiple render targets are only supported since OpenGLES v3+. 
- 
-To change the FBO rendering target(s) simply overwrite the protected DoSetupTexturesByViewport() method, like this:  
- 
-<file pascal> 
-uses 
-  Gorilla.Context.Texturing; 
-   
-procedure TMyRenderPass.DoSetupTexturesByViewport(const AContext : TContext3D; 
-  const AWidth, AHeight : Integer); 
-var LSize : TPoint; 
-    LUpdateTex : Boolean; 
-begin 
-  // update FBO texture size 
-  LSize := ComputeRenderingSize(AContext, AWidth, AHeight); 
- 
-  LUpdateTex := true; 
-  if Assigned(FFBOTexture) then 
-  begin 
-    // is size really different? - if not leave 
-    if (FFBOTexture.Width = LSize.X) and (FFBOTexture.Height = LSize.Y) then 
-      LUpdateTex := false 
-    else 
-    begin 
-      FFBO.UnattachTexture(FFBOTexture.Texture); 
-      FreeAndNil(FFBOTexture); 
-    end; 
-  end; 
- 
-  if LUpdateTex then 
-  begin 
-    FFBOTexture := TGorillaTextureBitmap.Create(LSize.X, LSize.Y); 
-    FFBOTexture.BeginSetup(); 
-    try 
-      with FFBOTexture do 
-      begin 
-        Components := TPixelFormatEx.Depth; 
-        Format := TPixelFormatEx.Depth; 
-        MinFilter := TTextureFilter.Nearest; 
-        MagFilter := TTextureFilter.Nearest; 
-        WrapS := TGorillaTextureWrap.ClampToBorder; 
-        WrapT := TGorillaTextureWrap.ClampToBorder; 
-      end; 
-    finally 
-      FFBOTexture.EndSetup(); 
-    end; 
-     
-    // attach the texture to the FBO 
-    if Assigned(AContext) and Assigned(FFBO) then 
-        FFBO.AttachTexture(AContext, FFBOTexture.GorillaTexture, TRenderTarget.Color_0); 
-  end; 
-end; 
-</file> 
- 
-Here we changed the FBO texture format to a depth-texture. 
- 
-**The default format is RGBA with an unsigned byte for each component (4 Byte per Pixel).** 
- 
-==== Multiple Rendering-Targets ==== 
- 
-As said above, we can use multiple render targets since OpenGLES v3. 
- 
-Multiple render targets are useful to store values in the shader to different output textures. 
-So you possibly could store the depth, diffuse, specular, normals or alpha values in separated textures. 
-Afterwards you could combine those together in some kind of way. 
-For example this is how deferred rendering works. 
- 
-In Gorilla3D we create those targets as TGorillaTextureBitmap instances in our render pass. 
-Afterwards we attach those to the framebuffer object (FBO). 
- 
-__Notice:__ Gorilla3D provides an extended TClearTarget enumeration type called TRenderTarget, where the first 3 values are compatible with the Delphi type (and OpenGLES v2). 
- 
-<file pascal> 
-TRenderTarget = (Color_0, Depth, Stencil 
-  {$IFDEF GL_ES_VERSION_3_0}, 
-    Color_1, Color_2, Color_3, Color_4, Color_5, Color_6, Color_7, 
-    Color_8, Color_9, Color_10, Color_11, Color_12, Color_13, Color_14, 
-    Color_15 
-  {$ENDIF}); 
-</file> 
- 
-=== Creating multiple targets === 
- 
-As seen in the code snippet above, we can simply create a TGorillaTextureBitmap instance in our render-pass class in the DoSetupTexturesByViewport() method. 
- 
-<file pascal> 
-FMyRenderTargetTexture := TGorillaTextureBitmap.Create(LSize.X, LSize.Y); 
-FMyRenderTargetTexture.BeginSetup(); 
-try 
-  with FMyRenderTargetTexture do 
-  begin 
-    DataType := TGorillaTextureDataType.dtFloat; 
-    Components := TPixelFormatEx.RGBA32F; 
-    Format := TPixelFormatEx.RGBA; 
-    MinFilter := TTextureFilter.Linear; 
-    MagFilter := TTextureFilter.Linear; 
-    WrapS := TGorillaTextureWrap.ClampToBorder; 
-    WrapT := TGorillaTextureWrap.ClampToBorder; 
-  end; 
-finally 
-  FMyRenderTargetTexture.EndSetup(); 
-end; 
-</file> 
- 
-=== Attaching multiple targets === 
-To attach a texture to the framebuffer object we call the AttachTexture() method of the FBO and supply the intended rendertarget (one of the values above). 
- 
-__Caution:__ Not all GPU's support all render targets. Some GPU's only support up to 8 targets or less. 
- 
-<file pascal> 
-if Assigned(AContext) and Assigned(FFBO) then 
-  FFBO.AttachTexture(AContext, FMyRenderTargetTexture.GorillaTexture, TRenderTarget.Color_1); 
-</file> 
- 
-=== Using multiple targets === 
- 
-To use a render target from the framebuffer object, we need to clear it on each rendering step. 
-After that, we have to activate it for shader usage by the Prepare() method. 
-The prepare method will activate all supplied render targets for shader computation. 
-If you forget to execute prepare() only the default target Color_0 will be available for computation. 
- 
-We do this all in the render-pass callback method (DoOnRenderPass), when state is "TRenderPassEventState.OnPassBegin": 
- 
-<file pascal> 
-[...] 
-case AState of 
-  TRenderPassEventState.OnPassBegin : 
-    begin 
-      [...] 
-      LTarget := TRenderTarget.Color_1; 
-         
-      // clear the specific render target buffer 
-      FFBO.Clear(Point(AContext.Width, AContext.Height),  
-        LTarget, TAlphaColorF.Create(0, 0, 0, 0), 0, 0); 
-       
-      // activate the specific render target buffer for shader 
-      FFBO.Prepare([LTarget]); 
-    end; 
-     
-    [...] 
-</file> 
- 
-On "OnPassEnd" state we need to unbind the framebuffer object: 
- 
-<file pascal> 
-TRenderPassEventState.OnPassEnd : 
-  begin 
-    [...] 
-  end; 
-</file> 
- 
-=== In Shader === 
- 
-The usage in your material shader depends on your target setup and the activated targets. 
-For example: Preparing 3 render targets will be used like this: 
- 
-<file pascal> 
-FFBO.Prepare([TRenderTarget.Color0, TRenderTarget.Color2, TRenderTarget.Color3]); 
-</file> 
- 
-In Fragment-Shader you'll see, that layout location index **do not** correspond with the render target index, but with the array index of supplied render targets. 
- 
-<file GLSL> 
-layout(location = 0) out vec4 outColor_0; 
-layout(location = 1) out vec4 outColor_2; 
-layout(location = 2) out vec4 outColor_3; 
- 
-[...] 
- 
-// output one with red color 
-outColor_0 = vec4(1.0, 0.0, 0.0, 1.0); 
- 
-// output two with green color 
-outColor_2 = vec4(0.0, 1.0, 0.0, 1.0); 
- 
-// output three with blue color 
-outColor_3 = vec4(0.0, 0.0, 1.0, 1.0); 
-</file> 
- 
-==== Iterations ==== 
- 
-The callback also provides an "ACount" value, which indicates the iteration count for this render-pass. 
-It is possible to set a number of iterations this pass should run.  
-This is very useful for ping-pong rendering techniques like blurring. 
- 
-Set the "Iterations" property in your render-pass constructor to define the number of iterations. 
-The DoOnRenderPass() method will be called on each iteration step. 
- 
-==== Helpful methods ==== 
- 
-To use a different camera view or change to another projection mode, overwrite the following methods: 
- 
-  * function GetViewMatrix(const AContext : TContext3D) : TMatrix3D; 
-  * function GetProjectionMatrix(const AContext : TContext3D) : TMatrix3D; 
- 
- 
-===== How to use ===== 
- 
-Using your own render pass is very easy. Just instanciate it and attach the viewport to it. 
-This will automatically integrate your render-pass in the rendering-pipeline. 
-By the "Enabled" property you can activate or deactivate it at any time. 
- 
-<file pascal> 
-FMyRenderPass := TMyRenderPass.Create(FGorilla); 
-FMyRenderPass.Viewport := FGorilla; 
-FMyRenderPass.Enabled := true; 
-</file> 
- 
-Next step: [[shadow|shadow]]