LWJGL Forum

Programming => OpenGL => Topic started by: ghillieLEAD on April 10, 2012, 00:03:23

Title: Rendering using shaders
Post by: ghillieLEAD on April 10, 2012, 00:03:23
I've been trying to use shaders, but can't get them working.  I create and compile the shaders (no error there), attach them to a program, link the program and validate it.  No errors.  I then use the program and draw a triangle, but the triangle is always drawn using fixed function mode rather than using my basic shader program.  It doesn't matter if I use immediate mode, vertex arrays, or VBOs, the shader is never used.  If you could help me determine the issue I would appreciate it a lot.

The code:

Main class


package net.midnightindie.dungeon;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Frame;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import net.midnightindie.dungeon.render.ProgramManager;
import net.midnightindie.dungeon.util.WindowListener;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Controllers;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.glu.GLU;

public class Dungeon extends Applet implements Runnable
{
private static final long serialVersionUID = 1L;
private static final boolean isApplet = false;

protected Frame frame;
protected Canvas canvas;
protected int displayWidth;
protected int displayHeight;

protected boolean areControllersAvailable;

protected Thread gameThread;
protected boolean isRunning;
protected boolean isPaused;

protected long lastSecond;
protected long lastFrame;
protected int frames;

protected FloatBuffer vertexArray;

protected FloatBuffer vboVertexArray;
protected int vboVertexArrayHandle;

public Dungeon()
{

}

public void initialize()
{
displayWidth = 900;
displayHeight = 600;
CreateDisplay();

areControllersAvailable = false;
CreateInputDevices();

initializeGL();

ProgramManager.instance().createPrograms();
ProgramManager.instance().useProgram("basic");

initializeVertexArray();
initializeVBO();

lastSecond = lastFrame = System.currentTimeMillis();
frames = 0;

isRunning = true;
isPaused = false;
}

protected void initializeGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glClearDepth(1.0f);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

GLU.gluPerspective(45, displayWidth / displayHeight, 0.1f, 100);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

public void initializeVertexArray()
{
vertexArray = BufferUtils.createFloatBuffer(9);

vertexArray.put(-1).put(-1).put(0);
vertexArray.put(0).put(1).put(0);
vertexArray.put(1).put(-1).put(0);

vertexArray.flip();
}

public void initializeVBO()
{
vboVertexArray = BufferUtils.createFloatBuffer(9);

vboVertexArray.put(-1).put(-1).put(0);
vboVertexArray.put(0).put(1).put(0);
vboVertexArray.put(1).put(-1).put(0);

vboVertexArray.flip();

IntBuffer buffer = BufferUtils.createIntBuffer(1);
glGenBuffers(buffer);
vboVertexArrayHandle = buffer.get(0);

glBindBuffer(GL_ARRAY_BUFFER, vboVertexArrayHandle);
glBufferData(GL_ARRAY_BUFFER, vboVertexArray, GL_STATIC_DRAW);
}

public void cleanupVBO()
{
IntBuffer buffer = BufferUtils.createIntBuffer(1);
buffer.put(vboVertexArrayHandle);
buffer.flip();
glDeleteBuffers(buffer);
}

@SuppressWarnings("serial")
protected void CreateDisplay()
{
if (isApplet)
{
canvas = new Canvas()
{
public final void addNotify()
{
super.addNotify();

try
{
Display.setParent(this);
Display.create();
} catch (Exception ex)
{
}
}

public final void removeNotify()
{
Display.destroy();

super.removeNotify();
}
};
canvas.setSize(getWidth(), getHeight());
add(canvas);
canvas.setFocusable(true);
canvas.requestFocus();
canvas.setIgnoreRepaint(true);
setVisible(true);
}
else
{
frame = new Frame();
frame.setTitle("glint");
frame.setSize(displayWidth, displayHeight);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());
frame.addWindowListener(new WindowListener(this, gameThread));

canvas = new Canvas();
frame.add(canvas, "Center");

frame.setVisible(true);

try
{
Display.setParent(canvas);
Display.create();

} catch (LWJGLException ex)
{
HandleError(ex.getMessage());
}
}

}

public void CreateInputDevices()
{
try
{
Keyboard.create();
Mouse.create();

Mouse.setGrabbed(true);
} catch (LWJGLException ex)
{
HandleError("Unable to create input devices");
}

try
{
Controllers.create();
areControllersAvailable = true;
} catch (LWJGLException ex)
{
areControllersAvailable = false;
}
}

