hi there
here's yet another Pass. it renders the outline of objects in the scene. the code is part of the cell shading technique as described at gamedev.net: http://www.gamedev.net/reference/articles/article1438.asp
the same technique can be used to render wireframe on top of models (wireframe and models visible).
if you people think this stuff is useful, please tell me, then i'll be glad do donate it to jme. othewise it might land in my own game (which is GPL not BDS).
any improvements, suggestions and opinions are welcome.
a screenshot is available at : http://moenia.sourceforge.net/images/screenshots/outline.png
(note that it was made without antialiasing or line smoothing.
TestOutlineRenderPass.java
import com.jme.app.SimplePassGame;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.SharedNode;
import com.jmex.model.XMLparser.JmeBinaryReader;
/*
* Created on Jan 19, 2006
*/
/**
* @author Beskid Lucian Cristian
*/
public class TestOutlineRenderPass extends SimplePassGame
{
private Node model = null;
protected void simpleInitGame()
{
display.setTitle("Outline render pass test");
display.getRenderer().setBackgroundColor(new ColorRGBA(0.5f, 0.7f, 1f, 1f));
cam.setFrustumPerspective(55.0f, (float) display.getWidth() / (float) display.getHeight(), 1, 1000);
cam.setLocation(new Vector3f(500, 0, 0));
cam.lookAt(new Vector3f(0,0,0), new Vector3f(0,1,0));
PointLight light = new PointLight();
light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
light.setLocation(new Vector3f(0, 30, 0));
light.setEnabled(true);
lightState.attach(light);
Node normalObjects = new Node("normal");
Node outlinedObjects = new Node("outlined");
OutlineRenderPass outlineRenderPass = new OutlineRenderPass();
outlineRenderPass.add(outlinedObjects);
outlineRenderPass.setEnabled(true);
RenderPass renderPass = new RenderPass();
renderPass.add(normalObjects);
renderPass.setEnabled(true);
pManager.add(outlineRenderPass);
pManager.add(renderPass);
rootNode.attachChild(normalObjects);
rootNode.attachChild(outlinedObjects);
// load objects
JmeBinaryReader reader = new JmeBinaryReader();
try
{
model = reader.loadBinaryFormat(getClass().getClassLoader().getResourceAsStream("jmetest/data/model/bike.jme"));
}
catch (Exception e)
{
e.printStackTrace();
}
if (model != null) {
SharedNode outlinedModel = new SharedNode("outlined.model", model);
SharedNode normalModel = new SharedNode("normal.model", model);
outlinedModel.setLocalTranslation(new Vector3f(0, 200, 0));
normalModel.setLocalTranslation(new Vector3f(0, -200, 0));
outlinedObjects.attachChild(outlinedModel);
normalObjects.attachChild(normalModel);
}
rootNode.updateGeometricState(0, true);
rootNode.updateRenderState();
}
public static void main(String[] args)
{
TestOutlineRenderPass app = new TestOutlineRenderPass();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
}
OutlineRenderPass.java
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.Pass;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Spatial;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.WireframeState;
import com.jme.system.DisplaySystem;
/**
* @author Beskid Lucian Cristian
*/
public class OutlineRenderPass extends RenderPass
{
public static final float DEFAULT_LINE_WIDTH = 3f;
public static final ColorRGBA DEFAULT_OUTLINE_COLOR = ColorRGBA.darkGray;
public static final Pass DEFAULT_SECOND_RENDER_PASS = new RenderPass();
private RenderState[] backupStates = new RenderState[RenderState.RS_MAX_STATE];
// render states needed to draw the outline
private WireframeState wireframeState;
private CullState cullFront;
private LightState noLights;
private TextureState noTexture;
private AlphaState alphaState;
public OutlineRenderPass()
{
wireframeState = DisplaySystem.getDisplaySystem().getRenderer().createWireframeState();
wireframeState.setFace(WireframeState.WS_FRONT);
wireframeState.setLineWidth(DEFAULT_LINE_WIDTH);
wireframeState.setEnabled(true);
cullFront = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
cullFront.setCullMode(CullState.CS_FRONT);
cullFront.setEnabled(true);
noLights = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
noLights.setGlobalAmbient(DEFAULT_OUTLINE_COLOR);
noLights.setEnabled(true);
noTexture = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
noTexture.setEnabled(true);
alphaState = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
alphaState.setSrcFunction(AlphaState.SB_SRC_ALPHA);
alphaState.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
alphaState.setBlendEnabled(true);
alphaState.setEnabled(true);
}
public void doRender(Renderer renderer)
{
// if there's nothing to do
if (spatials.size() == 0) return;
// normal render
super.doRender(renderer);
// set up the render states
backupRenderStates();
Spatial.enforceState(wireframeState);
Spatial.enforceState(cullFront);
Spatial.enforceState(noLights);
Spatial.enforceState(noTexture);
Spatial.enforceState(alphaState);
// this will draw the wireframe
for (int i = 0; i < spatials.size(); ++i) {
Spatial spatial = (Spatial)spatials.get(i);
spatial.onDraw(renderer);
}
// restore the render states
restoreRenderStates();
}
private void backupRenderStates() {
for (int i = 0; i < RenderState.RS_MAX_STATE; ++i) {
backupStates[i] = Spatial.enforcedStateList[i];
}
}
private void restoreRenderStates() {
for (int i = 0; i < RenderState.RS_MAX_STATE; ++i) {
Spatial.enforcedStateList[i] = backupStates[i];
}
}
public void setOutlineWidth(float width) {
wireframeState.setLineWidth(width);
}
public float getOutlineWidth() {
return wireframeState.getLineWidth();
}
public void setOutlineColor(ColorRGBA outlineColor) {
noLights.setGlobalAmbient(outlineColor);
}
public ColorRGBA getOutlineColor() {
return noLights.getGlobalAmbient();
}
}