Help with learning shaders

I am using this tutorial:



http://www.lighthouse3d.com/opengl/glsl/index.php?lights



to learn the basics of shaders. It is asking me to call something like this and put it into the shader as such:


   struct gl_LightSourceParameters {
      vec4 ambient;
      vec4 diffuse;
      vec4 specular;
      vec4 position;
      vec4 halfVector;
      vec3 spotDirection;
      float spotExponent;
      float spotCutoff; // (range: [0.0,90.0], 180.0)
      float spotCosCutoff; // (range: [1.0,0.0],-1.0)
      float constantAttenuation;
      float linearAttenuation;
      float quadraticAttenuation;   
   };
   
   uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];



however, the only part I know how to do is the last line where you set a uniform. How do you set this "struct" within JME holding all these values?

Also, on the next page,

http://www.lighthouse3d.com/opengl/glsl/index.php?ogldir1

it brings up

gl_FrontMaterial.diffuse

What exactly is this and how do I work with it within JME? Is this just the base texture map applied to an object?


Thanks so much for the help!

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