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 13:33] – [Rendering Method] 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. 
-Here the so called FrameBufferObject (FBO) may come in place. For further information read down below. 
- 
-^ Type ^ Description ^ 
-| TRenderPassMethod.RenderListToContext | Will render all 3D objects in rendering list to the default FrameBufferObject (so called FBO / context or main texture). If a render pass material exists it will apply it, otherwise it will use the element specific material shader. | 
-| TRenderPassMethod.RenderListToFBO | Will render all 3D objects in rendering list to the render pass specific FrameBufferObject (FBO) and attached textures. | 
-| TRenderPassMethod.RectToContext | Will render a rectangle to default FrameBufferObject (FBO). The render pass need to have an individual material applied, otherwise an error occurs. Use this method for rendering post effects. The shader program will render to default FBO / context / main texture. | 
-| TRenderPassMethod.RectToFBO | Will render a rectangle to the render pass specific FrameBufferObject (FBO). he render pass need to have an individual material applied, otherwise an error occurs. Use this method for rendering post effects before applying to main texture / context / default FBO. | 
- 
-In the next step you have to decide, if the element materials (only in RenderList) or an especially for the render-pass created material should be used. 
-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. 
- 
-===== 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); 
-        FFBO.Bind(); 
-        FFBO.Prepare([TRenderTarget.Color_0, TRenderTarget.Depth]);         
-      end; 
- 
-    OnPassEnd: 
-      begin         
-        AContext.SetCameraMatrix(FPrevCamView); 
-         
-        FFBO.Unbind();         
-      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. 
- 
-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); 
-       
-      // bind again the framebuffer object 
-      FFBO.Bind(); 
-       
-      // 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 
-    [...] 
-     
-    // unbind framebuffer object 
-    FFBO.Unbind(); 
-  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; 
- 
-===== 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> 
- 
-===== 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>