TranslucentBucket :

- Added a translucent bucket that is rendered after the processors (usefull for shadows)
- For filters, rendering this bucket is a bit particular, so you can use the TranslucentBucketFilter to render the translucent bucket in the middle of the fillter stack (doc is comming up in the wiki)
- renamed Filter's preRender method to postQueue for consistancy with processors
- added translucent objects in TestPostWater, added a fire (particles) in test transparent shadows

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7540 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 14 years ago
parent 29a4e7e01c
commit 2d4896942d
  1. 3
      engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
  2. 3
      engine/src/core-data/Common/MatDefs/Post/Post.vert
  3. 18
      engine/src/core/com/jme3/post/Filter.java
  4. 38
      engine/src/core/com/jme3/post/FilterPostProcessor.java
  5. 19
      engine/src/core/com/jme3/renderer/RenderManager.java
  6. 8
      engine/src/core/com/jme3/renderer/Renderer.java
  7. 34
      engine/src/core/com/jme3/renderer/queue/RenderQueue.java
  8. 3
      engine/src/core/com/jme3/system/NullRenderer.java
  9. 2
      engine/src/desktop-fx/com/jme3/post/filters/BloomFilter.java
  10. 2
      engine/src/desktop-fx/com/jme3/post/filters/CartoonEdgeFilter.java
  11. 4
      engine/src/desktop-fx/com/jme3/post/filters/ColorOverlayFilter.java
  12. 4
      engine/src/desktop-fx/com/jme3/post/filters/CrossHatchFilter.java
  13. 4
      engine/src/desktop-fx/com/jme3/post/filters/DepthOfFieldFilter.java
  14. 3
      engine/src/desktop-fx/com/jme3/post/filters/FadeFilter.java
  15. 3
      engine/src/desktop-fx/com/jme3/post/filters/FogFilter.java
  16. 2
      engine/src/desktop-fx/com/jme3/post/filters/LightScatteringFilter.java
  17. 3
      engine/src/desktop-fx/com/jme3/post/filters/PosterizationFilter.java
  18. 3
      engine/src/desktop-fx/com/jme3/post/filters/RadialBlurFilter.java
  19. 76
      engine/src/desktop-fx/com/jme3/post/filters/TranslucentBucketFilter.java
  20. 12
      engine/src/desktop-fx/com/jme3/post/ssao/SSAOFilter.java
  21. 10
      engine/src/desktop-fx/com/jme3/water/WaterFilter.java
  22. 32
      engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java
  23. 37
      engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java
  24. 25
      engine/src/test/jme3test/light/TestTransparentShadow.java
  25. 29
      engine/src/test/jme3test/post/TestMultiViewsFilters.java
  26. 90
      engine/src/test/jme3test/water/TestPostWater.java

@ -1259,6 +1259,9 @@ public class OGLESShaderRenderer implements Renderer {
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst){
logger.warning("copyFrameBuffer is not supported.");
}
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth){
logger.warning("copyFrameBuffer is not supported.");
}
/*
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst){
if (GLContext.getCapabilities().GL_EXT_framebuffer_blit){

@ -5,7 +5,6 @@ attribute vec2 inTexCoord;
varying vec2 texCoord;
void main() {
vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
gl_Position = vec4(pos, 0.0, 1.0);
gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
texCoord = inTexCoord;
}

@ -200,7 +200,7 @@ public abstract class Filter implements Savable {
* @param renderManager
* @param viewPort
*/
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
}
/**
@ -211,6 +211,14 @@ public abstract class Filter implements Savable {
public void preFrame(float tpf) {
}
/**
* Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering
* @param renderManager
* @param viewPort
*/
public void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
}
/**
* Override this method if you want to save extra properties when the filter is saved else only basic properties of the filter will be saved
* This method should always begin by super.write(ex);
@ -268,6 +276,14 @@ public abstract class Filter implements Savable {
return false;
}
/**
* Override this method and return false if your Filter does not need the scene texture
* @return
*/
public boolean isRequiresSceneTexture() {
return true;
}
public List<Pass> getPostRenderPasses() {
return postRenderPasses;
}

