📄 directionalshadowmappass.java
字号:
* @param occluder * The spatial to add as an occluder */ public void addOccluder(Spatial occluder) { occluderNodes.add(occluder); } /** * Initialise the pass render states */ public void init(Renderer r) { if (initialised) { return; } initialised = true; // now it's initialised // the texture that the shadow map will be rendered into. Modulated so // that it can be blended over the scene. shadowMapTexture = new Texture2D(); shadowMapTexture.setApply(Texture.ApplyMode.Modulate); shadowMapTexture .setMinificationFilter(Texture.MinificationFilter.NearestNeighborNoMipMaps); shadowMapTexture.setWrap(Texture.WrapMode.Clamp); shadowMapTexture .setMagnificationFilter(Texture.MagnificationFilter.Bilinear); shadowMapTexture .setRenderToTextureType(Texture.RenderToTextureType.Depth); shadowMapTexture.setMatrix(new Matrix4f()); shadowMapTexture .setEnvironmentalMapMode(Texture.EnvironmentalMapMode.EyeLinear); shadowMapTexture .setDepthCompareMode(DepthTextureCompareMode.RtoTexture); shadowMapTexture .setDepthCompareFunc(DepthTextureCompareFunc.GreaterThanEqual); shadowMapTexture.setDepthMode(DepthTextureMode.Intensity); // configure the texture renderer to output to the texture shadowMapRenderer = DisplaySystem.getDisplaySystem() .createTextureRenderer(shadowMapSize, shadowMapSize, TextureRenderer.Target.Texture2D); shadowMapRenderer.setupTexture(shadowMapTexture); // render state to apply the shadow map texture shadowTextureState = r.createTextureState(); shadowTextureState.setTexture(shadowMapTexture, 0); noClip = r.createClipState(); noClip.setEnabled(false); // render states to use when rendering into the shadmop, no textures or // colours // are required since we're only interested in recording depth // Also only need back faces when rendering the shadow maps noTexture = r.createTextureState(); noTexture.setEnabled(false); colorDisabled = r.createColorMaskState(); colorDisabled.setAll(false); cullFrontFace = r.createCullState(); cullFrontFace.setEnabled(true); cullFrontFace.setCullFace(CullState.Face.Front); noLights = r.createLightState(); noLights.setEnabled(false); // Then rendering and comparing the shadow map with the current // depth the result will be set to alpha 1 if not in shadow and // to 0 if it's is in shadow. However, we're going to blend it into the // scene // so the alpha will be zero if there is no shadow at this location but // > 0 on shadows. discardShadowFragments = r.createBlendState(); discardShadowFragments.setEnabled(true); discardShadowFragments.setBlendEnabled(true); discardShadowFragments .setSourceFunction(BlendState.SourceFunction.SourceAlpha); discardShadowFragments .setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha); // light used to uniformly light the scene when rendering the shadows // themselfs // this is so the geometry colour can be used as the source for blending // - i.e. // transparent shadows rather than matte black brightLights = r.createLightState(); brightLights.setEnabled(true); DirectionalLight light = new DirectionalLight(); light.setDiffuse(new ColorRGBA(1, 1, 1, 1f)); light.setEnabled(true); brightLights.attach(light); darkMaterial = r.createMaterialState(); darkMaterial.setEnabled(true); darkMaterial.setDiffuse(shadowCol); darkMaterial.setAmbient(new ColorRGBA(0, 0, 0, 0f)); darkMaterial.setShininess(0); darkMaterial.setSpecular(new ColorRGBA(0, 0, 0, 0)); darkMaterial.setEmissive(new ColorRGBA(0, 0, 0, 0)); darkMaterial.setMaterialFace(MaterialState.MaterialFace.Front); if (useShaders) { shader = DisplaySystem.getDisplaySystem().getRenderer() .createGLSLShaderObjectsState(); shader.load(getResource("shadowMap.vert"), prefixStream( "const float OFFSET = 0.5 / " + shadowMapSize + ".0;", getResource("shadowMap.frag"))); shader.setUniform("shadowMap", 0); shader.setUniform("offset", 0.0002f); shader.setEnabled(true); } updateShadowCamera(); } public GLSLShaderObjectsState getShader() { return shader; } private InputStream prefixStream(String text, InputStream in) { try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataInputStream dataStream = new DataInputStream(in); byte shaderCode[] = new byte[in.available()]; dataStream.readFully(shaderCode); in.close(); dataStream.close(); bout.write(text.getBytes()); bout.write(shaderCode); bout.close(); return new ByteArrayInputStream(bout.toByteArray()); } catch (IOException e) { throw new RuntimeException("Failed to load shadow map shader:", e); } } private InputStream getResource(String ref) { return Thread.currentThread().getContextClassLoader() .getResourceAsStream("com/jme/renderer/pass/" + ref); } /** * @see com.jme.renderer.pass.Pass#doRender(com.jme.renderer.Renderer) */ public void doRender(Renderer r) { if (occluderNodes.size() == 0) { return; } init(r); updateShadowMap(r); renderShadowedScene(r); } /** * Render the scene with shadows * * @param r * The renderer to use */ protected void renderShadowedScene(Renderer r) { saveEnforcedStates(); context.enforceState(shadowTextureState); context.enforceState(discardShadowFragments); if (useShaders) { Matrix4f view = ((AbstractCamera) r.getCamera()) .getModelViewMatrix(); shader.setUniform("inverseView", view.invert(), false); context.enforceState(shader); } else { context.enforceState(brightLights); context.enforceState(darkMaterial); } // draw the scene, only the shadowed bits will be drawn and blended // with the shadow coloured geometry r.setPolygonOffset(0, -5); for (Spatial spat : spatials) { spat.onDraw(r); } r.renderQueue(); r.clearPolygonOffset(); replaceEnforcedStates(); } /** * Update the shadow map * * @param r * The renderer to being use to display this map */ protected void updateShadowMap(Renderer r) { saveEnforcedStates(); context.enforceState(noClip); context.enforceState(noTexture); context.enforceState(colorDisabled); context.enforceState(cullFrontFace); context.enforceState(noLights); r.setPolygonOffset(0, 5); CullHint cullModeBefore = CullHint.Never; if (!cullOccluders) { cullModeBefore = occludersRenderNode.getCullHint(); occluderNodes.get(0).setCullHint(CullHint.Never); } shadowMapRenderer.render(occludersRenderNode, shadowMapTexture, true); if (!cullOccluders) { occludersRenderNode.setCullHint(cullModeBefore); } r.clearPolygonOffset(); replaceEnforcedStates(); } /** * Update the direction from which the shadows are cast */ protected void updateShadowCamera() { // render the shadow map, use the texture renderer to render anything // thats been added as occluder float scale = shadowMapSize * shadowMapScale; shadowMapRenderer.getCamera().setLocation(shadowCameraLocation); shadowMapRenderer.getCamera().setFrustum(nearPlane, farPlane, -scale, scale, -scale, scale); shadowMapRenderer.getCamera().lookAt(shadowCameraLookAt, Vector3f.UNIT_Y.clone()); shadowMapRenderer.getCamera().setParallelProjection(true); shadowMapRenderer.getCamera().update(); Matrix4f proj = new Matrix4f(); Matrix4f view = new Matrix4f(); proj.set(((AbstractCamera) shadowMapRenderer.getCamera()) .getProjectionMatrix()); view.set(((AbstractCamera) shadowMapRenderer.getCamera()) .getModelViewMatrix()); shadowMapTexture.getMatrix().set( view.multLocal(proj).multLocal(biasMatrix)).transposeLocal(); } /** * @see com.jme.renderer.pass.Pass#cleanUp() */ public void cleanUp() { super.cleanUp(); if (shadowMapRenderer != null) { shadowMapRenderer.cleanup(); } } /** * Remove the contents of the pass */ public void clear() { occluderNodes.clear(); spatials.clear(); } /** * Helper class to get all spatials rendered in one TextureRenderer.render() * call. */ private class OccludersRenderNode extends Node { private static final long serialVersionUID = 7367501683137581101L; public void draw(Renderer r) { Spatial child; for (int i = 0, cSize = occluderNodes.size(); i < cSize; i++) { child = occluderNodes.get(i); if (child != null) child.onDraw(r); } } public void onDraw(Renderer r) { draw(r); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -