Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
renderpass [2019/04/12 13:27] – [Multiple Rendering-Targets] admin | renderpass [2020/01/09 14:23] – [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 | + | | TRenderPassMethod.RenderListToContext |
- | | TRenderPassMethod.ToContext | + | | TRenderPassMethod.RenderListToFBO | Will render |
+ | | TRenderPassMethod.RectToContext | ||
+ | | TRenderPassMethod.RectToFBO | Will render a rectangle to the render pass specific FrameBufferObject (FBO). The render pass need to have an individual | ||
- | In the next step you have to decide, if the element materials (only in RenderList) or an especially | + | In the next step you have to decide, if a **one-for-all material |
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); | ||
+ | procedure DoInitialize(); | ||
+ | public | ||
+ | end; | ||
+ | |||
+ | TMyRenderPassMaterialSource = class(TGorillaRenderPassMaterialSource) | ||
+ | protected | ||
+ | function CreateMaterial() : TMaterial; override; | ||
+ | public | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | 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 = | ||
+ | ' | ||
+ | '' | ||
+ | ' | ||
+ | '' | ||
+ | ' | ||
+ | '' | ||
+ | 'void main( void ){' + | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | ResourceString SOURCE_FS = | ||
+ | ' | ||
+ | '' | ||
+ | 'void main( void ){' + | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | procedure TMyRenderPassMaterial.DoInitialize(); | ||
+ | var LOGLBytes : TArray< | ||
+ | begin | ||
+ | LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_VS); | ||
+ | FVertexShader := TShaderManager.RegisterShaderFromData(' | ||
+ | TContextShaderSource.Create(TContextShaderArch.GLSL, | ||
+ | LOGLBytes, | ||
+ | [ | ||
+ | TContextShaderVariable.Create(' | ||
+ | ] | ||
+ | ) | ||
+ | ]); | ||
+ | |||
+ | LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_FS); | ||
+ | FPixelShader := TShaderManager.RegisterShaderFromData(' | ||
+ | TContextShaderSource.Create(TContextShaderArch.GLSL, | ||
+ | LOGLBytes, | ||
+ | [] | ||
+ | ) | ||
+ | ]); | ||
+ | end; | ||
+ | |||
+ | { TMyRenderPassMaterial } | ||
+ | |||
+ | procedure TMyRenderPassMaterial.DoApply(const Context: TContext3D); | ||
+ | begin | ||
+ | // activate shaders | ||
+ | Context.SetShaders(FVertexShader, | ||
+ | // set model view projection matrix | ||
+ | TCustomContextOpenGL(Context).SetShaderVariable(' | ||
+ | end; | ||
+ | |||
+ | { TMyRenderPassMaterialSource } | ||
+ | |||
+ | function TMyRenderPassMaterialSource.CreateMaterial() : TMaterial; | ||
+ | begin | ||
+ | Result := TMyRenderPassMaterial.Create(Self); | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | 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; | ||
+ | </ | ||
+ | |||
+ | ===== 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 " | ||
+ | |||
+ | 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; | ||
+ | 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, | ||
+ | [TRenderTarget.Color_0, | ||
+ | TAlphaColorF.Create(0, | ||
+ | | ||
+ | // prepare framebufferobject for multiple render targets | ||
+ | FFBO.Prepare([TRenderTarget.Color_0, | ||
+ | end; | ||
+ | |||
+ | OnPassEnd: | ||
+ | begin | ||
+ | AContext.SetCameraMatrix(FPrevCamView); | ||
+ | end; | ||
+ | end; | ||
+ | end; | ||
+ | </ | ||
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), | We do this all in the render-pass callback method (DoOnRenderPass), | ||
Line 159: | Line 321: | ||
FFBO.Clear(Point(AContext.Width, | FFBO.Clear(Point(AContext.Width, | ||
LTarget, TAlphaColorF.Create(0, | LTarget, TAlphaColorF.Create(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; | ||
</ | </ | ||
Line 191: | Line 347: | ||
</ | </ | ||
- | In Fragment-Shader: | + | In Fragment-Shader |
<file GLSL> | <file GLSL> | ||
layout(location = 0) out vec4 outColor_0; | layout(location = 0) out vec4 outColor_0; | ||
Line 207: | 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); | ||
- | </ | ||
- | ===== 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 " | ||
- | |||
- | Here is a short example for a callback function. | ||
- | |||
- | <file pascal> | ||
- | procedure TMyRenderPass.DoOnRenderPass(const AContext : TContext3D; | ||
- | const ACount : Integer; const AState : TRenderPassEventState; | ||
- | var LCtx : TCustomContextOpenGL; | ||
- | begin | ||
- | inherited; | ||
- | |||
- | LCtx := TCustomContextOpenGL(AContext); | ||
- | case AState of | ||
- | OnPassBegin: | ||
- | begin | ||
- | // rendering method for rendering pass | ||
- | FFBO.Clear(Point(AContext.Width, | ||
- | [TRenderTarget.Color_0, | ||
- | TAlphaColorF.Create(0, | ||
- | FFBO.Bind(); | ||
- | FFBO.Prepare([TRenderTarget.Color_0, | ||
- | | ||
- | // 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; | ||
</ | </ | ||
Line 255: | Line 370: | ||
The callback also provides an " | The callback also provides an " | ||
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 | + | This is very useful for ping-pong rendering techniques like blurring. |
Set the " | Set the " | ||
Line 267: | 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); | ||
- | procedure DoInitialize(); | ||
- | public | ||
- | end; | ||
- | |||
- | TMyRenderPassMaterialSource = class(TGorillaRenderPassMaterialSource) | ||
- | protected | ||
- | function CreateMaterial() : TMaterial; override; | ||
- | public | ||
- | end; | ||
- | </ | ||
- | |||
- | 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 = | ||
- | ' | ||
- | '' | ||
- | ' | ||
- | '' | ||
- | ' | ||
- | '' | ||
- | 'void main( void ){' + | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | ' | ||
- | |||
- | ResourceString SOURCE_FS = | ||
- | ' | ||
- | '' | ||
- | 'void main( void ){' + | ||
- | ' | ||
- | ' | ||
- | |||
- | procedure TMyRenderPassMaterial.DoInitialize(); | ||
- | var LOGLBytes : TArray< | ||
- | begin | ||
- | LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_VS); | ||
- | FVertexShader := TShaderManager.RegisterShaderFromData(' | ||
- | TContextShaderSource.Create(TContextShaderArch.GLSL, | ||
- | LOGLBytes, | ||
- | [ | ||
- | TContextShaderVariable.Create(' | ||
- | ] | ||
- | ) | ||
- | ]); | ||
- | |||
- | LOGLBytes := TEncoding.ASCII.GetBytes(SOURCE_FS); | ||
- | FPixelShader := TShaderManager.RegisterShaderFromData(' | ||
- | TContextShaderSource.Create(TContextShaderArch.GLSL, | ||
- | LOGLBytes, | ||
- | [] | ||
- | ) | ||
- | ]); | ||
- | end; | ||
- | |||
- | { TMyRenderPassMaterial } | ||
- | |||
- | procedure TMyRenderPassMaterial.DoApply(const Context: TContext3D); | ||
- | begin | ||
- | // activate shaders | ||
- | Context.SetShaders(FVertexShader, | ||
- | // set model view projection matrix | ||
- | TCustomContextOpenGL(Context).SetShaderVariable(' | ||
- | end; | ||
- | |||
- | { TMyRenderPassMaterialSource } | ||
- | |||
- | function TMyRenderPassMaterialSource.CreateMaterial() : TMaterial; | ||
- | begin | ||
- | Result := TMyRenderPassMaterial.Create(Self); | ||
- | end; | ||
- | </ | ||
- | |||
- | 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; | ||
- | </ | ||
===== How to use ===== | ===== How to use ===== | ||
Line 381: | Line 394: | ||
FMyRenderPass.Enabled := true; | FMyRenderPass.Enabled := true; | ||
</ | </ | ||
+ | |||
+ | Next step: [[shadow|shadow]] |