public void Start()
{
gameThread = new Thread(this, "glint");
gameThread.start();
}

public void Pause()
{
isPaused = true;
}

public void Resume()
{
isPaused = false;
}

public void Stop()
{
isRunning = false;
}

public void Destroy()
{
cleanupVBO();

Keyboard.destroy();
Mouse.setGrabbed(false);
Mouse.destroy();
Controllers.destroy();
Display.destroy();

System.out.println("TERMINATED");
}

public void PollInputDevices()
{
if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) isRunning = false;
if (Keyboard.isKeyDown(Keyboard.KEY_F11)) Mouse.setGrabbed(true);
if (Keyboard.isKeyDown(Keyboard.KEY_F12)) Mouse.setGrabbed(false);
}

public void Update()
{
long currentTime = System.currentTimeMillis();
long elapsedTime = currentTime - lastFrame;
if (currentTime - lastSecond >= 1000)
{
System.out.println("FPS:  " + frames);
lastSecond = currentTime;
frames = 0;
}

lastFrame = currentTime;
frames++;
}

public void immediateModeTriangle()
{
glBegin(GL_TRIANGLES);
glColor3f(0, 0, 0);
glVertex3f(1, 0, -4);
glColor3f(1, 0, 0);
glVertex3f(0, 1, -4);
glColor3f(0, 0, 0);
glVertex3f(-1, 0, -4);
glEnd();
}

public void vertexArrayTriangle()
{
glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(3, 0, vertexArray);
glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableClientState(GL_VERTEX_ARRAY);
}

public void vboTriangle()
{
glEnableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vboVertexArrayHandle);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableClientState(GL_VERTEX_ARRAY);
}

public void Render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glColor3f(1, 0, 0);

immediateModeTriangle();

// glTranslatef(0, 0, -4);
// vertexArrayTriangle();

// glTranslatef(0, 0, -4);
// vboTriangle();
}

public void run()
{
initialize();

while (isRunning)
{
if (isPaused)
{
try
{
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException ex)
{

}

continue;
}

PollInputDevices();
Update();
Render();

Display.update();
}

Destroy();
System.exit(0);
}

public void HandleError(String errorMessage)
{
System.out.println("[ERROR]  " + errorMessage);
Stop();
}

public void start()
{
Start();
}

public void stop()
{
Stop();
}

public static void main(String[] args)
{
System.out.println("Working Directory:  " + System.getProperty("user.dir"));

Dungeon glint = new Dungeon();
glint.Start();
}
}


Program Manager


package net.midnightindie.dungeon.render;

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.lwjgl.BufferUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;

public class ProgramManager
{
private static ProgramManager instance = null;

public static ProgramManager instance()
{
if (instance == null)
{
instance = new ProgramManager();
}

return instance;
}

private Hashtable<String, Shader> vertexShaders;
private Hashtable<String, Shader> fragmentShaders;
private Hashtable<String, Program> programs;

private ProgramManager()
{
vertexShaders = new Hashtable<String, Shader>();
fragmentShaders = new Hashtable<String, Shader>();
programs = new Hashtable<String, Program>();
}

public void createPrograms()
{
programs.clear();

int numPrograms = 0;

try
{
File filePrograms = new File("res/programs.xml");
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePrograms);

NodeList nodeListPrograms = doc.getElementsByTagName("program");

for (int i = 0; i < nodeListPrograms.getLength(); i++)
{
Node nodeProgram = nodeListPrograms.item(i);

if (nodeProgram.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) nodeProgram;

NodeList nodeListName = element.getElementsByTagName("name").item(0).getChildNodes();
String programName = ((Node) nodeListName.item(0)).getNodeValue();

ArrayList<Shader> vshaders = new ArrayList<Shader>();
NodeList nodeListVertexShaders = element.getElementsByTagName("vertex");
for (int j = 0; j < nodeListVertexShaders.getLength(); j++)
{
NodeList nodeListVertexShadersValue = nodeListVertexShaders.item(j).getChildNodes();
String shaderName = ((Node) nodeListVertexShadersValue.item(0)).getNodeValue();

if (!vertexShaders.containsKey(shaderName))
{
loadVertexShader(shaderName);
}

vshaders.add(vertexShaders.get(shaderName));
}

ArrayList<Shader> fshaders = new ArrayList<Shader>();
NodeList nodeListFragmentShaders = element.getElementsByTagName("fragment");
for (int j = 0; j < nodeListFragmentShaders.getLength(); j++)
{
NodeList nodeListFragmentShadersValue = nodeListFragmentShaders.item(j).getChildNodes();
String shaderName = ((Node) nodeListFragmentShadersValue.item(0)).getNodeValue();

if (!fragmentShaders.containsKey(shaderName))
{
loadFragmentShader(shaderName);
}

fshaders.add(fragmentShaders.get(shaderName));
}

programs.put(programName, new Program(vshaders, fshaders));

numPrograms++;
}
}

} catch (Exception ex)
{
System.out.println(ex.getMessage());
ex.printStackTrace();
System.exit(0);
}

