Slick Forums

Discuss the Slick 2D Library
It is currently Mon Apr 21, 2014 8:58 am

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Shaders in Slick?
PostPosted: Wed Apr 13, 2011 12:54 am 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
So some time ago TheMatrix154 posted on implementing shaders in slick. The concern of course is that in doing so you are isolating the people who's video cards don't support shaders.

I've been looking shaders quite a bit lately their uses, and alternatives and I'd like to make a few observations. Generally speaking shaders are either used to make something look prettier or add nice looking effect. Not integral to gameplay, or they are used to do something that would simply be far too taxing to do on the CPU.

In the first case I don't think it's a deal killer for people with lower end video cards to play games without all the available shinies. True it would be ideal for the developer to make an alternate non shader implementation but chances are if the user is running a six year old video card (Yeah OpenGL 2.0 is that old) they probably don't have a CPU powerful enough to take up the slack. The only group left out would be those that have a decent computer but lack a discrete video card. Except no; most integrated video cards have supported OpenGL 2/.0 for a while, heck I have been running Shaders on software implementations of OpenGL.

In the second case shaders are simply the only reasonable alternative. Rendering fractals or variable Perlin noise in real time is simply not practical on the CPU, but easily achievable when implemented in a shader.

I agree that isolating users with lower end systems is a bad thing, but I wonder if we are really isolating that many people.

Thoughts? Comments?

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 13, 2011 9:07 am 
Offline
Game Developer

