Hi,
With jME you can write to a texture I had the same problem but core-dump showed me a few places to look and set me on the right path, I hope you don't mind there's some code here
declaring a renderPass to jME
import com.jme.image.Texture;
import com.jme.image.Texture2D;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.TextureRenderer;
import com.jme.renderer.pass.Pass;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
public class colorchange extends Pass
{
private static final long serialVersionUID = 1L;
private Camera cam;
private GLSLShaderObjectsState Shader;
private Quad fullScreenQuad;
DisplaySystem display;
private TextureRenderer tRenderer;
/** The final resulting texture to be splatted across the screen */
private Texture2D resultTexture;
/** The copy of the screen */
private Texture2D screenTexture;
public colorchange( Camera cam ) {
this.cam = cam;
display = DisplaySystem.getDisplaySystem();
tRenderer = display.createTextureRenderer(display.getWidth(), display.getHeight(), TextureRenderer.Target.Texture2D);
tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
tRenderer.setCamera(cam);
screenTexture = new Texture2D();
screenTexture.setWrap(Texture.WrapMode.Clamp);
tRenderer.setupTexture(screenTexture);
resultTexture = new Texture2D();
resultTexture.setWrap(Texture.WrapMode.Clamp);
resultTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
tRenderer.setupTexture(resultTexture);
fullScreenQuad = new Quad("FullScreenQuad", display.getWidth() / 4,
display.getHeight() / 4);
fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2,
display.getHeight() / 2, 0);
fullScreenQuad.getLocalScale().set(1, 1, 1);
fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);
fullScreenQuad.setCullHint(Spatial.CullHint.Never);
fullScreenQuad.setTextureCombineMode(Spatial.TextureCombineMode.Replace);
fullScreenQuad.setLightCombineMode(Spatial.LightCombineMode.Off);
TextureState ts = display.getRenderer().createTextureState();
ts.setEnabled(true);
fullScreenQuad.setRenderState(ts);
BlendState as = display.getRenderer().createBlendState();
// no blending, result texture has to overwrite screen - not blend!
as.setTestEnabled(true);
as.setTestFunction(BlendState.TestFunction.GreaterThan);
as.setEnabled(true);
fullScreenQuad.setRenderState(as);
fullScreenQuad.updateRenderState();
fullScreenQuad.updateGeometricState(0.0f, true);
Shader = display.getRenderer().createGLSLShaderObjectsState();
Shader.load(
"varying vec2 vTexCoord;"+
"void main(void)"+
"{"+
" vec2 Pos = sign(gl_Vertex.xy);"+
" gl_Position = vec4(Pos.xy, 0, 1);"+
" vTexCoord.x = 0.5 * (1.0 + Pos.x);"+
" vTexCoord.y = 0.5 * (1.0 + Pos.y);"+
"}"
,
"uniform sampler2D scene;"+
"varying vec2 vTexCoord;"+
"void main()"+
"{"+
" vec4 sum = texture2D(scene, vTexCoord);"+
"if((sum.r > 0.7) && (sum.g > 0.7))"+
"{"+
" sum.r = 0.05;"+
" sum.g = 0.1;"+
" sum.b = 0.3;"+
" sum.a = 1.0;"+
"}"+
"else"+
"{"+
" sum.b += 0.2;"+
"}"+
" gl_FragColor = sum;"+
"}"
);
Shader.setEnabled(true);
}
@Override
protected void doRender(Renderer r)
{
BlendState as = (BlendState) fullScreenQuad.states[RenderState.StateType.Blend.ordinal()];
TextureState ts = (TextureState) fullScreenQuad.states[RenderState.StateType.Texture.ordinal()];
as.setEnabled(false);
// rendering the screen
tRenderer.copyToTexture(screenTexture, DisplaySystem
.getDisplaySystem().getWidth(), DisplaySystem
.getDisplaySystem().getHeight());
fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = Shader;
r.draw(fullScreenQuad);
}
}
now the shader code is inlined to my pass as strings, so you do not need any more files, just to review it though
shaders come in two forms, the vertex shader and the fragment shader, I'm not an expert but from what I had to learn to write this simple shader all you do is use the vertex to pass data to the fragment shader which does all the work, once you learn more than I did (only took a few hours including me whining about my lack of knowledge), you'll be in a better position to do cool things, also because jME is open source you'll notice lots of things from reading their shaders
vertex shader
varying vec2 vTexCoord; // variable can be unified or varying. think of them like constants and variables
void main(void) // this is the main loop just like in your Java app or a C program
{
vec2 Pos = sign(gl_Vertex.xy);
gl_Position = vec4(Pos.xy, 0, 1);
vTexCoord.x = 0.5 * (1.0 + Pos.x);
vTexCoord.y = 0.5 * (1.0 + Pos.y);
}
now that code works to pass the verts to my fragment shader, all I understand is it's a bit like a for loop with i & j or x & y as we will call them, if that last bit makes no sense read up on loop structures
this next part I understand better than the vertex part it deals with each fragment and modifies their r, g, b and a values
uniform sampler2D scene;
varying vec2 vTexCoord;
void main()
{
vec4 sum = texture2D(scene, vTexCoord);
if((sum.r > 0.7) && (sum.g > 0.7))
{
sum.r = 0.05;
sum.g = 0.1;
sum.b = 0.3;
sum.a = 1.0;
}
else
{
sum.b += 0.2;
}
gl_FragColor = sum;
}
I think it gets the value of a pixel in rgba format from scene as a texture, you could pass any texture to a shader but mine was for underwater blue adding, you'll also notice it checks the values of red and green and if they have a certain value it diminishes them, this is to stop white being made from overly red or green colours, I could set red and green to zero but this seemed unnessecarry because I wanted it to be tinted blue but not just reduced to a shade of blue, I could have used a specific rgb value or value range and replaced that colour with blue to introduce a sort of keystoning colour replacement effect but I decided not to also worth a note is that opengl uses r g b and a expressed as 0.0 - 1.0 which you can get by knowing rgb values of a color or by breaking a colour down for example
0x000000 or #000000 is black so it has alpha of 255 automatically in any web browser 255 = 1.0
this is because 1/255 * 255 = 1, we can do this for any color, an easier way to think of it is 1/maxValue * actualvalue = what we want
now to get the r, g and b we just split the number at every two numerics so r=00 or 0, g=00 or 0 and b=00 or 0
now when dealing with these colours if r, g and b are all even you will be dealing with a greyscale colour or k in the cmyk model of colours, if r, g or b is more prominent than the other components then the colour will be a shade of red green or blue
to work with a more complex number just remember to add commas so 0099ff =
r (00) g (99) b (ff)
r (0), g ( (16*9)+9 ), b( (16*15)+15 )
r (0), g (144+9), b(240+15)
r (0), g(153), b(255)
r (1/255 * 0), g(1/255 * 153), b(1/255 * 255)
r (0.0), g(0.6), b(1.0)
hope this helps lol as you can see I'm better with colours than opengl code lol