System.out.println("Number of programs created:  " + numPrograms);

vertexShaders.clear();
fragmentShaders.clear();
}

private void loadVertexShader(String name)
{
try
{
File file = new File("res/shaders/" + name + ".vert");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();

ByteBuffer shaderSource = BufferUtils.createByteBuffer((int) fc.size());
fc.read(shaderSource);

vertexShaders.put(name, new Shader(GL_VERTEX_SHADER, shaderSource));
System.out.println("Loaded vertex shader '" + name + "'");
} catch (Exception ex)
{
System.out.println("Error creating vertex shader '" + name + "'");
}
}

private void loadFragmentShader(String name)
{
try
{
File file = new File("res/shaders/" + name + ".frag");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();

ByteBuffer shaderSource = BufferUtils.createByteBuffer((int) fc.size());
fc.read(shaderSource);

fragmentShaders.put(name, new Shader(GL_FRAGMENT_SHADER, shaderSource));
System.out.println("Loaded fragment shader '" + name + "'");
} catch (Exception ex)
{
System.out.println("Error creating fragment shader '" + name + "'");
}
}

public void useProgram(String name)
{
programs.get(name).use();
System.out.println("Now using program '" + name + "'");
}

class Shader
{
public final int handle;

public Shader(int type, ByteBuffer source)
{
handle = glCreateShader(type);
glShaderSource(handle, source);
glCompileShader(handle);

if (glGetShader(handle, GL_COMPILE_STATUS) == GL_FALSE)
{
System.out.println("shader compilation failed.");
}
}
}

class Program
{
public final int handle;

public Program(ArrayList<Shader> vshaders, ArrayList<Shader> fshaders)
{
handle = glCreateProgram();

for (int i = 0; i < vshaders.size(); i++)
{
glAttachShader(handle, vshaders.get(i).handle);
}

for (int i = 0; i < fshaders.size(); i++)
{
glAttachShader(handle, fshaders.get(i).handle);
}

glLinkProgram(handle);
glValidateProgram(handle);
}

public void use()
{
glUseProgram(handle);
}
}
}



Vertex Shader


void main()
{
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}


also tried


main()
{
gl_Position = ftransform();
}


Fragment Shader


void main()
{
gl_FragColor = vec4(0, 1, 0, 1);
}
Title: Re: Rendering using shaders
Post by: CodeBunny on April 10, 2012, 12:46:54
You need to bind the shader when you render for it to work, you know.
Title: Re: Rendering using shaders
Post by: ghillieLEAD on April 10, 2012, 14:21:35
As in glUseProgram(), correct?  Or are you referring to something else?  I do call my ProgramManager's useProgram() (which does a glUseProgram()) in my initialize method.  Just now I also tried putting the useProgram() call in my actual render function as well, just to see if it made a difference.  It didn't.


public void initialize()
{
...
ProgramManager.instance().createPrograms();
ProgramManager.instance().useProgram("basic");
...
}


also tried


public void Render()
{
...
glUseProgram(ProgramManager.instance().getProgramHandle("basic"));
immediateModeTriangle();
...
}
Title: Re: Rendering using shaders
Post by: ghillieLEAD on April 10, 2012, 23:48:40
I figured it out!  When I was loading the shaders (using a ByteBuffer) I forgot to flip the buffer after loading the file.  In case it helps someone in the future, the correct code is below.  The only change is the line shaderSource.flip();

New ProgramManager:


package net.midnightindie.dungeon.render;

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.lwjgl.BufferUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;