Joined: Sun Nov 12, 2006 11:18 pm
Posts: 890
Location: Germany
I think as long as it is simple to detect if the client hardware supports shaders we should add it to Slick.
I would love to play around with Shader stuff (haven't touched it at all) as long as Slick provides a simple way for me :lol:
As it already does for OpenGL, OpenAL and all this other low level tech stuff :wink:

Is TheMatrix154's code a good base or should we discuss with Kev how his effect approach he mentions in the shader thread should look like?

Shaders in Slick FTW :wink:

_________________
Right Angle Games | Marte Engine
Back to the past | Star Cleaner | SpiderTrap


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 13, 2011 5:44 pm 
Offline
Oldbie
User avatar

Joined: Fri Jul 20, 2007 9:25 am
Posts: 410
Location: Croatia
I'm actually learning shaders now as it's a core part of OpenGL now days. In modern OpenGL you can't do anything without a shader.
I don't really care about compatibility profile as almost all graphic cards have shaders now.

I've done shaders tests for learning by using LWJGL turorial directly so far... haven't seen TheMatrix154's thread until now.

Let's join out efforts on shader implementation?I'll be doing lighting shader, as I'm not happy with lighting I've done so far.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 13, 2011 7:09 pm 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
TheMatrix's code is good but it is quite old. LWJGL has grown a bit since then.

Few changes that need to be made:
1. Switch from relying purely on the ARB implementation.

2. Provide a Shader manager similar to Slicks current Texture Manager so that people aren't needlessly loading and compiling reused shaders.

3. Provide error messages to user when the shader fails compiling or linking.

4. Provide methods to access Uniform variables.

5. Provide very careful interface so that the Shader class can be extended. This would be the hardest.

6. Provide a MultiTextureImage class so that people can create an image with more then one texture so that Shaders can actually make use of multitexturing.

I have 1-4 mostly figured out, I can't post my code right now, but hopefully tonight or tomorrow, then people can go nuts and pick it apart :P.

Current usage pattern is:
Code:
Shader s1 = Shader.makeShader("vertFile", "fragfile");
Shader s2 = Shader.makeShader("vertFile2", "fragfile2");
//....
s1.start();
//Render stuff with shader 1 applied
s2.start();
//Render stuff with shader 2 applied
Shader.ForceFixedPipeline(); // Return to the default fixed pipeline shader

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 14, 2011 8:22 pm 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
Tommy wrote:
...or should we discuss with Kev how his effect approach he mentions in the shader thread should look like?

Woops my bad, in my zeal to see some interest in this I missed that part of the post. I think it would definitely be worth it to get Kev's take on it.

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 15, 2011 1:17 am 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
Anyway here is the what I have been useing to get my shaders running the meat of the thing is still mostly the same as TheMatrix's implementation with a few convenience features thrown in. Functionality has more or less been added as I need it, so there is a bunch of half implemented stuff.
Code:
public class Shader {
 
  /**
   * A simple class used to prevent duplicate shaders from
   * being loaded and compiled onto the video card.</br>
   * @author Chronocide
   */
  private static final class ShaderResourceManager{
    private Map<String, Integer> map = new HashMap<String, Integer>();
   
    public ShaderResourceManager(){}
   
    public int getFragementShaderID(String fragmentFileName){
      Integer id = map.get(fragmentFileName);
      if(id==null){
        id = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
        map.put(fragmentFileName, id);
      }
      return id;
    }
   
    public int getVertexShaderID(String vertexFileName){
      Integer id = map.get(vertexFileName);
      if(id==null){
        id = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        map.put(vertexFileName, id);
      }
      return id;
    }
  }
  private static ShaderResourceManager staticSRM = null;

 
  public static final int BRIEF = 128;
  public static final int MODERATE = 512;
  public static final int VERBOSE = 1024;
  private static int logging = MODERATE;
 
 
  private int programID = -1; //ID of the compiled Shader program
 
 
  private Shader(ShaderResourceManager srm,
                 String vertexFileName,
                 String fragmentFileName) throws SlickException{
    StringBuilder errorMessage = new StringBuilder();
   
    int vsid = srm.getVertexShaderID(vertexFileName);
    int fsid = srm.getFragementShaderID(fragmentFileName);
   
    GL20.glShaderSource(vsid, getProgramCode(vertexFileName));
      GL20.glCompileShader(vsid);
      if(!compiledSuccessfully(vsid)){
        errorMessage.append("Could not compile Vertex Shader ");
        errorMessage.append(vertexFileName);
        errorMessage.append(" failed to compile.\n");
        errorMessage.append(getShaderInfoLog(vsid));
        errorMessage.append("\n\n");
      }
   
    GL20.glShaderSource(fsid, getProgramCode(fragmentFileName));
      GL20.glCompileShader(fsid);
      if(!compiledSuccessfully(fsid)){
        errorMessage.append("Could not compile Fragment Shader ");
        errorMessage.append(fragmentFileName);
        errorMessage.append(" failed to compile.\n");
        errorMessage.append(getShaderInfoLog(fsid));
        errorMessage.append("\n\n");
      }

    programID = GL20.glCreateProgram();
      GL20.glAttachShader(programID, vsid);
      GL20.glAttachShader(programID, fsid);
   
      GL20.glLinkProgram(programID);
      if(!linkedSuccessfully()){
        errorMessage.append("Linking Error\n");
        errorMessage.append(getProgramInfoLog(programID));
        errorMessage.append("\n\n");
      }
     
      if(errorMessage.length()!=0){
        errorMessage.append("Stack Trace:");
        throw new SlickException(errorMessage.toString());
      }
  }
 
 
 
  /**
   * Factory method to create a new Shader.
   * @param vertexFileName
   * @param fragmentFileName
   * @return
   * @throws SlickException
   */
  public static Shader makeShader(String vertexFileName,
                                  String fragmentFileName)throws SlickException{
    if(staticSRM == null){staticSRM = new ShaderResourceManager();}
    return new Shader(staticSRM, vertexFileName, fragmentFileName);
  }

 
 
  /**
   * Activates the shader.</br>
   */
  public void startShader(){
    GL20.glUseProgram(programID);
  }
 
 
 
  /**
   * Reverts GL context back to the fixed pixel pipeline.<br>
   */
  public static void forceFixedShader(){
    GL20.glUseProgram(0);
  }
 
 
 
  /**
   * Sets the value of the uniform integer Variable <tt>name</tt>.</br>
   * @param name the variable to set.
   * @param value the value to be set.
   */
  public void setUniformIVariable(String name, int value){
    CharSequence param = new StringBuffer(name);
    int location = GL20.glGetUniformLocation(programID, param);
   
    GL20.glUseProgram(programID);
    GL20.glUniform1i(location, value);
    GL20.glUseProgram(0);
  }

 
 
  /**
   * Sets the value of the uniform integer Variable <tt>name</tt>.</br>
   * @param name the variable to set.
   * @param value the value to be set.
   */
  public void setUniformFVariable(String name, float value){
    CharSequence param = new StringBuffer(name);
    int location = GL20.glGetUniformLocation(programID, param);
   
    GL20.glUseProgram(programID);
    GL20.glUniform1f(location, value);
    GL20.glUseProgram(0);
  }
 
 
 
  /**
   * Returns true if the shader compiled successfully.</br>
   * @param shaderID
   * @return true if the shader compiled successfully.</br>
   */
  private boolean compiledSuccessfully(int shaderID){
    return GL20.glGetShader(shaderID, GL20.GL_COMPILE_STATUS)==GL11.GL_TRUE;
  }
 
 
 
  /**
   * Returns true if the shader program linked successfully.</br>
   * @param shaderID
   * @return true if the shader program linked successfully.</br>
   */
  private boolean linkedSuccessfully(){
    return GL20.glGetShader(programID, GL20.GL_LINK_STATUS)==GL11.GL_TRUE;
  }
 
 
 
  private String getShaderInfoLog(int shaderID){
    return GL20.glGetShaderInfoLog(shaderID, logging).trim();
  }
 
 
 
  private String getProgramInfoLog(int programID){
    return GL20.glGetProgramInfoLog(programID, logging).trim();
  }
 
 
 
  /**
   * Gets the program code from the file "filename" and puts in into a
   * byte buffer.
   * @param filename the full name of the file.
   * @return a ByteBuffer containing the program code.
   * @throws SlickException
   */
  private ByteBuffer getProgramCode(String filename)throws SlickException{
    InputStream fileInputStream = null;
    byte[] shaderCode = null;
       
    fileInputStream = ResourceLoader.getResourceAsStream(filename);
    DataInputStream dataStream = new DataInputStream(fileInputStream);
    try {
    dataStream.readFully(shaderCode = new byte[fileInputStream.available()]);
    fileInputStream.close();
    dataStream.close();
    } catch (IOException e) {
    throw new SlickException(e.getMessage());
    }

 
    ByteBuffer shaderPro = BufferUtils.createByteBuffer(shaderCode.length);

    shaderPro.put(shaderCode);
    shaderPro.flip();

    return shaderPro;
  }
 
 
}

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 17, 2011 6:23 am 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
Hey Kova, got some good news for you.
Threw together a MultiTexture class, and succeeded in loading a base colour map and a normal map then implemented a simple (very simple) per pixel lighting shader with promising results.
See: http://www.youtube.com/watch?v=q020X3KcFl8&feature=related for what I am talking about.

No shadows being cast from one object to another, that is a little tricky, but initial experiments show that once a single good shader is created. Lighting in Slick even really complex stuff can be made quite simple. Something to the extent of:
Code:
Renderable r = new MultiTexture("colourImg.png", "normalImg.png");
Shader s = new Shader("lighting.vrt", "lighting.frg");
//...
s.start
s.setUniformIvariable("colourImg\0", 0);
s.setUniformIvariable("normalImg\0", 1);
s.setUnifrom2fVariable("lightLocation\0", lx, ly);
r.draw(x,y);

Some of that can probably even be automated so that the user doesn't need to be aware of all the crazy texture unit stuff going on. Also handling the null termination can be automated

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 17, 2011 8:27 am 
Offline
Oldbie
User avatar

Joined: Fri Jul 20, 2007 9:25 am
Posts: 410
Location: Croatia
Excellent!
The approach I'm taking will take very long I assume to produce the final result so your input (or anybody's for that matter) is welcome.
I'm reading a book OpenGL Super Bible 5th edition which is OpenGL 3.x (core profile where shaders are basic rendering tool, a must) and it has 1000 pages :) ... as I progress I'll write usefull addons to slick. Not just shaders but performance and other utilities also.

