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
Last revisionBoth sides next revision
renderpass [2019/04/12 13:29] – [Multiple Rendering-Targets] adminrenderpass [2020/01/09 14:24] – [How to use] admin
Line 15: Line 15:
  
 You are allowed to configure a destination / method for your individual render pass. 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 ^ ^ Type ^ Description ^
-| TRenderPassMethod.RenderList It will execute the render list. If exists, it will apply the render pass material to all 3D objects. Otherwise it will use the element specific material shaders. | +| TRenderPassMethod.RenderListToContext Will render all 3D objects in rendering list to context. If a render pass material exists it will be appliedotherwise it will use the 3D object specific material shader. | 
-| TRenderPassMethod.ToContext | The render pass will work on the current context texture (useful for post-effects) with the render-pass 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 the element materials (only in RenderList) or an especially for the render-pass created material should be used.+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. 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>
  
  
Line 145: Line 305:
 To use a render target from the framebuffer object, we need to clear it on each rendering step. 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. 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": We do this all in the render-pass callback method (DoOnRenderPass), when state is "TRenderPassEventState.OnPassBegin":
Line 159: Line 321:
       FFBO.Clear(Point(AContext.Width, AContext.Height),        FFBO.Clear(Point(AContext.Width, AContext.Height), 
         LTarget, TAlphaColorF.Create(0, 0, 0, 0), 0, 0);         LTarget, TAlphaColorF.Create(0, 0, 0, 0), 0, 0);
-       
-      // bind again the framebuffer object 
-      FFBO.Bind(); 
              
       // activate the specific render target buffer for shader       // activate the specific render target buffer for shader
Line 176: Line 335:
   begin   begin
     [...]     [...]
-     
-    // unbind framebuffer object 
-    FFBO.Unbind(); 
   end;   end;
 </file> </file>
Line 208: Line 364:
 // output three with blue color // output three with blue color
 outColor_3 = vec4(0.0, 0.0, 1.0, 1.0); outColor_3 = vec4(0.0, 0.0, 1.0, 1.0);
-</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> 
-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 
-        // 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]); 
-         
-        // deactivate ZTest in OpenGL 
-        AContext.SetContextState(TContextState.csZTestOff); 
-         
-        // Set view matrix and angle of view 
-        AContext.SetCameraMatrix(GetViewMatrix(AContext)); 
-        AContext.SetCameraAngleOfView(Viewport.CurrentCamera.AngleOfView); 
-      end; 
- 
-    OnPassEnd: 
-      begin 
-        FFBO.Unbind(); 
-      end; 
-  end; 
-end; 
 </file> </file>
  
Line 256: Line 370:
 The callback also provides an "ACount" value, which indicates the iteration count for this render-pass. 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.  It is possible to set a number of iterations this pass should run. 
-This is very useful for example for ping-pong rendering techniques like blurring.+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. Set the "Iterations" property in your render-pass constructor to define the number of iterations.
Line 268: Line 382:
   * function GetProjectionMatrix(const AContext : TContext3D) : TMatrix3D;   * function GetProjectionMatrix(const AContext : TContext3D) : TMatrix3D;
  
-===== Render-Pass Material ===== 
- 
-To create a 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 simple 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 ===== ===== How to use =====
Line 382: Line 394:
 FMyRenderPass.Enabled := true; FMyRenderPass.Enabled := true;
 </file> </file>
 +
 +Next step: [[shadows|Shadows]]