⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shadowedrenderpass.java

📁 java 3d game jme 工程开发源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jme.renderer.pass;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;

import com.jme.light.Light;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.shadow.MeshShadows;
import com.jme.scene.shadow.ShadowVolume;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.ColorMaskState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.StencilState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.StencilState.StencilFunction;
import com.jme.scene.state.StencilState.StencilOperation;
import com.jme.system.DisplaySystem;

/**
 * <code>ShadowedRenderPass</code> is a render pass that renders the added
 * spatials along with shadows cast by givens occluders and lights flagged as
 * casting shadows.
 *
 * @author Mike Talbot (some code for MODULATIVE method written Jan 2005)
 * @author Joshua Slack
 * @version $Id: ShadowedRenderPass.java,v 1.16 2006/11/16 16:55:52 nca Exp $
 */
public class ShadowedRenderPass extends Pass {

   private static final long serialVersionUID = 1L;

   public enum LightingMethod {
       /**
        * value for lightingMethod indicating that a scene should be rendered first
        * with ambient lighting and then multiple passes per light done to
        * illuminate unshadowed areas (resulting in shadows.) More costly but more
        * accurate than Modulative.
        */
       Additive,
    
       /**
        * value for lightingMethod indicating that a scene should be rendered first
        * with full lighting and then multiple screens applied per light to darken
        * shadowed areas. More prone to artifacts than Additive, but faster.
        */
       Modulative;
   }

   /** list of occluders registered with this pass. */
   protected ArrayList<Spatial> occluders = new ArrayList<Spatial>();

   /** node used to gather and hold shadow volumes for rendering. */
   protected Node volumeNode = new Node("Volumes");

   /** whether or not the renderstates for this pass have been init'd yet. */
   protected boolean initialised = false;

   /**
    * A quad to use with MODULATIVE lightMethod for full screen darkening
    * against the shadow stencil.
    */
   protected Quad shadowQuad = new Quad("RenderForeground", 10, 10);

   /**
    * Used with MODULATIVE lightMethod. Defines the base color of the shadow -
    * the alpha value is replaced with 1 - the alpha of the light's alpha.
    */
   protected ColorRGBA shadowColor = new ColorRGBA(.2f,.2f,.2f,.1f);

   /** Whether shadow volumes are visible */
   protected boolean renderVolume = false;

   /** Whether to render shadows (true) or act like a normal RenderPass (false) */
   protected boolean renderShadows = true;

   /** Sets the type of pass to do to show shadows - ADDITIVE or MODULATIVE */
   protected LightingMethod lightingMethod = LightingMethod.Additive;

   /** collection of TriMesh to MeshShadows mappings */
   protected IdentityHashMap<TriMesh, MeshShadows> meshes = new IdentityHashMap<TriMesh, MeshShadows>();

   /**
    * list of occluders that will be casting shadows in this pass. If no
    * occluders set, pass acts like normal RenderPass.
    */
   protected ArrayList<TriMesh> occluderMeshes = new ArrayList<TriMesh>();

   /**
    * list of lights that will be used to calculate shadows in this pass.
    * Constructed dynamically by searching through the scene for lights with
    * shadowCaster set to true.
    */
   protected ArrayList<Light> shadowLights = new ArrayList<Light>();

   /**
    * a place to internally save previous enforced states setup before
    * rendering this pass
    */
   protected RenderState[] preStates = new RenderState[RenderState.StateType.values().length];

   protected int quadWidth = -1, quadHeight = -1;

   private ShadowGate shadowGate = new DefaultShadowGate();    

   public static boolean rTexture = true;


   /**
    * <code>addOccluder</code> adds an occluder to this pass.
    *
    * @param toAdd
    *            Occluder Spatial to add to this pass.
    */
   public void addOccluder(Spatial toAdd) {
       occluders.add(toAdd);
   }

   /**
    * <code>clearOccluders</code> removes all occluders from this pass.
    */
   public void clearOccluders() {
       occluders.clear();
   }

   /**
    * <code>containsOccluder</code>
    *
    * @param s
    * @return
    */
   public boolean containsOccluder(Spatial s) {
       return occluders.contains(s);
   }

   /**
    * <code>removeOccluder</code>
    *
    * @param toRemove the Occluder Spatial to remove from this pass.
    * @return true if the Spatial was found and removed.
    */
   public boolean removeOccluder(Spatial toRemove) {
       return occluders.remove(toRemove);
   }

   /**
    * @return the number of occluders registered with this pass
    */
   public int occludersSize() {
       return occluders.size();
   }

   /**
    * @return Returns whether shadow volumes will be rendered to the display.
    */
   public boolean getRenderVolume() {
       return renderVolume;
   }

   /**
    * @param renderVolume
    *            sets whether shadow volumes will be rendered to the display
    */
   public void setRenderVolume(boolean renderVolume) {
       this.renderVolume = renderVolume;
   }

   /**
    * @return whether shadow volumes will be rendered to the display.
    */
   public boolean getRenderShadows() {
       return renderShadows;
   }