@ -40,6 +40,7 @@ import com.jme3.export.InputCapsule;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.material.Material;
import com.jme3.post.filters.TranslucentBucketFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.Caps;
import com.jme3.renderer.RenderManager;
@ -80,6 +81,10 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
private int originalHeight;
private int lastFilterIndex = -1;
private boolean cameraInit = false;
// private boolean handleTranslucentBucket = false;
// private FrameBuffer transFrameBuffer;
// private Material transMaterial;
// private boolean isTransparencyRendered=false;
/**
* Create a FilterProcessor constructor
@ -159,8 +164,9 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
filterCam.resize(buff.getWidth(), buff.getHeight(), true);
fsQuad.setPosition(0, 0);
}
if (mat.getAdditionalRenderState().isDepthWrite()) {
mat.getAdditionalRenderState().setDepthWrite(false);
}
fsQuad.setMaterial(mat);
fsQuad.updateGeometricState();
@ -179,14 +185,16 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
for (Iterator<Filter> it = filters.iterator(); it.hasNext();) {
Filter filter = it.next();
if (filter.isEnabled()) {
filter.preRender(renderManager, viewPort);
filter.postQueue(renderManager, viewPort);
}
}
}
Picture pic = new Picture("debug");
public void renderFilterChain(Renderer r) {
public void renderFilterChain(Renderer r, FrameBuffer sceneFb) {
Texture2D tex = filterTexture;
FrameBuffer buff = null;
boolean msDepth = depthTexture != null && depthTexture.getImage().getMultiSamples() > 1;
for (int i = 0; i < filters.size(); i++) {
Filter filter = filters.get(i);
@ -216,22 +224,27 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
}
}
filter.postFrame(renderManager, viewPort, buff, sceneFb);
Material mat = filter.getMaterial();
if (msDepth && filter.isRequiresDepthTexture()) {
mat.setInt("NumSamplesDepth", depthTexture.getImage().getMultiSamples());
}
if (filter.isRequiresSceneTexture()) {
mat.setTexture("Texture", tex);
if (tex.getImage().getMultiSamples() > 1) {
mat.setInt("NumSamples", tex.getImage().getMultiSamples());
} else {
mat.clearParam("NumSamples");
}
}
FrameBuffer buff = outputBuffer;
buff = outputBuffer;
if (i != lastFilterIndex) {
buff = filter.getRenderFrameBuffer();
tex = filter.getRenderedTexture();
}
renderProcessing(r, buff, mat);
}
@ -240,11 +253,13 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
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);
renderFilterChain(renderer, sceneBuffer);
}
@ -336,7 +351,6 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
renderFrameBufferMS.setColorTexture(msColor);
filterTexture = msColor;
depthTexture = msDepth;
// samplePositions = ((LwjglRenderer) renderer).getFrameBufferSamplePositions(renderFrameBufferMS);
} else {
renderFrameBufferMS.setDepthBuffer(Format.Depth);
renderFrameBufferMS.setColorBuffer(Format.RGBA8);
@ -420,4 +434,12 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
numSamples = ic.readInt("numSamples", 0);
filters = ic.readSavableArrayList("filters", null);
}
public Texture2D getDepthTexture() {
return depthTexture;
}
public Texture2D getFilterTexture() {
return filterTexture;
}
}

@ -94,6 +94,7 @@ public class RenderManager {
camLoc = new Vector3f();
//temp technique
private String tmpTech;
private boolean handleTranlucentBucket = true;
/**
* Create a high-level rendering interface over the
@ -607,6 +608,13 @@ public class RenderManager {
}
}
public void renderTranslucentQueue(ViewPort vp) {
RenderQueue rq = vp.getQueue();
if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
}
}
private void setViewPort(Camera cam) {
// this will make sure to update viewport only if needed
if (cam != prevCam || cam.isViewportChanged()) {
@ -729,7 +737,8 @@ public class RenderManager {
proc.postFrame(vp.getOutputFrameBuffer());
}
}
//renders the translucent objects queue after processors have been rendered
renderTranslucentQueue(vp);
// clear any remaining spatials that were not rendered.
clearQueue(vp);
}
@ -768,4 +777,12 @@ public class RenderManager {
public void setAlphaToCoverage(boolean value) {
renderer.setAlphaToCoverage(value);
}
public boolean isHandleTranslucentBucket() {
return handleTranlucentBucket;
}
public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
this.handleTranlucentBucket = handleTranslucentBucket;
}
}

@ -29,7 +29,6 @@
* 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.jme3.renderer;
import com.jme3.light.LightList;
@ -138,6 +137,12 @@ public interface Renderer {
*/
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst);
/**
* Copies contents from src to dst, scaling if neccessary.
* set copyDepth to false ton ly copy the color
*/
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth);
/**
* Sets the framebuffer that will be drawn to.
*/
@ -212,5 +217,4 @@ public interface Renderer {
* @param value
*/
public void setAlphaToCoverage(boolean value);
}

