From 26161b7e1d65c5bc2c917b127beaaa3717792b0a Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Wed, 18 Jun 2025 11:03:01 +0200 Subject: [PATCH] Update FilterPostProcessor.java --- .../com/jme3/post/FilterPostProcessor.java | 366 ++++++++++++------ 1 file changed, 248 insertions(+), 118 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index aa8896a951..fa0e14ab77 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,18 +32,28 @@ package com.jme3.post; import com.jme3.asset.AssetManager; -import com.jme3.export.*; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.material.Material; -import com.jme3.profile.*; -import com.jme3.renderer.*; +import com.jme3.profile.AppProfiler; +import com.jme3.profile.SpStep; +import com.jme3.renderer.Camera; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.texture.Image.Format; import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; -import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; import com.jme3.util.SafeArrayList; + import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -52,13 +62,22 @@ import java.util.List; /** - * A FilterPostProcessor is a processor that can apply several {@link Filter}s to a rendered scene
- * It manages a list of filters that will be applied in the order in which they've been added to the list - * @author Rémy Bouquet aka Nehon + * A `FilterPostProcessor` is a {@link SceneProcessor} that can apply several + * {@link Filter}s to a rendered scene. It manages a list of filters that will be + * applied in the order in which they have been added. This processor handles + * rendering the main scene to an offscreen framebuffer, then applying each enabled + * filter sequentially, optionally with anti-aliasing (multisampling) and depth texture + * support. + * + * @author Nehon */ public class FilterPostProcessor implements SceneProcessor, Savable { + /** + * The simple name of this class, used for profiling. + */ public static final String FPP = FilterPostProcessor.class.getSimpleName(); + private RenderManager renderManager; private Renderer renderer; private ViewPort viewPort; @@ -89,23 +108,28 @@ public class FilterPostProcessor implements SceneProcessor, Savable { private Format depthFormat = Format.Depth; /** - * Create a FilterProcessor - * @param assetManager the assetManager + * Creates a new `FilterPostProcessor`. + * + * @param assetManager The asset manager to be used by filters for loading assets. */ public FilterPostProcessor(AssetManager assetManager) { this.assetManager = assetManager; } /** - * Don't use this constructor, use {@link #FilterPostProcessor(AssetManager assetManager)}
- * This constructor is used for serialization only + * Serialization-only constructor. Do not use this constructor directly; + * use {@link #FilterPostProcessor(AssetManager)}. */ protected FilterPostProcessor() { } /** - * Adds a filter to the filters list
- * @param filter the filter to add + * Adds a filter to the list of filters to be applied. Filters are applied + * in the order they are added. If the processor is already initialized, + * the filter is immediately initialized as well. + * + * @param filter The filter to add (not null). + * @throws IllegalArgumentException If the provided filter is null. */ public void addFilter(Filter filter) { if (filter == null) { @@ -118,13 +142,14 @@ public void addFilter(Filter filter) { } setFilterState(filter, filter.isEnabled()); - } /** - * removes this filters from the filters list + * Removes a specific filter from the list. The filter's `cleanup` method + * is called upon removal. * - * @param filter the Filter to remove (not null) + * @param filter The filter to remove (not null). + * @throws IllegalArgumentException If the provided filter is null. */ public void removeFilter(Filter filter) { if (filter == null) { @@ -135,10 +160,22 @@ public void removeFilter(Filter filter) { updateLastFilterIndex(); } + /** + * Returns an iterator over the filters currently managed by this processor. + * + * @return An `Iterator` of {@link Filter} objects. + */ public Iterator getFilterIterator() { return filters.iterator(); } + /** + * Initializes the `FilterPostProcessor`. This method is called by the + * `RenderManager` when the processor is added to a viewport. + * + * @param rm The `RenderManager` instance. + * @param vp The `ViewPort` this processor is attached to. + */ @Override public void initialize(RenderManager rm, ViewPort vp) { renderManager = rm; @@ -148,10 +185,11 @@ public void initialize(RenderManager rm, ViewPort vp) { fsQuad.setWidth(1); fsQuad.setHeight(1); + // Determine optimal framebuffer format based on renderer capabilities if (!renderer.getCaps().contains(Caps.PackedFloatTexture)) { - if(renderer.getCaps().contains(Caps.FloatColorBufferRGB)){ + if (renderer.getCaps().contains(Caps.FloatColorBufferRGB)) { fbFormat = Format.RGB16F; - } else if(renderer.getCaps().contains(Caps.FloatColorBufferRGBA)){ + } else if (renderer.getCaps().contains(Caps.FloatColorBufferRGBA)) { fbFormat = Format.RGBA16F; } else { fbFormat = Format.RGB8; @@ -160,34 +198,47 @@ public void initialize(RenderManager rm, ViewPort vp) { Camera cam = vp.getCamera(); - //save view port dimensions + // Save original viewport dimensions left = cam.getViewPortLeft(); right = cam.getViewPortRight(); top = cam.getViewPortTop(); bottom = cam.getViewPortBottom(); originalWidth = cam.getWidth(); originalHeight = cam.getHeight(); - //first call to reshape + + // First call to reshape to set up internal framebuffers and textures reshape(vp, cam.getWidth(), cam.getHeight()); } + /** + * Returns the default color buffer format used for the internal rendering + * passes of the filters. This format is determined during initialization + * based on the renderer's capabilities. + * + * @return The default `Format` for the filter pass textures. + */ public Format getDefaultPassTextureFormat() { return fbFormat; } /** - * init the given filter - * @param filter - * @param vp + * Initializes a single filter. This method is called when a filter is added + * or when the post-processor is initialized/reshaped. It sets the processor + * for the filter, handles depth texture requirements, and calls the filter's + * `init` method. + * + * @param filter The {@link Filter} to initialize. + * @param vp The `ViewPort` associated with this processor. */ private void initFilter(Filter filter, ViewPort vp) { filter.setProcessor(this); if (filter.isRequiresDepthTexture()) { if (!computeDepth && renderFrameBuffer != null) { + // If depth texture is required and not yet created, create it depthTexture = new Texture2D(width, height, depthFormat); renderFrameBuffer.setDepthTarget(FrameBufferTarget.newTarget(depthTexture)); } - computeDepth = true; + computeDepth = true; // Mark that depth texture is needed filter.init(assetManager, renderManager, vp, width, height); filter.setDepthTexture(depthTexture); } else { @@ -196,45 +247,52 @@ private void initFilter(Filter filter, ViewPort vp) { } /** - * renders a filter on a fullscreen quad - * @param r - * @param buff - * @param mat + * Renders a filter's material onto a full-screen quad. This method + * handles setting up the rendering context (framebuffer, camera, material) + * for a filter pass. It correctly resizes the camera and adjusts material + * states based on whether the target buffer is the final output buffer or an + * intermediate filter buffer. + * + * @param r The `Renderer` instance. + * @param buff The `FrameBuffer` to render to. + * @param mat The `Material` to use for rendering the filter. */ private void renderProcessing(Renderer r, FrameBuffer buff, Material mat) { + // Adjust camera and viewport based on target framebuffer if (buff == outputBuffer) { viewPort.getCamera().resize(originalWidth, originalHeight, false); viewPort.getCamera().setViewPort(left, right, bottom, top); - // update is redundant because resize and setViewPort will both - // run the appropriate (and same) onXXXChange methods. - // Also, update() updates some things that don't need to be updated. - //viewPort.getCamera().update(); - renderManager.setCamera( viewPort.getCamera(), false); + // viewPort.getCamera().update(); // Redundant as resize and setViewPort call onXXXChange + renderManager.setCamera(viewPort.getCamera(), false); + // Disable depth test/write for final pass to prevent artifacts if (mat.getAdditionalRenderState().isDepthWrite()) { mat.getAdditionalRenderState().setDepthTest(false); mat.getAdditionalRenderState().setDepthWrite(false); } } else { + // Rendering to an intermediate framebuffer for a filter pass viewPort.getCamera().resize(buff.getWidth(), buff.getHeight(), false); viewPort.getCamera().setViewPort(0, 1, 0, 1); - // update is redundant because resize and setViewPort will both - // run the appropriate (and same) onXXXChange methods. - // Also, update() updates some things that don't need to be updated. - //viewPort.getCamera().update(); - renderManager.setCamera( viewPort.getCamera(), false); + // viewPort.getCamera().update(); // Redundant as resize and setViewPort call onXXXChange + renderManager.setCamera(viewPort.getCamera(), false); + // Enable depth test/write for intermediate passes if material needs it mat.getAdditionalRenderState().setDepthTest(true); mat.getAdditionalRenderState().setDepthWrite(true); } - fsQuad.setMaterial(mat); fsQuad.updateGeometricState(); r.setFrameBuffer(buff); - r.clearBuffers(true, true, true); + r.clearBuffers(true, true, true); // Clear color, depth, and stencil buffers renderManager.renderGeometry(fsQuad); } + /** + * Checks if the `FilterPostProcessor` has been initialized. + * + * @return True if initialized, false otherwise. + */ @Override public boolean isInitialized() { return viewPort != null; @@ -244,30 +302,44 @@ public boolean isInitialized() { public void postQueue(RenderQueue rq) { for (Filter filter : filters.getArray()) { if (filter.isEnabled()) { - if (prof != null) prof.spStep(SpStep.ProcPostQueue, FPP, filter.getName()); + if (prof != null) { + prof.spStep(SpStep.ProcPostQueue, FPP, filter.getName()); + } filter.postQueue(rq); } } } /** - * iterate through the filter list and renders filters - * @param r - * @param sceneFb + * Renders the chain of filters. This method is the core of the post-processing. + * It iterates through each enabled filter, handling pre-filter passes, + * setting up textures (scene, depth), performing the main filter rendering, + * and managing intermediate framebuffers. + * + * @param r The `Renderer` instance. + * @param sceneFb The framebuffer containing the rendered scene (either MS or single-sample). */ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { Texture2D tex = filterTexture; FrameBuffer buff = sceneFb; boolean msDepth = depthTexture != null && depthTexture.getImage().getMultiSamples() > 1; + for (int i = 0; i < filters.size(); i++) { Filter filter = filters.get(i); - if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName()); + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName()); + } + if (filter.isEnabled()) { + // Handle additional passes a filter might have (e.g., blur passes) if (filter.getPostRenderPasses() != null) { - for (Iterator it1 = filter.getPostRenderPasses().iterator(); it1.hasNext();) { - Filter.Pass pass = it1.next(); - if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), pass.toString()); + for (Filter.Pass pass : filter.getPostRenderPasses()) { + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), pass.toString()); + } pass.beforeRender(); + + // Set scene texture if required by the pass if (pass.requiresSceneAsTexture()) { pass.getPassMaterial().setTexture("Texture", tex); if (tex.getImage().getMultiSamples() > 1) { @@ -277,6 +349,8 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { } } + + // Set depth texture if required by the pass if (pass.requiresDepthAsTexture()) { pass.getPassMaterial().setTexture("DepthTexture", depthTexture); if (msDepth) { @@ -288,7 +362,9 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { renderProcessing(r, pass.getRenderFrameBuffer(), pass.getPassMaterial()); } } - if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "postFrame"); + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "postFrame"); + } filter.postFrame(renderManager, viewPort, buff, sceneFb); Material mat = filter.getMaterial(); @@ -305,23 +381,31 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { } } + // Apply bilinear filtering if requested by the filter boolean wantsBilinear = filter.isRequiresBilinear(); if (wantsBilinear) { tex.setMagFilter(Texture.MagFilter.Bilinear); tex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); } + // Determine target framebuffer and source texture for the next pass buff = outputBuffer; if (i != lastFilterIndex) { buff = filter.getRenderFrameBuffer(); tex = filter.getRenderedTexture(); - } - if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "render"); + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "render"); + } + // Render the main filter pass renderProcessing(r, buff, mat); - if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "postFilter"); + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName(), "postFilter"); + } + // Call filter's postFilter for final adjustments filter.postFilter(r, buff); + // Revert texture filtering if it was changed if (wantsBilinear) { tex.setMagFilter(Texture.MagFilter.Nearest); tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps); @@ -339,10 +423,14 @@ public void postFrame(FrameBuffer out) { } else if (renderFrameBufferMS != null) { sceneBuffer = renderFrameBufferMS; } + + // Execute the filter chain renderFilterChain(renderer, sceneBuffer); + + // Restore the original output framebuffer for the viewport renderer.setFrameBuffer(outputBuffer); - //viewport can be null if no filters are enabled + // viewport can be null if no filters are enabled if (viewPort != null) { renderManager.setCamera(viewPort.getCamera(), false); } @@ -351,40 +439,44 @@ public void postFrame(FrameBuffer out) { @Override public void preFrame(float tpf) { if (filters.isEmpty() || lastFilterIndex == -1) { - //If the camera is initialized and there are no filter to render, the camera viewport is restored as it was + // If no filters are enabled, restore the camera's original viewport + // and output framebuffer to bypass the post-processor. if (cameraInit) { viewPort.getCamera().resize(originalWidth, originalHeight, true); viewPort.getCamera().setViewPort(left, right, bottom, top); viewPort.setOutputFrameBuffer(outputBuffer); cameraInit = false; } - } else { - setupViewPortFrameBuffer(); - //if we are in a multiview situation we need to resize the camera - //to the viewport size so that the back buffer is rendered correctly - if (multiView) { + setupViewPortFrameBuffer(); + // If in a multi-view situation, resize the camera to the viewport size + // so that the back buffer is rendered correctly for filtering. + if (multiView) { viewPort.getCamera().resize(width, height, false); viewPort.getCamera().setViewPort(0, 1, 0, 1); viewPort.getCamera().update(); renderManager.setCamera(viewPort.getCamera(), false); - } + } } + // Call preFrame on all enabled filters for (Filter filter : filters.getArray()) { if (filter.isEnabled()) { - if (prof != null) prof.spStep(SpStep.ProcPreFrame, FPP, filter.getName()); + if (prof != null) { + prof.spStep(SpStep.ProcPreFrame, FPP, filter.getName()); + } filter.preFrame(tpf); } } - } /** - * sets the filter to enabled or disabled + * Sets the enabled state of a specific filter. If the filter is part of + * this processor's list, its `enabled` flag is updated, and the + * `lastFilterIndex` is recomputed. * - * @param filter the Filter to modify (not null) - * @param enabled true to enable, false to disable + * @param filter The {@link Filter} to modify (not null). + * @param enabled True to enable the filter, false to disable it. */ protected void setFilterState(Filter filter, boolean enabled) { if (filters.contains(filter)) { @@ -394,26 +486,27 @@ protected void setFilterState(Filter filter, boolean enabled) { } /** - * compute the index of the last filter to render + * Computes the index of the last enabled filter in the list. This is used + * to determine which filter should render to the final output framebuffer + * and which should render to intermediate framebuffers. If no filters are + * enabled, the viewport's output framebuffer is restored to its original. */ private void updateLastFilterIndex() { lastFilterIndex = -1; for (int i = filters.size() - 1; i >= 0 && lastFilterIndex == -1; i--) { if (filters.get(i).isEnabled()) { lastFilterIndex = i; - // The FPP is initialized, but the viewport framebuffer is the - // original out framebuffer, so we must recover from a situation - // where no filter was enabled. So we set the correct framebuffer - // on the viewport. - if(isInitialized() && viewPort.getOutputFrameBuffer()==outputBuffer){ + // If the FPP is initialized but the viewport framebuffer is the + // original output framebuffer (meaning no filter was enabled + // previously), then redirect it to the FPP's internal framebuffer. + if (isInitialized() && viewPort.getOutputFrameBuffer() == outputBuffer) { setupViewPortFrameBuffer(); } return; } } + // If no filters are enabled, restore the original framebuffer to the viewport. if (isInitialized() && lastFilterIndex == -1) { - //There is no enabled filter, we restore the original framebuffer - //to the viewport to bypass the fpp. viewPort.setOutputFrameBuffer(outputBuffer); } } @@ -421,40 +514,56 @@ private void updateLastFilterIndex() { @Override public void cleanup() { if (viewPort != null) { - //reset the viewport camera viewport to its initial value + // Reset the viewport camera and output framebuffer to their initial values viewPort.getCamera().resize(originalWidth, originalHeight, true); viewPort.getCamera().setViewPort(left, right, bottom, top); viewPort.setOutputFrameBuffer(outputBuffer); viewPort = null; - if(renderFrameBuffer != null){ + // Dispose of internal framebuffers and textures + if (renderFrameBuffer != null) { renderFrameBuffer.dispose(); } - if(depthTexture!=null){ - depthTexture.getImage().dispose(); + if (depthTexture != null) { + depthTexture.getImage().dispose(); } filterTexture.getImage().dispose(); - if(renderFrameBufferMS != null){ - renderFrameBufferMS.dispose(); + if (renderFrameBufferMS != null) { + renderFrameBufferMS.dispose(); } for (Filter filter : filters.getArray()) { filter.cleanup(renderer); } } - } + /** + * Sets the profiler instance for this processor. + * + * @param profiler The `AppProfiler` instance to use for performance monitoring. + */ @Override public void setProfiler(AppProfiler profiler) { this.prof = profiler; } + /** + * Reshapes the `FilterPostProcessor` when the viewport or canvas size changes. + * This method recalculates internal framebuffer dimensions, creates new + * framebuffers and textures if necessary (e.g., for anti-aliasing), and + * reinitializes all filters with the new dimensions. It also detects + * multi-view scenarios. + * + * @param vp The `ViewPort` being reshaped. + * @param w The new width of the viewport's canvas. + * @param h The new height of the viewport's canvas. + */ @Override public void reshape(ViewPort vp, int w, int h) { Camera cam = vp.getCamera(); - //this has no effect at first init but is useful when resizing the canvas with multi views + // This sets the camera viewport to its full extent (0-1) for rendering to the FPP's internal buffer. cam.setViewPort(left, right, bottom, top); - //resizing the camera to fit the new viewport and saving original dimensions + // Resizing the camera to fit the new viewport and saving original dimensions cam.resize(w, h, true); left = cam.getViewPortLeft(); right = cam.getViewPortRight(); @@ -463,16 +572,16 @@ public void reshape(ViewPort vp, int w, int h) { originalWidth = w; originalHeight = h; - //computing real dimension of the viewport and resizing the camera + // Computing real dimension of the viewport based on its relative size within the canvas width = (int) (w * (Math.abs(right - left))); height = (int) (h * (Math.abs(bottom - top))); width = Math.max(1, width); height = Math.max(1, height); - //Testing original versus actual viewport dimension. - //If they are different we are in a multiview situation and - //camera must be handled differently - if(originalWidth!=width || originalHeight!=height){ + // Test if original dimensions differ from actual viewport dimensions. + // If they are different, we are in a multiview situation, and the + // camera must be handled differently (e.g., resized to the sub-viewport). + if (originalWidth != width || originalHeight != height) { multiView = true; } @@ -485,9 +594,11 @@ public void reshape(ViewPort vp, int w, int h) { Collection caps = renderer.getCaps(); - //antialiasing on filters only supported in opengl 3 due to depth read problem + // antialiasing on filters only supported in opengl 3 due to depth read problem if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)) { renderFrameBufferMS = new FrameBuffer(width, height, numSamples); + + // If OpenGL 3.2+ is supported, multisampled textures can be attached directly if (caps.contains(Caps.OpenGL32)) { Texture2D msColor = new Texture2D(width, height, numSamples, fbFormat); Texture2D msDepth = new Texture2D(width, height, numSamples, depthFormat); @@ -496,11 +607,14 @@ public void reshape(ViewPort vp, int w, int h) { filterTexture = msColor; depthTexture = msDepth; } else { + // Otherwise, multisampled framebuffer must use internal texture, which cannot be directly read renderFrameBufferMS.setDepthTarget(FrameBufferTarget.newTarget(depthFormat)); renderFrameBufferMS.addColorTarget(FrameBufferTarget.newTarget(fbFormat)); } } + // Setup single-sampled framebuffer if no multisampling, or if OpenGL 3.2+ is not supported + // (because for non-GL32, a single-sampled buffer is still needed to copy MS content into). if (numSamples <= 1 || !caps.contains(Caps.OpenGL32) || !caps.contains(Caps.FrameBufferMultisample)) { renderFrameBuffer = new FrameBuffer(width, height, 1); renderFrameBuffer.setDepthTarget(FrameBufferTarget.newTarget(depthFormat)); @@ -508,6 +622,7 @@ public void reshape(ViewPort vp, int w, int h) { renderFrameBuffer.addColorTarget(FrameBufferTarget.newTarget(filterTexture)); } + // Set names for debugging if (renderFrameBufferMS != null) { renderFrameBufferMS.setName("FilterPostProcessor MS"); } @@ -516,6 +631,7 @@ public void reshape(ViewPort vp, int w, int h) { renderFrameBuffer.setName("FilterPostProcessor"); } + // Initialize all existing filters with the new dimensions for (Filter filter : filters.getArray()) { initFilter(filter, vp); } @@ -523,16 +639,16 @@ public void reshape(ViewPort vp, int w, int h) { } /** - * return the number of samples for antialiasing - * @return numSamples + * Returns the number of samples used for anti-aliasing. + * + * @return The number of samples. */ public int getNumSamples() { return numSamples; } /** - * - * Removes all the filters from this processor + * Removes all filters currently added to this processor. */ public void removeAllFilters() { filters.clear(); @@ -540,8 +656,12 @@ public void removeAllFilters() { } /** - * Sets the number of samples for antialiasing - * @param numSamples the number of Samples + * Sets the number of samples for anti-aliasing. A value of 1 means no + * anti-aliasing. This method should generally be called before the + * processor is initialized to have an effect. + * + * @param numSamples The number of samples. Must be greater than 0. + * @throws IllegalArgumentException If `numSamples` is less than or equal to 0. */ public void setNumSamples(int numSamples) { if (numSamples <= 0) { @@ -561,27 +681,30 @@ public void setAssetManager(AssetManager assetManager) { } /** - * Sets the format to be used for the internal frame buffer's color buffer + * Sets the preferred `Image.Format` to be used for the internal frame buffer's + * color buffer. * - * @param fbFormat the format + * @param fbFormat The desired `Format` for the color buffer. */ public void setFrameBufferFormat(Format fbFormat) { this.fbFormat = fbFormat; } /** - * Sets the format to be used for the internal frame buffer's depth buffer + * Sets the preferred `Image.Format` to be used for the internal frame buffer's + * depth buffer. * - * @param depthFormat the format + * @param depthFormat The desired `Format` for the depth buffer. */ public void setFrameBufferDepthFormat(Format depthFormat) { this.depthFormat = depthFormat; } /** - * Returns the depth format currently used for the internal frame buffer's depth buffer - * - * @return the depth format + * Returns the `Image.Format` currently used for the internal frame buffer's + * depth buffer. + * + * @return The current depth `Format`. */ public Format getFrameBufferDepthFormat() { return depthFormat; @@ -609,43 +732,50 @@ public void read(JmeImporter im) throws IOException { } /** - * For internal use only
- * returns the depth texture of the scene - * @return the depth texture + * For internal use only. + * Returns the depth texture generated from the scene's depth buffer. + * This texture is available if any filter requires a depth texture. + * + * @return The `Texture2D` containing the scene's depth information, or null if not computed. */ public Texture2D getDepthTexture() { return depthTexture; } /** - * For internal use only
- * returns the rendered texture of the scene - * @return the filter texture + * For internal use only. + * Returns the color texture that contains the rendered scene or the output + * of the previous filter in the chain. This texture serves as input for subsequent filters. + * + * @return The `Texture2D` containing the scene's color information or the intermediate filter output. */ public Texture2D getFilterTexture() { return filterTexture; } /** - * returns the first filter in the list assignable from the given type + * Returns the first filter in the managed list that is assignable from the + * given filter type. Useful for retrieving specific filters to modify their properties. * - * @param the filter type - * @param filterType the filter type - * @return a filter assignable from the given type + * @param The type of the filter to retrieve. + * @param filterType The `Class` object representing the filter type. + * @return A filter instance assignable from `filterType`, or null if no such filter is found. */ @SuppressWarnings("unchecked") public T getFilter(Class filterType) { - for (Filter c : filters.getArray()) { - if (filterType.isAssignableFrom(c.getClass())) { - return (T) c; + for (Filter f : filters.getArray()) { + if (filterType.isAssignableFrom(f.getClass())) { + return (T) f; } } return null; } /** - * returns an unmodifiable version of the filter list. - * @return the filters list + * Returns an unmodifiable version of the list of filters currently + * managed by this processor. + * + * @return An unmodifiable `List` of {@link Filter} objects. */ public List getFilterList(){ return Collections.unmodifiableList(filters); @@ -658,4 +788,4 @@ private void setupViewPortFrameBuffer() { viewPort.setOutputFrameBuffer(renderFrameBuffer); } } - } +}