   /**
    * @param renderShadows
    *            whether shadows will be rendered by this pass.
    */
   public void setRenderShadows(boolean renderShadows) {
       this.renderShadows = renderShadows;
   }


   /**
    * @return the shadowColor used by MODULATIVE lightMethod.
    */
   public ColorRGBA getShadowColor() {
       return shadowColor;
   }


   /**
    * @param shadowColor
    *            the shadowColor used by MODULATIVE lightMethod.
    */
   public void setShadowColor(ColorRGBA shadowColor) {
       if (shadowColor == null)
           throw new IllegalArgumentException("shadowColor must not be null!");
       this.shadowColor = shadowColor;
   }


   /**
    * @return the lightingMethod currently in use.
    */
   public LightingMethod getLightingMethod() {
       return lightingMethod;
   }


   /**
     * Sets which method to use with the shadow volume stencils in order to
     * generate shadows in the scene. See javadoc descriptions in the enum
     * LightingMethod for more info.
     * 
     * @param method
     *            method to use
     * @throws IllegalArgumentException
     *             if method is null
     */
   public void setLightingMethod(LightingMethod method) {
       if (method == null) {
           throw new IllegalArgumentException("method can not be null.");
       }
       this.lightingMethod = method;
   }


   /**
    * <code>doRender</code> renders this pass to the framebuffer
    *
    * @param r
    *            Renderer to use for drawing.
    * @see com.jme.renderer.pass.Pass#doRender(com.jme.renderer.Renderer)
    */
   public void doRender(Renderer r) {
       // init states
       init();
       
       if (!renderShadows) {
           renderScene(r);
           if (renderVolume) {
               getShadowLights();
               setupOccluderMeshes();
               generateVolumes();
               drawVolumes(r);
           }
           return;
       }

       // grab the shadowcasting lights
       getShadowLights();

       // grab the occluders
       setupOccluderMeshes();

       // if no occluders or no shadow casting lights, just render the scene normally and return.
       if (occluderMeshes.size() == 0 || shadowLights.size() == 0) {
           //render normal
           renderScene(r);
           cleanup();
           return;
       } 
           
       // otherwise render an ambient pass by masking the diffuse and specular of shadowcasting lights.
       if (lightingMethod == LightingMethod.Additive) {
           maskShadowLights(LightState.MASK_DIFFUSE | LightState.MASK_SPECULAR);
           saveEnforcedStates();
           context.enforceState(noTexture);
           renderScene(r);
           replaceEnforcedStates();
           unmaskShadowLights();
           r.setPolygonOffset(0.0f, -5.0f);
       } else {
           renderScene(r);
       }       

       generateVolumes();

       for (int l = shadowLights.size(); --l >= 0;) {
           Light light = shadowLights.get(l);
           light.setEnabled(false);
       }
       for (int l = shadowLights.size(); --l >= 0;) {
           Light light = shadowLights.get(l);
           // Clear out the stencil buffer
           r.clearStencilBuffer();
           light.setEnabled(true);

           saveEnforcedStates();
           context.enforceState(noTexture);
           context.enforceState(forTesting);
           context.enforceState(colorDisabled);

           if (StencilState.supportsTwoSided()) {
               context.enforceState(noCull);
               context.enforceState(stencilBothFaces);
               volumeNode.getChildren().clear();
               addShadowVolumes(light);
               volumeNode.updateWorldVectors();
               volumeNode.onDraw(r);
           } else {
               context.enforceState(stencilFrontFaces);
               context.enforceState(cullBackFace);
    
               volumeNode.getChildren().clear();
               addShadowVolumes(light);
               volumeNode.updateWorldVectors();
               volumeNode.onDraw(r);
    
               context.enforceState(stencilBackFaces);
               context.enforceState(cullFrontFace);
               volumeNode.onDraw(r);
           }

           context.enforceState(colorEnabled);
           context.enforceState(forColorPassTesting);
           context.enforceState(cullBackFace);
           if (lightingMethod == LightingMethod.Additive) {
               context.enforceState(lights);
               context.enforceState(blended);
               lights.detachAll();
               lights.attach(light);
               context.enforceState(stencilDrawWhenNotSet);
               renderScene(r);
           } else {
               if (rTexture) {
                   context.enforceState(modblended);
                   context.enforceState(zbufferAlways);
                   context.enforceState(cullBackFace);
                   context.enforceState(noLights);
                   context.enforceState(stencilDrawOnlyWhenSet);
    
                   shadowColor.a = 1 - light.getAmbient().a;
                   shadowQuad.setDefaultColor(shadowColor);
                   r.setOrtho();
                   resetShadowQuad(r);
                   shadowQuad.draw(r);
                   r.unsetOrtho();
               }
           }
           light.setEnabled(false);
           replaceEnforcedStates();
       }

       for (int l = shadowLights.size(); --l >= 0;) {
           Light light = shadowLights.get(l);
           light.setEnabled(true);
       }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -