/** * renders a filter on a fullscreen quad * * @param r * @param buff * @param mat */ private void renderProcessing(Renderer r, FrameBuffer buff, Material mat) { if (buff == outputBuffer) { fsQuad.setWidth(width); fsQuad.setHeight(height); filterCam.resize(originalWidth, originalHeight, true); fsQuad.setPosition(left * originalWidth, bottom * originalHeight); } else { fsQuad.setWidth(buff.getWidth()); fsQuad.setHeight(buff.getHeight()); filterCam.resize(buff.getWidth(), buff.getHeight(), true); fsQuad.setPosition(0, 0); } if (mat.getAdditionalRenderState().isDepthWrite()) { mat.getAdditionalRenderState().setDepthTest(false); mat.getAdditionalRenderState().setDepthWrite(false); } fsQuad.setMaterial(mat); fsQuad.updateGeometricState(); renderManager.setCamera(filterCam, true); r.setFrameBuffer(buff); r.clearBuffers(false, true, true); renderManager.renderGeometry(fsQuad); }
public static void getPreNormals( RenderManager renderManager, Pass normalPass, ViewPort viewPort) { curCount++; // do we already have a valid cache to set the framebuffer to? Renderer r = renderManager.getRenderer(); if (cachedPreNormals != null) { r.copyFrameBuffer(cachedPreNormals, normalPass.getRenderFrameBuffer(), false); } else { // lets make the prenormals r.setFrameBuffer(normalPass.getRenderFrameBuffer()); renderManager.getRenderer().clearBuffers(true, true, true); if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) { renderManager.setForcedTechnique("PreNormalPass15"); } else { renderManager.setForcedTechnique("PreNormalPass"); } renderManager.renderViewPortQueues(viewPort, false); renderManager.setForcedTechnique(null); // if we should cache this, do it now if (lastNormalPassesCount > 1) { cachedPreNormals = normalPass.getRenderFrameBuffer(); } } renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer()); }
@SuppressWarnings("fallthrough") public void postQueue(RenderQueue rq) { GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive); if (sceneReceivers.size() == 0 || occluders.size() == 0) { return; } updateShadowCams(viewPort.getCamera()); Renderer r = renderManager.getRenderer(); renderManager.setForcedMaterial(preshadowMat); renderManager.setForcedTechnique("PreShadow"); for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) { if (debugfrustums) { doDisplayFrustumDebug(shadowMapIndex); } renderShadowMap(shadowMapIndex, occluders, sceneReceivers); } debugfrustums = false; if (flushQueues) { occluders.clear(); } // restore setting for future rendering r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); renderManager.setForcedTechnique(null); renderManager.setCamera(viewPort.getCamera(), false); }
/** * Preloads this material for the given render manager. * * <p>Preloading the material can ensure that when the material is first used for rendering, there * won't be any delay since the material has been already been setup for rendering. * * @param rm The render manager to preload for */ public void preload(RenderManager rm) { autoSelectTechnique(rm); Renderer r = rm.getRenderer(); TechniqueDef techDef = technique.getDef(); Collection<MatParam> params = paramValues.values(); for (MatParam param : params) { if (param instanceof MatParamTexture) { MatParamTexture texParam = (MatParamTexture) param; r.setTexture(0, texParam.getTextureValue()); } else { if (!techDef.isUsingShaders()) { continue; } technique.updateUniformParam(param.getName(), param.getVarType(), param.getValue()); } } Shader shader = technique.getShader(); if (techDef.isUsingShaders()) { r.setShader(shader); } }
@Override protected void postQueue(RenderQueue renderQueue) { Renderer r = renderManager.getRenderer(); r.setFrameBuffer(normalPass.getRenderFrameBuffer()); renderManager.getRenderer().clearBuffers(true, true, true); renderManager.setForcedTechnique("PreNormalPass"); renderManager.renderViewPortQueues(viewPort, false); renderManager.setForcedTechnique(null); renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer()); }
public void postQueue(RenderQueue rq) { GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); if (occluders.size() == 0) { noOccluders = true; return; } else { noOccluders = false; } GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive); // update frustum points based on current camera Camera viewCam = viewPort.getCamera(); ShadowUtil.updateFrustumPoints( viewCam, viewCam.getFrustumNear(), viewCam.getFrustumFar(), 1.0f, points); Vector3f frustaCenter = new Vector3f(); for (Vector3f point : points) { frustaCenter.addLocal(point); } frustaCenter.multLocal(1f / 8f); // update light direction shadowCam.setProjectionMatrix(null); shadowCam.setParallelProjection(true); // shadowCam.setFrustumPerspective(45, 1, 1, 20); shadowCam.lookAtDirection(direction, Vector3f.UNIT_Y); shadowCam.update(); shadowCam.setLocation(frustaCenter); shadowCam.update(); shadowCam.updateViewProjection(); // render shadow casters to shadow map ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points); Renderer r = renderManager.getRenderer(); renderManager.setCamera(shadowCam, false); renderManager.setForcedMaterial(preshadowMat); r.setFrameBuffer(shadowFB); r.clearBuffers(false, true, false); viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true); r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); renderManager.setCamera(viewCam, false); }
public void postFrame(FrameBuffer out) { FrameBuffer sceneBuffer = renderFrameBuffer; if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL31)) { renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer); } else if (renderFrameBufferMS != null) { sceneBuffer = renderFrameBufferMS; } renderFilterChain(renderer, sceneBuffer); renderer.setFrameBuffer(outputBuffer); // viewport can be null if no filters are enabled if (viewPort != null) { renderManager.setCamera(viewPort.getCamera(), false); } }
public void disableClip() { if (clipWasSet) { r.clearClipRect(); clipWasSet = false; } }
public void enableClip(int x0, int y0, int x1, int y1) { clipWasSet = true; r.setClipRect(x0, getHeight() - y1, x1 - x0, y1 - y0); }
public void reshape(ViewPort vp, int w, int h) { // this has no effect at first init but is useful when resizing the canvas with multi views Camera cam = vp.getCamera(); cam.setViewPort(left, right, bottom, top); // resizing the camera to fit the new viewport and saving original dimensions cam.resize(w, h, false); left = cam.getViewPortLeft(); right = cam.getViewPortRight(); top = cam.getViewPortTop(); bottom = cam.getViewPortBottom(); originalWidth = w; originalHeight = h; cam.setViewPort(0, 1, 0, 1); // computing real dimension of the viewport and resizing he camera width = (int) (w * (Math.abs(right - left))); height = (int) (h * (Math.abs(bottom - top))); width = Math.max(1, width); height = Math.max(1, height); cam.resize(width, height, false); cameraInit = true; computeDepth = false; if (renderFrameBuffer == null) { outputBuffer = viewPort.getOutputFrameBuffer(); } Collection<Caps> caps = renderer.getCaps(); // 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 (caps.contains(Caps.OpenGL31)) { Texture2D msColor = new Texture2D(width, height, numSamples, Format.RGBA8); Texture2D msDepth = new Texture2D(width, height, numSamples, Format.Depth); renderFrameBufferMS.setDepthTexture(msDepth); renderFrameBufferMS.setColorTexture(msColor); filterTexture = msColor; depthTexture = msDepth; } else { renderFrameBufferMS.setDepthBuffer(Format.Depth); renderFrameBufferMS.setColorBuffer(Format.RGBA8); } } if (numSamples <= 1 || !caps.contains(Caps.OpenGL31)) { renderFrameBuffer = new FrameBuffer(width, height, 1); renderFrameBuffer.setDepthBuffer(Format.Depth); filterTexture = new Texture2D(width, height, Format.RGBA8); renderFrameBuffer.setColorTexture(filterTexture); } for (Iterator<Filter> it = filters.iterator(); it.hasNext(); ) { Filter filter = it.next(); initFilter(filter, vp); } if (renderFrameBufferMS != null) { viewPort.setOutputFrameBuffer(renderFrameBufferMS); } else { viewPort.setOutputFrameBuffer(renderFrameBuffer); } }
protected void renderMultipassLighting(Shader shader, Geometry g, RenderManager rm) { Renderer r = rm.getRenderer(); LightList lightList = g.getWorldLightList(); Uniform lightDir = shader.getUniform("g_LightDirection"); Uniform lightColor = shader.getUniform("g_LightColor"); Uniform lightPos = shader.getUniform("g_LightPosition"); Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); boolean isFirstLight = true; boolean isSecondLight = false; for (int i = 0; i < lightList.size(); i++) { Light l = lightList.get(i); if (l instanceof AmbientLight) { continue; } if (isFirstLight) { // set ambient color for first light only ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); isFirstLight = false; isSecondLight = true; } else if (isSecondLight) { ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); // apply additive blending for 2nd and future lights r.applyRenderState(additiveLight); isSecondLight = false; } TempVars vars = TempVars.get(); Quaternion tmpLightDirection = vars.quat1; Quaternion tmpLightPosition = vars.quat2; ColorRGBA tmpLightColor = vars.color; Vector4f tmpVec = vars.vect4f; ColorRGBA color = l.getColor(); tmpLightColor.set(color); tmpLightColor.a = l.getType().getId(); lightColor.setValue(VarType.Vector4, tmpLightColor); switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; Vector3f dir = dl.getDirection(); tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1); lightPos.setValue(VarType.Vector4, tmpLightPosition); tmpLightDirection.set(0, 0, 0, 0); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; case Point: PointLight pl = (PointLight) l; Vector3f pos = pl.getPosition(); float invRadius = pl.getInvRadius(); tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius); lightPos.setValue(VarType.Vector4, tmpLightPosition); tmpLightDirection.set(0, 0, 0, 0); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; case Spot: SpotLight sl = (SpotLight) l; Vector3f pos2 = sl.getPosition(); Vector3f dir2 = sl.getDirection(); float invRange = sl.getInvSpotRange(); float spotAngleCos = sl.getPackedAngleCos(); tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); lightPos.setValue(VarType.Vector4, tmpLightPosition); // We transform the spot directoin in view space here to save 5 varying later in the // lighting shader // one vec4 less and a vec4 that becomes a vec3 // the downside is that spotAngleCos decoding happen now in the frag shader. tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; default: throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); } vars.release(); r.setShader(shader); r.renderMesh(g.getMesh(), g.getLodLevel(), 1); } if (isFirstLight && lightList.size() > 0) { // There are only ambient lights in the scene. Render // a dummy "normal light" so we can see the ambient ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); lightPos.setValue(VarType.Vector4, nullDirLight); r.setShader(shader); r.renderMesh(g.getMesh(), g.getLodLevel(), 1); } }
/** * Called by {@link RenderManager} to render the geometry by using this material. * * <p>The material is rendered as follows: * * <ul> * <li>Determine which technique to use to render the material - either what the user selected * via {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) * Material.selectTechnique()}, or the first default technique that the renderer supports * (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering * capabilities}) * <ul> * <li>If the technique has been changed since the last frame, then it is notified via * {@link Technique#makeCurrent(com.jme3.asset.AssetManager, boolean, * java.util.EnumSet) Technique.makeCurrent()}. If the technique wants to use a shader * to render the model, it should load it at this part - the shader should have all * the proper defines as declared in the technique definition, including those that * are bound to material parameters. The technique can re-use the shader from the last * frame if no changes to the defines occurred. * </ul> * <li>Set the {@link RenderState} to use for rendering. The render states are applied in this * order (later RenderStates override earlier RenderStates): * <ol> * <li>{@link TechniqueDef#getRenderState() Technique Definition's RenderState} - i.e. * specific renderstate that is required for the shader. * <li>{@link #getAdditionalRenderState() Material Instance Additional RenderState} - i.e. * ad-hoc renderstate set per model * <li>{@link RenderManager#getForcedRenderState() RenderManager's Forced RenderState} - * i.e. renderstate requested by a {@link com.jme3.post.SceneProcessor} or * post-processing filter. * </ol> * <li>If the technique {@link TechniqueDef#isUsingShaders() uses a shader}, then the uniforms * of the shader must be updated. * <ul> * <li>Uniforms bound to material parameters are updated based on the current material * parameter values. * <li>Uniforms bound to world parameters are updated from the RenderManager. Internally * {@link UniformBindingManager} is used for this task. * <li>Uniforms bound to textures will cause the texture to be uploaded as necessary. The * uniform is set to the texture unit where the texture is bound. * </ul> * <li>If the technique uses a shader, the model is then rendered according to the lighting mode * specified on the technique definition. * <ul> * <li>{@link LightMode#SinglePass single pass light mode} fills the shader's light * uniform arrays with the first 4 lights and renders the model once. * <li>{@link LightMode#MultiPass multi pass light mode} light mode renders the model * multiple times, for the first light it is rendered opaque, on subsequent lights it * is rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth * writing disabled. * </ul> * <li>For techniques that do not use shaders, fixed function OpenGL is used to render the model * (see {@link GL1Renderer} interface): * <ul> * <li>OpenGL state ({@link FixedFuncBinding}) that is bound to material parameters is * updated. * <li>The texture set on the material is uploaded and bound. Currently only 1 texture is * supported for fixed function techniques. * <li>If the technique uses lighting, then OpenGL lighting state is updated based on the * light list on the geometry, otherwise OpenGL lighting is disabled. * <li>The mesh is uploaded and rendered. * </ul> * </ul> * * @param geom The geometry to render * @param rm The render manager requesting the rendering */ public void render(Geometry geom, RenderManager rm) { autoSelectTechnique(rm); Renderer r = rm.getRenderer(); TechniqueDef techDef = technique.getDef(); if (techDef.getLightMode() == LightMode.MultiPass && geom.getWorldLightList().size() == 0) { return; } if (rm.getForcedRenderState() != null) { r.applyRenderState(rm.getForcedRenderState()); } else { if (techDef.getRenderState() != null) { r.applyRenderState( techDef.getRenderState().copyMergedTo(additionalState, mergedRenderState)); } else { r.applyRenderState(RenderState.DEFAULT.copyMergedTo(additionalState, mergedRenderState)); } } // update camera and world matrices // NOTE: setWorldTransform should have been called already if (techDef.isUsingShaders()) { // reset unchanged uniform flag clearUniformsSetByCurrent(technique.getShader()); rm.updateUniformBindings(technique.getWorldBindUniforms()); } // setup textures and uniforms for (int i = 0; i < paramValues.size(); i++) { MatParam param = paramValues.getValue(i); param.apply(r, technique); } Shader shader = technique.getShader(); // send lighting information, if needed switch (techDef.getLightMode()) { case Disable: r.setLighting(null); break; case SinglePass: updateLightListUniforms(shader, geom, 4); break; case FixedPipeline: r.setLighting(geom.getWorldLightList()); break; case MultiPass: // NOTE: Special case! resetUniformsNotSetByCurrent(shader); renderMultipassLighting(shader, geom, rm); // very important, notice the return statement! return; } // upload and bind shader if (techDef.isUsingShaders()) { // any unset uniforms will be set to 0 resetUniformsNotSetByCurrent(shader); r.setShader(shader); } r.renderMesh(geom.getMesh(), geom.getLodLevel(), 1); }