Okay, so I'm trying to get the tutorial here to work: http://lwjgl.org/wiki/index.php?title=GLSL_Shaders_with_LWJGL
My question is why aren't my shaders doing anything in this example? I'm very new to GLSL.
here is the code for the main class
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.util.glu.GLU;
/*
* Sets up the Display, the GL context, and runs the main game
loop.
*
* #author Stephen Jones
*/
public class GLSLTest{
Box box;
private boolean done=false; //game runs until done is set to true
public GLSLTest(){
init();
while(!done){
if(Display.isCloseRequested())
done=true;
render();
Display.update();
}
Display.destroy();
}
private void render(){
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT |
GL11.GL_DEPTH_BUFFER_BIT);
GL11.glLoadIdentity();
box.draw();
}
private void init(){
int w=1024;
int h=768;
try{
Display.setDisplayMode(new DisplayMode(w, h));
Display.setVSyncEnabled(true);
Display.setTitle("Shader Setup");
Display.create();
}catch(Exception e){
System.out.println("Error setting up display");
System.exit(0);
}
GL11.glViewport(0,0,w,h);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(45.0f, ((float)w/(float)h),0.1f,100.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL11.glClearDepth(1.0f);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT,
GL11.GL_NICEST);
box = new Box();
}
public static void main(String[] args){
new GLSLTest();
}
}
Here is the code for the Box class:
import org.lwjgl.opengl.GL11;
import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.Util;
/**
* The vertex and fragment shaders are setup when the box object is
* constructed. They are applied to the GL state prior to the box
* being drawn, and released from that state after drawing.
* #author Stephen Jones
*/
public class Box {
/*
* if the shaders are setup ok we can use shaders, otherwise we just
* use default settings
*/
private boolean useShader=true;
/*
* program shader, to which is attached a vertex and fragment shaders.
* They are set to 0 as a check because GL will assign unique int
* values to each
*/
private int shader=0;
private int vertShader=0;
private int fragShader=0;
public Box(){
/*
* create the shader program. If OK, create vertex
* and fragment shaders
*/
shader=ARBShaderObjects.glCreateProgramObjectARB();
if(shader!=0){
vertShader=createVertShader("screen.vert");
fragShader=createFragShader("screen.frag");
}
else useShader=false;
/*
* if the vertex and fragment shaders setup sucessfully,
* attach them to the shader program, link the sahder program
* (into the GL context I suppose), and validate
*/
if(vertShader !=0 && fragShader !=0){
ARBShaderObjects.glAttachObjectARB(shader, vertShader);
ARBShaderObjects.glAttachObjectARB(shader, fragShader);
ARBShaderObjects.glLinkProgramARB(shader);
ARBShaderObjects.glValidateProgramARB(shader);
useShader=printLogInfo(shader);
}else useShader=false;
}
/*
* If the shader was setup succesfully, we use the shader. Otherwise
* we run normal drawing code.
*/
public void draw(){
if(useShader) {
ARBShaderObjects.glUseProgramObjectARB(shader);
}
GL11.glLoadIdentity();
GL11.glTranslatef(0.0f, 0.0f, -10.0f);
GL11.glColor3f(1.0f, 1.0f, 1.0f);//white
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex3f(-1.0f, 1.0f, 0.0f);
GL11.glVertex3f(1.0f, 1.0f, 0.0f);
GL11.glVertex3f(1.0f, -1.0f, 0.0f);
GL11.glVertex3f(-1.0f, -1.0f, 0.0f);
GL11.glEnd();
//release the shader
ARBShaderObjects.glUseProgramObjectARB(0);
}
/*
* With the exception of syntax, setting up vertex and fragment shaders
* is the same.
* #param the name and path to the vertex shader
*/
private int createVertShader(String filename){
//vertShader will be non zero if succefully created
vertShader=ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB);
//if created, convert the vertex shader code to a String
if(vertShader==0){return 0;}
String vertexCode="";
String line;
try{
BufferedReader reader=new BufferedReader(new FileReader(filename));
while((line=reader.readLine())!=null){
vertexCode+=line + "\n";
}
}catch(Exception e){
System.out.println("Fail reading vertex shading code");
return 0;
}
/*
* associate the vertex code String with the created vertex shader
* and compile
*/
ARBShaderObjects.glShaderSourceARB(vertShader, vertexCode);
ARBShaderObjects.glCompileShaderARB(vertShader);
//if there was a problem compiling, reset vertShader to zero
if(!printLogInfo(vertShader)){
vertShader=0;
}
//if zero we won't be using the shader
return vertShader;
}
//same as per the vertex shader except for method syntax
private int createFragShader(String filename){
fragShader=ARBShaderObjects.glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
if(fragShader==0){return 0;}
String fragCode="";
String line;
try{
BufferedReader reader=new BufferedReader(new FileReader(filename));
while((line=reader.readLine())!=null){
fragCode+=line + "\n";
}
}catch(Exception e){
System.out.println("Fail reading fragment shading code");
return 0;
}
ARBShaderObjects.glShaderSourceARB(fragShader, fragCode);
ARBShaderObjects.glCompileShaderARB(fragShader);
if(!printLogInfo(fragShader)){
fragShader=0;
}
return fragShader;
}
private static boolean printLogInfo(int obj){
IntBuffer iVal = BufferUtils.createIntBuffer(1);
ARBShaderObjects.glGetObjectParameterARB(obj,
ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
int length = iVal.get();
if (length > 1) {
// We have some info we need to output.
ByteBuffer infoLog = BufferUtils.createByteBuffer(length);
iVal.flip();
ARBShaderObjects.glGetInfoLogARB(obj, iVal, infoLog);
byte[] infoBytes = new byte[length];
infoLog.get(infoBytes);
String out = new String(infoBytes);
System.out.println("Info log:\n"+out);
}
else return true;
return false;
}
}
Here is the code for the fragment shader
varying vec4 vertColor;
void main(){
gl_FragColor = vertColor;
}
and vertex shader:
varying vec4 vertColor;
void main(){
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
vertColor = vec4(0.6, 0.3, 0.4, 1.0);
}
Here is the output I get when I run the code:
Info log:
Vertex shader was successfully compiled to run on hardware.
Info log:
Fragment shader was successfully compiled to run on hardware.
And here is a screenshot: http://dl.dropbox.com/u/28109593/glslss.png
The problem is due to the fact that you're seeing anything in the Info log at all, i.e. it's yielding a message on success, the way some OpenGL drivers are inclined to do. printLogInfo is also doubling as a validation function, and returning false if there was any log info, which is telling createVertShader and createFragShader to zero out your perfectly good shader id and return a failure. It's really not at all a good design, for reasons exactly like this (and I know it came from someone else, so I know I'm not slagging you off personally :)
A quick workaround for this program ONLY would be to simply make printLogInfo always return true. What you ultimately need to do is check the return status, using glGetShader(id, param), like so:
glCompileShader(obj)
if (glGetShader(obj, GL_COMPILE_STATUS) == GL_FALSE
... handle error here ...
Then for linking and validating:
glLinkProgram(obj)
if (glGetProgram(obj, GL_LINK_STATUS) == GL_FALSE
... handle error here ...
glValidateProgram(obj)
if (glGetProgram(obj, GL_VALIDATE_STATUS) == GL_FALSE
... handle error here ...
http://www.opengl.org/sdk/docs/man/xhtml/glGetShader.xml
http://www.opengl.org/sdk/docs/man/xhtml/glGetProgram.xml
I don't know the ARB_* equivalents of these, sorry, but you probably should be using OpenGL 2.0 API instead of ARB extensions for something this basic. Anything that still only supports shaders as an extension is probably not worth doing shaders on anyway.
The shaders are doing what they're supposed to do.
Don't think of shaders in the sense of what you hear in video games, shaders are simply a way of having direct access to the GPU.
The reason you're not seeing a difference in color is due to the fact that color is not being output, try changing what is being set in the fragment shader for gl_fragColor.
If you're looking for more information on shader driven opengl I'd suggest taking a look at the online book
Learning Modern 3D Graphics Programming
If you google that title, it should be the first result.
Hope this helps!
Related
I'm going through this tutorial
Whenever my mouse hovers over the cube created with this code (my version below), the Atmosphere and Stars disappear.
This is how it looks normally:
This is how it looks when I hover over the cube (Look at the atmosphere):
I'm not sure what is going on here.
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwindx.examples.tutorial;
import gov.nasa.worldwind.Configuration;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.pick.PickSupport;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.OGLUtil;
import gov.nasa.worldwindx.examples.ApplicationTemplate;
import javax.media.opengl.*;
import java.awt.*;
/**
* Example of a custom {#link Renderable} that draws a cube at a geographic position. This class shows the simplest
* possible example of a custom Renderable, while still following World Wind best practices. See
* http://goworldwind.org/developers-guide/how-to-build-a-custom-renderable/ for a complete description of this
* example.
*
* #author pabercrombie
* #version $Id: Cube.java 691 2012-07-12 19:17:17Z pabercrombie $
*/
public class Cube extends ApplicationTemplate implements Renderable
{
/** Geographic position of the cube. */
protected Position position;
/** Length of each face, in meters. */
protected double size;
/** Support object to help with pick resolution. */
protected PickSupport pickSupport = new PickSupport();
// Determined each frame
protected long frameTimestamp = -1L;
protected OrderedCube currentFramesOrderedCube;
/**
* This class holds the Cube's Cartesian coordinates. An instance of it is added to the scene controller's ordered
* renderable queue during picking and rendering.
*/
protected class OrderedCube implements OrderedRenderable
{
/** Cartesian position of the cube, computed from
* {#link gov.nasa.worldwindx.examples.tutorial.Cube#position}. */
protected Vec4 placePoint;
/** Distance from the eye point to the cube. */
protected double eyeDistance;
/**
* The cube's Cartesian bounding extent.
*/
protected Extent extent;
public double getDistanceFromEye()
{
return this.eyeDistance;
}
public void pick(DrawContext dc, Point pickPoint)
{
// Use same code for rendering and picking.
this.render(dc);
}
public void render(DrawContext dc)
{
Cube.this.drawOrderedRenderable(dc, Cube.this.pickSupport);
}
}
public Cube(Position position, double sizeInMeters)
{
this.position = position;
this.size = sizeInMeters;
}
public void render(DrawContext dc)
{
// Render is called twice, once for picking and once for rendering. In both cases an OrderedCube is added to
// the ordered renderable queue.
OrderedCube orderedCube = this.makeOrderedRenderable(dc);
if (orderedCube.extent != null)
{
if (!this.intersectsFrustum(dc, orderedCube))
return;
// If the shape is less that a pixel in size, don't render it.
if (dc.isSmall(orderedCube.extent, 1))
return;
}
// Add the cube to the ordered renderable queue. The SceneController sorts the ordered renderables by eye
// distance, and then renders them back to front.
dc.addOrderedRenderable(orderedCube);
}
/**
* Determines whether the cube intersects the view frustum.
*
* #param dc the current draw context.
*
* #return true if this cube intersects the frustum, otherwise false.
*/
protected boolean intersectsFrustum(DrawContext dc, OrderedCube orderedCube)
{
if (dc.isPickingMode())
return dc.getPickFrustums().intersectsAny(orderedCube.extent);
return dc.getView().getFrustumInModelCoordinates().intersects(orderedCube.extent);
}
/**
* Compute per-frame attributes, and add the ordered renderable to the ordered renderable list.
*
* #param dc Current draw context.
*/
protected OrderedCube makeOrderedRenderable(DrawContext dc)
{
// This method is called twice each frame: once during picking and once during rendering. We only need to
// compute the placePoint, eye distance and extent once per frame, so check the frame timestamp to see if
// this is a new frame. However, we can't use this optimization for 2D continuous globes because the
// Cartesian coordinates of the cube are different for each 2D globe drawn during the current frame.
if (dc.getFrameTimeStamp() != this.frameTimestamp || dc.isContinuous2DGlobe())
{
OrderedCube orderedCube = new OrderedCube();
// Convert the cube's geographic position to a position in Cartesian coordinates. If drawing to a 2D
// globe ignore the shape's altitude.
if (dc.is2DGlobe())
{
orderedCube.placePoint = dc.getGlobe().computePointFromPosition(this.position.getLatitude(),
this.position.getLongitude(), 0);
}
else
{
orderedCube.placePoint = dc.getGlobe().computePointFromPosition(this.position);
}
// Compute the distance from the eye to the cube's position.
orderedCube.eyeDistance = dc.getView().getEyePoint().distanceTo3(orderedCube.placePoint);
// Compute a sphere that encloses the cube. We'll use this sphere for intersection calculations to determine
// if the cube is actually visible.
orderedCube.extent = new Sphere(orderedCube.placePoint, Math.sqrt(3.0) * this.size / 2.0);
// Keep track of the timestamp we used to compute the ordered renderable.
this.frameTimestamp = dc.getFrameTimeStamp();
this.currentFramesOrderedCube = orderedCube;
return orderedCube;
}
else
{
return this.currentFramesOrderedCube;
}
}
/**
* Set up drawing state, and draw the cube. This method is called when the cube is rendered in ordered rendering
* mode.
*
* #param dc Current draw context.
*/
protected void drawOrderedRenderable(DrawContext dc, PickSupport pickCandidates)
{
this.beginDrawing(dc);
try
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
if (dc.isPickingMode())
{
Color pickColor = dc.getUniquePickColor();
pickCandidates.addPickableObject(pickColor.getRGB(), this, this.position);
gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue());
}
// Render a unit cube and apply a scaling factor to scale the cube to the appropriate size.
gl.glScaled(this.size, this.size, this.size);
this.drawUnitCube(dc);
}
finally
{
this.endDrawing(dc);
}
}
/**
* Setup drawing state in preparation for drawing the cube. State changed by this method must be restored in
* endDrawing.
*
* #param dc Active draw context.
*/
protected void beginDrawing(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
int attrMask = GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT;
gl.glPushAttrib(attrMask);
if (!dc.isPickingMode())
{
dc.beginStandardLighting();
gl.glEnable(GL.GL_BLEND);
OGLUtil.applyBlending(gl, false);
// Were applying a scale transform on the modelview matrix, so the normal vectors must be re-normalized
// before lighting is computed.
gl.glEnable(GL2.GL_NORMALIZE);
}
// Multiply the modelview matrix by a surface orientation matrix to set up a local coordinate system with the
// origin at the cube's center position, the Y axis pointing North, the X axis pointing East, and the Z axis
// normal to the globe.
gl.glMatrixMode(GL2.GL_MODELVIEW);
Matrix matrix = dc.getGlobe().computeSurfaceOrientationAtPosition(this.position);
matrix = dc.getView().getModelviewMatrix().multiply(matrix);
double[] matrixArray = new double[16];
matrix.toArray(matrixArray, 0, false);
gl.glLoadMatrixd(matrixArray, 0);
}
/**
* Restore drawing state changed in beginDrawing to the default.
*
* #param dc Active draw context.
*/
protected void endDrawing(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
if (!dc.isPickingMode())
dc.endStandardLighting();
gl.glPopAttrib();
}
/**
* Draw a unit cube, using the active modelview matrix to orient the shape.
*
* #param dc Current draw context.
*/
protected void drawUnitCube(DrawContext dc)
{
// Vertices of a unit cube, centered on the origin.
float[][] v = {{-0.5f, 0.5f, -0.5f}, {-0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, 0.5f}, {0.5f, 0.5f, -0.5f},
{-0.5f, -0.5f, 0.5f}, {0.5f, -0.5f, 0.5f}, {0.5f, -0.5f, -0.5f}, {-0.5f, -0.5f, -0.5f}};
// Array to group vertices into faces
int[][] faces = {{0, 1, 2, 3}, {2, 5, 6, 3}, {1, 4, 5, 2}, {0, 7, 4, 1}, {0, 7, 6, 3}, {4, 7, 6, 5}};
// Normal vectors for each face
float[][] n = {{0, 1, 0}, {1, 0, 0}, {0, 0, 1}, {-1, 0, 0}, {0, 0, -1}, {0, -1, 0}};
// Note: draw the cube in OpenGL immediate mode for simplicity. Real applications should use vertex arrays
// or vertex buffer objects to achieve better performance.
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
gl.glBegin(GL2.GL_QUADS);
try
{
for (int i = 0; i < faces.length; i++)
{
gl.glNormal3f(n[i][0], n[i][1], n[i][2]);
for (int j = 0; j < faces[0].length; j++)
{
gl.glVertex3f(v[faces[i][j]][0], v[faces[i][j]][1], v[faces[i][j]][2]);
}
}
}
finally
{
gl.glEnd();
}
}
protected static class AppFrame extends ApplicationTemplate.AppFrame
{
public AppFrame()
{
super(true, true, false);
RenderableLayer layer = new RenderableLayer();
Cube cube = new Cube(Position.fromDegrees(35.0, -120.0, 3000), 100000);
layer.addRenderable(cube);
getWwd().getModel().getLayers().add(layer);
}
}
public static void main(String[] args)
{
Configuration.setValue(AVKey.INITIAL_LATITUDE, 35.0);
Configuration.setValue(AVKey.INITIAL_LONGITUDE, -120.0);
Configuration.setValue(AVKey.INITIAL_ALTITUDE, 2550000);
Configuration.setValue(AVKey.INITIAL_PITCH, 45);
Configuration.setValue(AVKey.INITIAL_HEADING, 45);
ApplicationTemplate.start("World Wind Custom Renderable Tutorial", AppFrame.class);
}
}
I have reproduced the problem, both with the tutorial Cube class that is included in worldwind.jar and your Cube class that draws a helpfully larger cube.
I have traced the point at which the atmosphere disappears is when the hidden buffer for the GLCanvas is swapped within the WorldWind render code, so the problem is that for some reason the atmosphere and stars layers are not drawn on the hidden buffer during rendering in picking mode using your code.
I then found that the example with Cylinders included as gov.nasa.worldwindx.examples.Cylinders.class draws pickable 3D shapes (cylinders) on the globe and does not exhibit this problem (there are others - Boxes for example is extremely close to this tutorial).
I think that that the issue is with the implementation of OrderedRenderable in this tutorial example - in the Cylinders example, the actual Cylinder class extends RigidShape which in turn extends AbstractShape, which is the class that actually implements OrderedRenderable. It's definitely a bug. Maybe you can work from the Boxes example to get the functionality you need.
I ended up getting an answer on the worldwind forums: http://forum.worldwindcentral.com/showthread.php?46115-Worldwind-Custom-Renderable-Picking-Issue&p=125173
Add a gl push matrix call in the begin drawing method:
protected void beginDrawing(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
int attrMask = GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT;
gl.glPushAttrib(attrMask);
if (!dc.isPickingMode())
{
dc.beginStandardLighting();
gl.glEnable(GL.GL_BLEND);
OGLUtil.applyBlending(gl, false);
// Were applying a scale transform on the modelview matrix, so the normal vectors must be re-normalized
// before lighting is computed.
gl.glEnable(GL2.GL_NORMALIZE);
}
// Multiply the modelview matrix by a surface orientation matrix to set up a local coordinate system with the
// origin at the cube's center position, the Y axis pointing North, the X axis pointing East, and the Z axis
// normal to the globe.
gl.glPushMatrix();
gl.glMatrixMode(GL2.GL_MODELVIEW);
Matrix matrix = dc.getGlobe().computeSurfaceOrientationAtPosition(this.position);
matrix = dc.getView().getModelviewMatrix().multiply(matrix);
double[] matrixArray = new double[16];
matrix.toArray(matrixArray, 0, false);
gl.glLoadMatrixd(matrixArray, 0);
}
And additionally, add a gl pop matrix call in the end drawing:
protected void endDrawing(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
if (!dc.isPickingMode())
dc.endStandardLighting();
gl.glPopMatrix();
gl.glPopAttrib();
}
move
if (!dc.isPickingMode())
dc.endStandardLighting();
from
protected void endDrawing(DrawContext dc)
after
gl.glLoadMatrixd(matrixArray, 0);
in
protected void beginDrawing(DrawContext dc)
I do a Mario like game with the libgdx library.
All works fine but sometime (especially when the camera goes fast) my TileMap has a little bug during the render.
A picture worth thousand word, so here it is : http://postimg.org/image/4tudtwewn/
I have tried to increment FPS, but there is no change. I have no idea where that is come from.
Here is my code :
public void show() {
TmxMapLoader loader = new TmxMapLoader();
this.plan = loader.load("maps/level-"+this.world+"-"+this.level+".tmx");
this.renderer = new OrthogonalTiledMapRenderer(this.plan);
...
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.renderer.render();// rendu de la carte
Batch batch = this.renderer.getSpriteBatch();
...
This happens when your Camera's position is not perfectly aligned with screen-space coordinates (pixels).
This results in some sprites being rounded to the next pixel while some other (that were connected to those) being rounded to the previous one, resulting in visible ugly glitches.
The easiest fix I could come up with is making sure that the Camera position is always perfectly aligned with screen-space coordinates.
public class TileMapCamera extends OrthographicCamera {
// Map tile size to round to
private int tileSize;
/**
* Create a pixel-perfect camera for a map with the specified tile size
* #param tileSize
*/
public TileMapCamera(int tileSize){
this.tileSize = tileSize;
}
#Override
public void update(){
// Round position to avoid glitches
float prevx = position.x;
float prevy = position.y;
position.x = (int)(position.x * tileSize) / (float)tileSize;
position.y = (int)(position.y * tileSize) / (float)tileSize;
super.update();
position.set(prevx, prevy, 0);
}
}
This works for a tile-based coordinate viewport:
mapViewport = new FitViewport(16, 15, new TileMapCamera(map.getProperties().get("tilewidth", Integer.class)));
If you're working with pixel-based coordinate viewports, you should round the camera position to the nearest integer instead.
I think its about the filtering.
This will help:
TiledMapRenderer Artifact
If the problem you are referring to, is the spacing you can fix when you import the tileset as it says Tenfour04
add or change pixel padding.
I'm following a tutorial on creating a Game Engine in Java using OpenGL.
I'm trying to render a triangle on the screen. Everything is running fine and I can change the background color but the triangle won't show. I've also tried running the code provided as part of the tutorial series and it still doesn't work.
Link to the tutorial: http://bit.ly/1EUnvz4
Link to the code used in the video: http://bit.ly/1z7XUlE
Setup
I've tried checking for OpenGL version and belive I have 2.1.
Mac OSX
Java - Eclipse
Mesh.java
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
public class Mesh
{
private int vbo; //pointer to the buffer
private int size; //size of the data to buffer
public Mesh ()
{
vbo = glGenBuffers();
size = 0;
}
public void addVertices (Vertex[] vertices)
{
size = vertices.length;
//add the data by first binding the buffer
glBindBuffer (GL_ARRAY_BUFFER, vbo); //vbo is now the buffer
//and then buffering the data
glBufferData (GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);
}
public void draw ()
{
glEnableVertexAttribArray (0); //divide up the data into a segment
glBindBuffer (GL_ARRAY_BUFFER, vbo); //vbo is now the buffer
//tell OpenGL more about the segment:
//segment = 0, elements = 3, type = float, normalize? = false, vertex size, where to start = 0)
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
//draw GL_TRIANGLES starting from '0' with a given 'size'
glDrawArrays (GL_TRIANGLES, 0, size);
glDisableVertexAttribArray (0);
}
}
RenderUtil.java
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL30.*;
public class RenderUtil
{
public static void clearScreen ()
{
//TODO: Stencil Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
//set everything to engine defaults
public static void initGraphics ()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // default color
glFrontFace(GL_CW); // direction for visible faces
glCullFace(GL_BACK); // direction for back faces
glEnable (GL_CULL_FACE); // don't draw back faces
glEnable (GL_DEPTH_TEST); // determines draw order by pixel depth testing
//TODO: Depth clamp for later
glEnable (GL_FRAMEBUFFER_SRGB); // do exponential correction on gamma so we don't have to
}
}
Util.java
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
public class Util
{
//create a float buffer (we need this because java is weird)
public static FloatBuffer createFloatBuffer (int size)
{
return BufferUtils.createFloatBuffer(size);
}
//flip the buffer to fit what OpenGL expects
public static FloatBuffer createFlippedBuffer (Vertex[] vertices)
{
FloatBuffer buffer = createFloatBuffer(vertices.length * Vertex.SIZE);
for (int i = 0; i < vertices.length; i++)
{
buffer.put(vertices[i].getPos().getX());
buffer.put(vertices[i].getPos().getY());
buffer.put(vertices[i].getPos().getZ());
}
buffer.flip();
return buffer;
}
}
You are using an invalid mix of legacy and modern OpenGL.
The glVertexAttribPointer() and glEnableVertexAttribArray() functions you are calling are used for setting up generic vertex attributes. This is the only way to set up vertex attribues in current versions of OpenGL (Core Profile of desktop OpenGL, or OpenGL ES 2.0 and later). They can be used in older versions of OpenGL as well, but only in combination with providing your own shaders implemented in GLSL.
If you are just getting started, your best option is probably to stick with what you have, and study how to start implementing your own shaders. If you wanted to get the code working with the legacy fixed pipeline (which is only supported in the Compatibility Profile of OpenGL), you would need to use the glVertexPointer() and glEnableClientState() functions instead.
Try a single import?
import static org.lwjgl.opengl.GL11.*
I only have one import on mine, also try importing the packages you need separately. One thing you are likely doing wrong is importing multiple versions of OpenGL
I am using Mesa 10.1.3 to be able to use OpenGL 3.3 on my Linux computer. I request a core profile when I create the window since only the core profile has OpenGL 3.3. But when I tried to write a simple program to display a triangle on the screen, I got nothing. So I thought I screwed up somewhere in the code but I rechecked it and it was correct. To test this, I tried running the program in Windows and it was working as it should. So I experimented a little bit more with the code; I multiplied the vertex location in the vertex shader by 0.001 and only then I was able to see my triangle, but even then, it was not working as it should. The triangle I see was a right angle triangle whereas I intended it to be an equilateral one (in Windows I see an equilateral triangle). So my guess is vertex location is somehow different when using OpenGL Core profile, but I don't quite know how to fix this. What am I doing wrong and what should I be doing?
By the way, this is my vertex shader looks like:
#version 330
in vec3 position;
void main()
{
gl_Position = vec4(0.001*position, 1.0);
}
Fragment shader:
#version 330
out vec4 fragColor;
void main()
{
fragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
Shader class:
public Shader()
{
program = glCreateProgram();
if(program == 0)
{
System.err.println("Shader creation failed: Could not find valid memory location");
System.exit(1);
}
}
public void bind()
{
glBindAttribLocation(program, 0, "position");
glUseProgram(program);
}
public void addVertexShader(String text)
{
addProgram(text, GL_VERTEX_SHADER);
}
public void addFragmentShader(String text)
{
addProgram(text, GL_FRAGMENT_SHADER);
}
public void addGeometryShader(String text)
{
addProgram(text, GL_GEOMETRY_SHADER);
}
public void compile()
{
glLinkProgram(program);
if(glGetProgrami(program, GL_LINK_STATUS) == 0)
{
System.err.println(glGetProgramInfoLog(program, 1024));
System.exit(1);
}
glValidateProgram(program);
if(glGetProgrami(program, GL_VALIDATE_STATUS) == 0)
{
System.err.println(glGetProgramInfoLog(program, 1024));
System.exit(1);
}
}
public void addProgram(String text, int type)
{
int shader = glCreateShader(type);
if(shader == 0)
{
System.err.println("Shader creation failed");
System.exit(1);
}
glShaderSource(shader, text);
glCompileShader(shader);
if(glGetShaderi(shader, GL_COMPILE_STATUS) == 0)
{
System.err.println(glGetShaderInfoLog(shader, 1024));
System.exit(1);
}
glAttachShader(program, shader);
}
And my array of vertices which I'm creating the VBO with:
Vertex[] data = new Vertex[] {
new Vertex(new Vector3f(-0.1f, -0.1f, 0)),
new Vertex(new Vector3f(0, 1, 0)),
new Vertex(new Vector3f( 1, -1, 0))};
My draw method:
public void draw()
{
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//Vertex is a class which only holds a Vector3f for position, currently, so size is set to 3
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
glDrawArrays(GL_TRIANGLES, 0, size);
glDisableVertexAttribArray(0);
}
And this is the result that I'm getting:
Your glBindAttribLocation() call comes too late:
glBindAttribLocation(program, 0, "position");
glUseProgram(program);
glBindAttribLocation() needs to be called before the glLinkProgram() to have any effect. You can move it, or use glGetAttribLocation() after linking to get the location that the linker assigned to the attribute. Or even easier, since you use GLSL 3.30, you can specify the location in the shader code:
layout(location = 0) in vec3 position;
When using the Core Profile, you will also need to use Vertex Array Objects (VAO). If you don't have calls like glGenVertexArrays() and glBindVertexArray() in your code, you will need those. There should be plenty of examples here on SO or on the rest of the internet if you search for "OpenGL VAO" or "OpenGL Vertex Array Object", so I won't repeat too much of it. Roughly, you will have something like this before you start initializing your vertex state:
GLuint vaoId = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// calls to glVertexAttribPointer, glEnableVertexAttribArray
Then when you get ready to draw:
glBindVertexArray(vao);
Your vertex data definition also looks like it could be a source of trouble:
Vertex[] data = new Vertex[] {
new Vertex(new Vector3f(-0.1f, -0.1f, 0)),
new Vertex(new Vector3f(0, 1, 0)),
new Vertex(new Vector3f( 1, -1, 0))};
While the code for filling this into the VBO is not shown, the data passed to glBufferData() needs to be a flat, contiguous array/buffer of floats, while this is an array of vector object references.
I'm trying to make top and bottom walls for my Pong game. I think I have everything right but it will not run because it says "The local variable wall may not have been initialized". How do I initialize an Image?
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Wall extends Block
{
/**
* Constructs a Wall with position and dimensions
* #param x the x position
* #param y the y position
* #param wdt the width
* #param hgt the height
*/
public Wall(int x, int y, int wdt, int hgt)
{super(x, y, wdt, hgt);}
/**
* Draws the wall
* #param window the graphics object
*/
public void draw(Graphics window)
{
Image wall;
try
{wall = ImageIO.read(new File("C:/eclipse/projects/Pong/wall.png"));}
catch (IOException e)
{e.printStackTrace();}
window.drawImage(wall, getX(), getY(), getWidth(), getHeight(), null);
}
}
Thanks to everyone who answered I've figured it out. I didn't realize I just needed to set wall = null.
Your image is indeed initialised with the statement
wall = ImageIO.read(new File("C:/eclipse/projects/Pong/wall.png"));
However, the compiler is complaining because that statement could possibly fail, as it is in a try/catch block. A possible way to just "satisfy" the compiler is to set the Image variable to null:
Image wall = null;
You are initializing the Image correctly. The reason Java is complaining is you have it in a try block. Try blocks are not guaranteed to run and you don't compensate for the possibility of the code failing in the catch block, so it you (and more importantly, Java) can't be sure that wall will exist when you call window.drawImage(). A possible fix would be (cutting out the imports but with a bit of code for reference):
public class Wall extends Block
{
/**
* Constructs a Wall with position and dimensions
* #param x the x position
* #param y the y position
* #param wdt the width
* #param hgt the height
*/
public Wall(int x, int y, int wdt, int hgt)
{super(x, y, wdt, hgt);}
/**
* Draws the wall
* #param window the graphics object
*/
public void draw(Graphics window)
{
Image wall;
try
{wall = ImageIO.read(new File("C:/eclipse/projects/Pong/wall.png"));}
catch (IOException e)
{
e.printStackTrace();
wall = new BufferedWindow(getWidth(), getHeight(), <Correct Image Type>);
}
window.drawImage(wall, getX(), getY(), getWidth(), getHeight(), null);
}
}
Always initialization of the variable declared to class is important
Image wall = null;