You're way ahead of me now in terms of direct LWJGL shaders and shader knowlage in general.... can you post a few links on LWJGL shader tutorial for the code you use? And a link to your MultiTexture class.
I'm for setting up a resource section so this would start it.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 17, 2011 9:09 pm 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
Well I (think) I have a pretty good handle on the boiler plate set up for shader stuff. I know I am still not very good at writing the shaders themselves though, so I certainly look forward to someone learning about that and sharing their hard earned wisdom.

I think I might put this up on google code, as an easy way to keep things updated.
**EDIT** should be available at https://code.google.com/p/slickshader/ assuming I set things up correctly.

Another thing I thought of is that shaders could work very well as the foundation of an effects class. Shaders do have a little more cognitive friction about them then the typical Slick operations, which is unfortunate but they really are the only way of achieving some things. So we start by supporting them, because there are some very smart Slick users who will be able to take advantage of them. Then as they get used, certain classes of uses for them are likely to emerge. Once these generic uses are determined they can be encapsulated into an Effects objects. This even gives an opportunity to develop a non shader dependant implementation, which can be bundled into the Effects object and have the Effects object do the work of determining which implementation to use.

This has a number of advantages, you don't need to try to build a whole effects library off the bat, you don't need to waste time developing effects that you think will be used, and when important Effects are identified they can be more easily implemented in a shader free way since their scope and usage patterns will be better understood having already been used.

The drawback is that we rely on the community to share their implementations, but I don't think that this is too big an issue as the Slick community seems fairly generous and helpful.

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 19, 2011 7:28 pm 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
It occurred to me that editing my previous post wouldn't mark the thread as having new info. So there is a project up now to add a shader extension for Slick, anyone who wants to check it out can get it at https://code.google.com/p/slickshader/ complete with a simple example.

Anyone interested in contributing can PM me.

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 8:37 pm 
Offline
Oldbie
User avatar

Joined: Thu Jan 13, 2011 4:42 pm
Posts: 349
I'm getting an error message when I try to run the example:


Code:
Thu Sep 01 16:37:08 EDT 2011 ERROR:Could not compile shader.
Vertex Shader data/multiTex.vrt failed to compile.
ERROR: 0:1: 'gl_' : reserved built-in name
ERROR: 0:3: 'gl_' : reserved built-in name
ERROR: 0:4: 'gl_' : reserved built-in name

Fragment Shader data/multiTex.frg failed to compile.
ERROR: 0:1: 'gl_' : reserved built-in name

Linking Error

...


anybody know what might be wrong? do i need a special compiler?


Top
 Profile  
 
 Post subject: Re: Shaders in Slick?
PostPosted: Tue Nov 29, 2011 3:54 am 
Offline
Regular

Joined: Sun Dec 07, 2008 5:22 am
Posts: 238
Location: Vancouver, BC, Canada
What's wrong, is that I suck at writing shaders. The multi texture examples aren't properly compliant and only work on a few video cards.
I commented out those portions of the example that deal with multi-textures. So it should work for you now,

Sorry for the slow response.

_________________
If at first quads don't succeed tri tri again.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: Dan and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group