@ -29,7 +29,6 @@
* 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.jme3.renderer.queue;
import com.jme3.renderer.Camera;
@ -42,6 +41,7 @@ public class RenderQueue {
private GeometryList opaqueList;
private GeometryList guiList;
private GeometryList transparentList;
private GeometryList translucentList;
private GeometryList skyList;
private GeometryList shadowRecv;
private GeometryList shadowCast;
@ -50,20 +50,24 @@ public class RenderQueue {
this.opaqueList = new GeometryList(new OpaqueComparator());
this.guiList = new GeometryList(new GuiComparator());
this.transparentList = new GeometryList(new TransparentComparator());
this.translucentList = new GeometryList(new TransparentComparator());
this.skyList = new GeometryList(new NullComparator());
this.shadowRecv = new GeometryList(new OpaqueComparator());
this.shadowCast = new GeometryList(new OpaqueComparator());
}
public enum Bucket {
Gui,
Opaque,
Sky,
Transparent,
Translucent,
Inherit,
}
public enum ShadowMode {
Off,
Cast,
Receive,
@ -89,6 +93,8 @@ public class RenderQueue {
* by material first and front to back within the same material.
* <li>Bucket.Transparent: {@link com.jme3.renderer.queue.TransparentComparator} which
* sorts purely back to front by leading bounding edge with no material sort.
* <li>Bucket.Translucent: {@link com.jme3.renderer.queue.TransparentComparator} which
* sorts purely back to front by leading bounding edge with no material sort. this bucket is rendered after post processors.
* <li>Bucket.Sky: {@link com.jme3.renderer.queue.NullComparator} which does no sorting
* at all.
* <li>Bucket.Gui: {@link com.jme3.renderer.queue.GuiComparator} sorts geometries back to
@ -108,6 +114,9 @@ public class RenderQueue {
case Transparent:
transparentList = new GeometryList(c);
break;
case Translucent:
translucentList = new GeometryList(c);
break;
default:
throw new UnsupportedOperationException("Unknown bucket type: " + bucket);
}
@ -115,8 +124,10 @@ public class RenderQueue {
public void addToShadowQueue(Geometry g, ShadowMode shadBucket) {
switch (shadBucket) {
case Inherit: break;
case Off: break;
case Inherit:
break;
case Off:
break;
case Cast:
shadowCast.add(g);
break;
@ -146,6 +157,9 @@ public class RenderQueue {
case Transparent:
transparentList.add(g);
break;
case Translucent:
translucentList.add(g);
break;
default:
throw new UnsupportedOperationException("Unknown bucket type: " + bucket);
}
@ -173,12 +187,14 @@ public class RenderQueue {
rm.renderGeometry(g);
// make sure to reset queue distance
}
if (obj != null)
if (obj != null) {
obj.queueDistance = Float.NEGATIVE_INFINITY;
}
if (clear)
}
if (clear) {
list.clear();
}
}
public void renderShadowQueue(GeometryList list, RenderManager rm, Camera cam, boolean clear) {
renderGeometryList(list, rm, cam, clear);
@ -207,6 +223,8 @@ public class RenderQueue {
return skyList.size() == 0;
case Transparent:
return transparentList.size() == 0;
case Translucent:
return translucentList.size() == 0;
default:
throw new UnsupportedOperationException("Unsupported bucket type: " + bucket);
}
@ -230,6 +248,10 @@ public class RenderQueue {
case Transparent:
renderGeometryList(transparentList, rm, cam, clear);
break;
case Translucent:
renderGeometryList(translucentList, rm, cam, clear);
break;
default:
throw new UnsupportedOperationException("Unsupported bucket type: " + bucket);
}
@ -239,9 +261,9 @@ public class RenderQueue {
opaqueList.clear();
guiList.clear();
transparentList.clear();
translucentList.clear();
skyList.clear();
shadowCast.clear();
shadowRecv.clear();
}
}

@ -110,6 +110,9 @@ public class NullRenderer implements Renderer {
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
}
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
}
public void setFrameBuffer(FrameBuffer fb) {
}

@ -202,7 +202,7 @@ public class BloomFilter extends Filter {
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
if (glowMode != GlowMode.Scene) {
backupColor = viewPort.getBackgroundColor();
viewPort.setBackgroundColor(ColorRGBA.Black);

@ -67,7 +67,7 @@ public class CartoonEdgeFilter extends Filter {
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
Renderer r = renderManager.getRenderer();
r.setFrameBuffer(normalPass.getRenderFrameBuffer());
renderManager.getRenderer().clearBuffers(true, true, true);

@ -76,10 +76,6 @@ public class ColorOverlayFilter extends Filter {
this.color = color;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
@Override
public void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");

@ -105,10 +105,6 @@ public class CrossHatchFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
@Override
public void cleanUpFilter(Renderer r) {
}

@ -70,10 +70,6 @@ public class DepthOfFieldFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
@Override
public void initFilter(AssetManager assets, RenderManager renderManager,
ViewPort vp, int w, int h) {

@ -71,9 +71,6 @@ public class FadeFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
@Override
public void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {

@ -84,9 +84,6 @@ public class FogFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
/**
* returns the fog color

@ -88,7 +88,7 @@ public class LightScatteringFilter extends Filter {
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera());
// screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth();
// screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight();

@ -88,9 +88,6 @@ public class PosterizationFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
@Override
public void cleanUpFilter(Renderer r) {

@ -74,9 +74,6 @@ public class RadialBlurFilter extends Filter {
return material;
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
}
public float getSampleDist() {
return sampleDist;

@ -0,0 +1,76 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.jme3.post.filters;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.post.Filter;
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.Texture2D;
/**
*
* @author Nehon
*/
public final class TranslucentBucketFilter extends Filter {
private RenderManager renderManager;
@Override
public void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
this.renderManager = rm;
material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
material.setColor("Color", ColorRGBA.White);
Texture2D tex = processor.getFilterTexture();
material.setTexture("Texture", tex);
if (tex.getImage().getMultiSamples() > 1) {
material.setInt("NumSamples", tex.getImage().getMultiSamples());
} else {
material.clearParam("NumSamples");
}
renderManager.setHandleTranslucentBucket(false);
}
/**
* Override this method and return false if your Filter does not need the scene texture
* @return
*/
public boolean isRequiresSceneTexture() {
return false;
}
@Override
public void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
renderManager.setCamera(viewPort.getCamera(), false);
renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
renderManager.getRenderer().setFrameBuffer(sceneBuffer);
viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
}
@Override
public void cleanUpFilter(Renderer r) {
if (renderManager != null) {
renderManager.setHandleTranslucentBucket(true);
}
}
@Override
public Material getMaterial() {
return material;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (renderManager != null) {
renderManager.setHandleTranslucentBucket(!enabled);
}
}
}

@ -70,7 +70,7 @@ public class SSAOFilter extends Filter {
private Pass ssaoPass;
private Material downSampleMat;
private Pass downSamplePass;
private int downSampleFactor = 1;
private float downSampleFactor = 1f;
/**
* Create a Screen Space Ambiant Occlusion Filter
@ -101,7 +101,7 @@ public class SSAOFilter extends Filter {
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
Renderer r = renderManager.getRenderer();
r.setFrameBuffer(normalPass.getRenderFrameBuffer());
renderManager.getRenderer().clearBuffers(true, true, true);
@ -123,7 +123,7 @@ public class SSAOFilter extends Filter {
postRenderPasses = new ArrayList<Pass>();
normalPass = new Pass();
normalPass.init(renderManager.getRenderer(), screenWidth / downSampleFactor, screenHeight / downSampleFactor, Format.RGBA8, Format.Depth);
normalPass.init(renderManager.getRenderer(), (int)(screenWidth / downSampleFactor), (int)(screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
frustumNearFar = new Vector2f();
@ -149,11 +149,11 @@ public class SSAOFilter extends Filter {
@Override
public boolean requiresDepthAsTexture() {
return downSampleFactor == 1;
return true;
}
};
ssaoPass.init(renderManager.getRenderer(), screenWidth / downSampleFactor, screenHeight / downSampleFactor, Format.RGBA8, Format.Depth, 1, ssaoMat);
ssaoPass.init(renderManager.getRenderer(), (int)(screenWidth / downSampleFactor), (int)(screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
postRenderPasses.add(ssaoPass);
@ -174,7 +174,7 @@ public class SSAOFilter extends Filter {
float xScale = 1.0f / w;
float yScale = 1.0f / h;
float blurScale = 2.0f;
float blurScale = 2f;
material.setFloat("XScale", blurScale * xScale);
material.setFloat("YScale", blurScale * yScale);

@ -138,7 +138,7 @@ public class WaterFilter extends Filter {
}
@Override
public void preRender(RenderManager renderManager, ViewPort viewPort) {
public void postQueue(RenderManager renderManager, ViewPort viewPort) {
Camera sceneCam = viewPort.getCamera();
biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
material.setMatrix4("TextureProjMatrix", textureProjMatrix);
@ -171,7 +171,15 @@ public class WaterFilter extends Filter {
reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
}
boolean rtb = true;
if (!renderManager.isHandleTranslucentBucket()) {
renderManager.setHandleTranslucentBucket(true);
rtb = false;
}
renderManager.renderViewPort(reflectionView, savedTpf);
if (!rtb) {
renderManager.setHandleTranslucentBucket(false);
}
renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
renderManager.setCamera(sceneCam, false);
}

@ -42,7 +42,6 @@ import static org.lwjgl.opengl.GL11.*;
public class LwjglGL1Renderer implements GL1Renderer {
private static final Logger logger = Logger.getLogger(LwjglRenderer.class.getName());
private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);
private final StringBuilder stringBuf = new StringBuilder(250);
private final IntBuffer ib1 = BufferUtils.createIntBuffer(1);
@ -51,20 +50,16 @@ public class LwjglGL1Renderer implements GL1Renderer {
private final RenderContext context = new RenderContext();
private final GLObjectManager objManager = new GLObjectManager();
private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);
private int maxTexSize;
private int maxCubeTexSize;
private int maxVertCount;
private int maxTriCount;
private final Statistics statistics = new Statistics();
private int vpX, vpY, vpW, vpH;
private int clipX, clipY, clipW, clipH;
// private Matrix4f worldMatrix = new Matrix4f();
private Matrix4f viewMatrix = new Matrix4f();
// private Matrix4f projMatrix = new Matrix4f();
private boolean colorSet = false;
private boolean materialSet = false;
@ -325,8 +320,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
context.blendMode = state.getBlendMode();
}
if(state.isStencilTest())
if (state.isStencilTest()) {
throw new UnsupportedOperationException("OpenGL 1.1 doesn't support two sided stencil operations.");
}
}
@ -691,8 +687,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
}
public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) {
if (count > 1)
if (count > 1) {
throw new UnsupportedOperationException();
}
glDrawArrays(convertElementMode(mode), 0, vertCount);
}
@ -725,14 +722,16 @@ public class LwjglGL1Renderer implements GL1Renderer {
switch (vb.getBufferType()) {
case Position:
if (!(data instanceof FloatBuffer))
if (!(data instanceof FloatBuffer)) {
throw new UnsupportedOperationException();
}
glVertexPointer(comps, vb.getStride(), (FloatBuffer) data);
break;
case Normal:
if (!(data instanceof FloatBuffer))
if (!(data instanceof FloatBuffer)) {
throw new UnsupportedOperationException();
}
glNormalPointer(vb.getStride(), (FloatBuffer) data);
break;
@ -746,8 +745,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
}
break;
case TexCoord:
if (!(data instanceof FloatBuffer))
if (!(data instanceof FloatBuffer)) {
throw new UnsupportedOperationException();
}
glTexCoordPointer(comps, vb.getStride(), (FloatBuffer) data);
break;
@ -818,8 +818,6 @@ public class LwjglGL1Renderer implements GL1Renderer {
}
}
public void clearVertexAttribs() {
for (int i = 0; i < 16; i++) {
VertexBuffer vb = context.boundAttribs[i];
@ -874,8 +872,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
}
public void renderMesh(Mesh mesh, int lod, int count) {
if (mesh.getVertexCount() == 0)
if (mesh.getVertexCount() == 0) {
return;
}
if (context.pointSize != mesh.getPointSize()) {
glPointSize(mesh.getPointSize());
@ -887,8 +886,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
}
boolean dynamic = false;
if (mesh.getBuffer(Type.InterleavedData) != null)
if (mesh.getBuffer(Type.InterleavedData) != null) {
throw new UnsupportedOperationException();
}
if (mesh.getNumLodLevels() == 0) {
IntMap<VertexBuffer> bufs = mesh.getBuffers();
@ -929,6 +929,9 @@ public class LwjglGL1Renderer implements GL1Renderer {
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
}
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
}
public void setFrameBuffer(FrameBuffer fb) {
}
@ -943,5 +946,4 @@ public class LwjglGL1Renderer implements GL1Renderer {
public void deleteBuffer(VertexBuffer vb) {
}
}

@ -618,8 +618,7 @@ public class LwjglRenderer implements Renderer {
|| context.backStencilDepthFailOperation != state.getBackStencilDepthFailOperation()
|| context.backStencilDepthPassOperation != state.getBackStencilDepthPassOperation()
|| context.frontStencilFunction != state.getFrontStencilFunction()
|| context.backStencilFunction!=state.getBackStencilFunction()
){
|| context.backStencilFunction != state.getBackStencilFunction()) {
context.frontStencilStencilFailOperation = state.getFrontStencilStencilFailOperation(); //terrible looking, I know
context.frontStencilDepthFailOperation = state.getFrontStencilDepthFailOperation();
@ -635,21 +634,17 @@ public class LwjglRenderer implements Renderer {
glStencilOpSeparate(GL_FRONT,
glStencilOpFromStencilOp(state.getFrontStencilStencilFailOperation()),
glStencilOpFromStencilOp(state.getFrontStencilDepthFailOperation()),
glStencilOpFromStencilOp(state.getFrontStencilDepthPassOperation())
);
glStencilOpFromStencilOp(state.getFrontStencilDepthPassOperation()));
glStencilOpSeparate(GL_BACK,
glStencilOpFromStencilOp(state.getBackStencilStencilFailOperation()),
glStencilOpFromStencilOp(state.getBackStencilDepthFailOperation()),
glStencilOpFromStencilOp(state.getBackStencilDepthPassOperation())
);
glStencilOpFromStencilOp(state.getBackStencilDepthPassOperation()));
glStencilFuncSeparate(GL_FRONT,
glStencilFuncFromStencilFunc(state.getFrontStencilFunction()),
0,Integer.MAX_VALUE
);
0, Integer.MAX_VALUE);
glStencilFuncSeparate(GL_BACK,
glStencilFuncFromStencilFunc(state.getBackStencilFunction()),
0,Integer.MAX_VALUE
);
0, Integer.MAX_VALUE);
} else {
glDisable(GL_STENCIL_TEST);
}
@ -1179,6 +1174,10 @@ public class LwjglRenderer implements Renderer {
|* Framebuffers *|
\*********************************************************************/
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
copyFrameBuffer(src, dst, true);
}
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
if (GLContext.getCapabilities().GL_EXT_framebuffer_blit) {
int srcW = 0;
int srcH = 0;
@ -1212,11 +1211,15 @@ public class LwjglRenderer implements Renderer {
dstW = dst.getWidth();
dstH = dst.getHeight();
}
int mask = GL_COLOR_BUFFER_BIT;
if (copyDepth) {
mask |= GL_DEPTH_BUFFER_BIT;
}
glBlitFramebufferEXT(0, 0, srcW, srcH,
0, 0, dstW, dstH,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
0, 0, dstW, dstH, mask,
GL_NEAREST);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prevFBO);
try {
checkFrameBufferError();
@ -1643,9 +1646,9 @@ public class LwjglRenderer implements Renderer {
}
}
if (context.pointSprite)
if (context.pointSprite) {
return; // Attempt to fix glTexParameter crash for some ATI GPUs
}
// repeat modes
switch (tex.getType()) {
case ThreeDimensional:
@ -1723,8 +1726,9 @@ public class LwjglRenderer implements Renderer {
// Yes, some OpenGL2 cards (GeForce 5) still dont support NPOT.
if (!GLContext.getCapabilities().GL_ARB_texture_non_power_of_two) {
if (img.getData(0) == null)
if (img.getData(0) == null) {
throw new RendererException("non-power-of-2 framebuffer textures are not supported by the video hardware");
}
if (img.getWidth() != 0 && img.getHeight() != 0) {
if (!FastMath.isPowerOfTwo(img.getWidth())
@ -1740,9 +1744,10 @@ public class LwjglRenderer implements Renderer {
// Check if graphics card doesn't support multisample textures
if (!GLContext.getCapabilities().GL_ARB_texture_multisample) {
if (img.getMultiSamples() > 1)
if (img.getMultiSamples() > 1) {
throw new RendererException("Multisample textures not supported by graphics hardware");
}
}
if (target == GL_TEXTURE_CUBE_MAP) {
List<ByteBuffer> data = img.getData();

@ -33,6 +33,8 @@
package jme3test.light;
import com.jme3.app.SimpleApplication;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
@ -107,6 +109,29 @@ public class TestTransparentShadow extends SimpleApplication {
rootNode.attachChild(teaGeom);
/** Uses Texture from jme3-test-data library! */
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
//mat_red.getAdditionalRenderState().setDepthTest(true);
//mat_red.getAdditionalRenderState().setDepthWrite(true);
fire.setMaterial(mat_red);
fire.setImagesX(2); fire.setImagesY(2); // 2x2 texture animation
fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red
fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
fire.setInitialVelocity(new Vector3f(0, 2, 0));
fire.setStartSize(0.6f);
fire.setEndSize(0.1f);
fire.setGravity(0);
fire.setLowLife(0.5f);
fire.setHighLife(1.5f);
fire.setVelocityVariation(0.3f);
fire.setLocalTranslation(1.0f, 0, 1.0f);
fire.setLocalScale(0.3f);
fire.setQueueBucket(Bucket.Translucent);
rootNode.attachChild(fire);
PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 1);
pssmRenderer.setDirection(new Vector3f(0.01f, -1f, 0.01f).normalizeLocal());
pssmRenderer.setLambda(0.55f);

@ -42,6 +42,7 @@ import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.post.filters.CartoonEdgeFilter;
import com.jme3.post.filters.CrossHatchFilter;
import com.jme3.post.filters.FogFilter;
import com.jme3.post.filters.RadialBlurFilter;
import com.jme3.post.ssao.SSAOFilter;
@ -62,6 +63,7 @@ public class TestMultiViewsFilters extends SimpleApplication {
// create the geometry and attach it
Geometry teaGeom = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
teaGeom.scale(3);
teaGeom.getMaterial().setColor("GlowColor", ColorRGBA.Green);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
@ -109,18 +111,38 @@ public class TestMultiViewsFilters extends SimpleApplication {
view4.setClearFlags(true, true, true);
view4.attachScene(rootNode);
// Camera cam5 = new Camera(200, 200);
// cam5.setFrustumPerspective(45f, (float)cam.getWidth() / cam.getHeight(), 1f, 1000f);
// cam5.setName("cam5");
// cam5.setViewPort(5.23f, 6.33f, 0.56f, 1.66f);
// this.setViewPortAreas(5.23f, 6.33f, 0.56f, 1.66f);
// this.setViewPortCamSize(200, 200);
// 1046,1266,112,332
Camera cam5 = cam.clone();
cam5.setName("cam5");
cam5.setViewPort(1046f/settings.getWidth(), 1266f/settings.getWidth(), 112f/settings.getHeight(), 332f/settings.getHeight());
cam5.setLocation(new Vector3f(0.2846221f, 6.4271426f, 0.23380789f));
cam5.setRotation(new Quaternion(0.004381671f, 0.72363687f, -0.69015175f, 0.0045953835f));
final ViewPort view5 = renderManager.createMainView("center", cam5);
view5.setClearFlags(true, true, true);
view5.attachScene(rootNode);
rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));
final FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
final FilterPostProcessor fpp2 = new FilterPostProcessor(assetManager);
final FilterPostProcessor fpp3 = new FilterPostProcessor(assetManager);
final FilterPostProcessor fpp4 = new FilterPostProcessor(assetManager);
final FilterPostProcessor fpp5 = new FilterPostProcessor(assetManager);
// fpp.addFilter(new WaterFilter(rootNode, Vector3f.UNIT_Y.mult(-1)));
fpp3.addFilter(new CartoonEdgeFilter());
fpp2.addFilter(new BloomFilter());
fpp2.addFilter(new CrossHatchFilter());
final FogFilter ff = new FogFilter(ColorRGBA.Yellow, 0.7f, 2);
fpp.addFilter(ff);
@ -133,10 +155,13 @@ public class TestMultiViewsFilters extends SimpleApplication {
fpp4.addFilter(f);
SSAOUI ui = new SSAOUI(inputManager, f);
fpp5.addFilter(new BloomFilter(BloomFilter.GlowMode.Objects));
viewPort.addProcessor(fpp);
view2.addProcessor(fpp2);
view3.addProcessor(fpp3);
view4.addProcessor(fpp4);
view5.addProcessor(fpp5);
@ -149,11 +174,13 @@ public class TestMultiViewsFilters extends SimpleApplication {
view2.removeProcessor(fpp2);
view3.removeProcessor(fpp3);
view4.removeProcessor(fpp4);
view5.removeProcessor(fpp5);
} else {
viewPort.addProcessor(fpp);
view2.addProcessor(fpp2);
view3.addProcessor(fpp3);
view4.addProcessor(fpp4);
view5.addProcessor(fpp5);
}
filterEnabled = !filterEnabled;
}

@ -3,20 +3,29 @@ package jme3test.water;
import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.bounding.BoundingBox;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.DepthOfFieldFilter;
import com.jme3.post.filters.LightScatteringFilter;
import com.jme3.post.filters.TranslucentBucketFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
@ -35,7 +44,6 @@ import jme3tools.converters.ImageToAwt;
*/
public class TestPostWater extends SimpleApplication {
private FilterPostProcessor fpp;
private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f);
private WaterFilter water;
TerrainQuad terrain;
@ -65,7 +73,7 @@ public class TestPostWater extends SimpleApplication {
l.setColor(ColorRGBA.White.clone().multLocal(0.3f));
mainScene.addLight(l);
flyCam.setMoveSpeed(50);
flyCam.setMoveSpeed(100);
cam.setLocation(new Vector3f(-700, 100, 300));
cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0}));
@ -80,11 +88,24 @@ public class TestPostWater extends SimpleApplication {
waves.setLooping(true);
audioRenderer.playSource(waves);
//private FilterPostProcessor fpp;
fpp = new FilterPostProcessor(assetManager);
// fpp.setNumSamples(4);
water = new WaterFilter(rootNode, lightDir);
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
fpp.addFilter(water);
DepthOfFieldFilter dof=new DepthOfFieldFilter();
dof.setFocusDistance(0);
dof.setFocusRange(100);
fpp.addFilter(new TranslucentBucketFilter());
fpp.addFilter(dof);
// fpp.setNumSamples(4);
water.setWaveScale(0.003f);
water.setMaxAmplitude(2f);
water.setFoamExistence(new Vector3f(1f, 4, 0.5f));
@ -96,7 +117,9 @@ public class TestPostWater extends SimpleApplication {
//water.setFoamHardness(0.6f);
water.setWaterHeight(initialWaterHeight);
fpp.addFilter(water);
//
viewPort.addProcessor(fpp);
inputManager.addListener(new ActionListener() {
@ -118,6 +141,59 @@ public class TestPostWater extends SimpleApplication {
inputManager.addMapping("foam1", new KeyTrigger(keyInput.KEY_1));
inputManager.addMapping("foam2", new KeyTrigger(keyInput.KEY_2));
inputManager.addMapping("foam3", new KeyTrigger(keyInput.KEY_3));
createBox();
createFire();
}
Geometry box;
private void createBox() {
//creating a transluscent box
box = new Geometry("box", new Box(new Vector3f(0, 0, 0), 50, 50, 50));
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", new ColorRGBA(1.0f, 0, 0, 0.3f));
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
//mat.getAdditionalRenderState().setDepthWrite(false);
//mat.getAdditionalRenderState().setDepthTest(false);
box.setMaterial(mat);
box.setQueueBucket(Bucket.Translucent);
//creating a post view port
// ViewPort post=renderManager.createPostView("transpPost", cam);
// post.setClearFlags(false, true, true);
box.setLocalTranslation(-600, 0, 300);
//attaching the box to the post viewport
//Don't forget to updateGeometricState() the box in the simpleUpdate
// post.attachScene(box);
rootNode.attachChild(box);
}
private void createFire() {
/** Uses Texture from jme3-test-data library! */
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
fire.setMaterial(mat_red);
fire.setImagesX(2);
fire.setImagesY(2); // 2x2 texture animation
fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red
fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
fire.setInitialVelocity(new Vector3f(0, 2, 0));
fire.setStartSize(10f);
fire.setEndSize(1f);
fire.setGravity(0);
fire.setLowLife(0.5f);
fire.setHighLife(1.5f);
fire.setVelocityVariation(0.3f);
fire.setLocalTranslation(-500, 30, 300);
fire.setQueueBucket(Bucket.Translucent);
rootNode.attachChild(fire);
}
private void createTerrain(Node rootNode) {
@ -138,7 +214,7 @@ public class TestPostWater extends SimpleApplication {
rock.setWrap(WrapMode.Repeat);
matRock.setTexture("DiffuseMap_2", rock);
matRock.setFloat("DiffuseMap_2_scale", 128);
Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.png");
Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
normalMap0.setWrap(WrapMode.Repeat);
Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
normalMap1.setWrap(WrapMode.Repeat);
@ -171,7 +247,6 @@ public class TestPostWater extends SimpleApplication {
rootNode.attachChild(terrain);
}
//This part is to emulate tides, slightly varrying the height of the water plane
private float time = 0.0f;
private float waterHeight = 0.0f;
@ -180,6 +255,7 @@ public class TestPostWater extends SimpleApplication {
@Override
public void simpleUpdate(float tpf) {
super.simpleUpdate(tpf);
// box.updateGeometricState();
time += tpf;
waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f;
water.setWaterHeight(initialWaterHeight + waterHeight);

Loading…
Cancel
Save