public class ProgramManager
{
private static ProgramManager instance = null;

public static ProgramManager instance()
{
if (instance == null)
{
instance = new ProgramManager();
}

return instance;
}

private Hashtable<String, Shader> vertexShaders;
private Hashtable<String, Shader> fragmentShaders;
private Hashtable<String, Program> programs;

private ProgramManager()
{
vertexShaders = new Hashtable<String, Shader>();
fragmentShaders = new Hashtable<String, Shader>();
programs = new Hashtable<String, Program>();
}

public void createPrograms()
{
programs.clear();

int numPrograms = 0;

try
{
File filePrograms = new File("res/programs.xml");
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePrograms);

NodeList nodeListPrograms = doc.getElementsByTagName("program");

for (int i = 0; i < nodeListPrograms.getLength(); i++)
{
Node nodeProgram = nodeListPrograms.item(i);

if (nodeProgram.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) nodeProgram;

NodeList nodeListName = element.getElementsByTagName("name").item(0).getChildNodes();
String programName = ((Node) nodeListName.item(0)).getNodeValue();

ArrayList<Shader> vshaders = new ArrayList<Shader>();
NodeList nodeListVertexShaders = element.getElementsByTagName("vertex");
for (int j = 0; j < nodeListVertexShaders.getLength(); j++)
{
NodeList nodeListVertexShadersValue = nodeListVertexShaders.item(j).getChildNodes();
String shaderName = ((Node) nodeListVertexShadersValue.item(0)).getNodeValue();

if (!vertexShaders.containsKey(shaderName))
{
loadVertexShader(shaderName);
}

vshaders.add(vertexShaders.get(shaderName));
}

ArrayList<Shader> fshaders = new ArrayList<Shader>();
NodeList nodeListFragmentShaders = element.getElementsByTagName("fragment");
for (int j = 0; j < nodeListFragmentShaders.getLength(); j++)
{
NodeList nodeListFragmentShadersValue = nodeListFragmentShaders.item(j).getChildNodes();
String shaderName = ((Node) nodeListFragmentShadersValue.item(0)).getNodeValue();

if (!fragmentShaders.containsKey(shaderName))
{
loadFragmentShader(shaderName);
}

fshaders.add(fragmentShaders.get(shaderName));
}

programs.put(programName, new Program(vshaders, fshaders));

numPrograms++;
}
}

} catch (Exception ex)
{
System.out.println(ex.getMessage());
ex.printStackTrace();
System.exit(0);
}

System.out.println("Number of programs created:  " + numPrograms);

vertexShaders.clear();
fragmentShaders.clear();
}

private void loadVertexShader(String name)
{
try
{
File file = new File("res/shaders/" + name + ".vert");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();

ByteBuffer shaderSource = BufferUtils.createByteBuffer((int) fc.size());
fc.read(shaderSource);
shaderSource.flip();

vertexShaders.put(name, new Shader(GL_VERTEX_SHADER, shaderSource));
System.out.println("Loaded vertex shader '" + name + "'");
} catch (Exception ex)
{
System.out.println("Error creating vertex shader '" + name + "'");
}
}

private void loadFragmentShader(String name)
{
try
{
File file = new File("res/shaders/" + name + ".frag");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();

ByteBuffer shaderSource = BufferUtils.createByteBuffer((int) fc.size());
fc.read(shaderSource);
shaderSource.flip();

fragmentShaders.put(name, new Shader(GL_FRAGMENT_SHADER, shaderSource));
System.out.println("Loaded fragment shader '" + name + "'");
} catch (Exception ex)
{
System.out.println("Error creating fragment shader '" + name + "'");
}
}

public void useProgram(String name)
{
programs.get(name).use();
System.out.println("Now using program '" + name + "'");
}

class Shader
{
public final int handle;

public Shader(int type, ByteBuffer source)
{
handle = glCreateShader(type);
glShaderSource(handle, source);
glCompileShader(handle);

if (glGetShader(handle, GL_COMPILE_STATUS) == GL_FALSE)
{
System.out.println("shader compilation failed.");
}
}
}

class Program
{
public final int handle;

public Program(ArrayList<Shader> vshaders, ArrayList<Shader> fshaders)
{
handle = glCreateProgram();

for (int i = 0; i < vshaders.size(); i++)
{
glAttachShader(handle, vshaders.get(i).handle);
}

for (int i = 0; i < fshaders.size(); i++)
{
glAttachShader(handle, fshaders.get(i).handle);
}

glLinkProgram(handle);
glValidateProgram(handle);
}

public void use()
{
glUseProgram(handle);
}
}
}