Unable to load Attribute into shader - java

I would like to have some custom data stored inside the shader to be re-used for multiple frame during rendering.
At first what I try to do is to store a color buffer, to see is this can be done.
vertex shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
vec2 u_mouse;
uniform float u_time;
attribute vec3 my_data;
varying vec3 frag_data;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
frag_data = my_data;
}
fragment shader:
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
varying vec3 frag_data;
void main(){
gl_FragColor = vec4(vec3(frag_data),1.0);
}
The shaders compile and work as intended with the exception of the usage of vec3 my_data:
ShaderProgram.pedantic = false;
vertex_shader = Gdx.files.internal("vertex_shader.glsl").readString();
fragment_shader = Gdx.files.internal("fragment_shader.glsl").readString();
shader_program = new ShaderProgram(vertex_shader, fragment_shader);
I try to set the variable from a button-click, like so:
goBtn = new TextButton("Reset", textButtonStyle);
goBtn.setSize(128,128);
goBtn.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
FloatBuffer myArray = BufferUtils.newFloatBuffer(3);
myArray.put(1.0f);myArray.put(1.0f);myArray.put(1.0f);
shader_program.begin();
shader_program.setVertexAttribute("my_data", 3, GL20.GL_FLOAT, false, 0, myArray);
shader_program.end();
}
});
But it has no effect..
What am I doing wrong here?
What would be the correct way to do this?

I've never tried setting a vertex attribute via the ShaderProgram. I'm not even sure why that exists as an option, because vertex data is supposed to be per-vertex. Since you are setting this for the whole mesh, it should be a uniform. And since it's a uniform, you don't have to pass it via a varying either.
So remove the varying and attribute from your vertex shader. And change the varying in the fragment shader to a uniform.
And to pass the data:
public void changed(ChangeEvent event, Actor actor) {
shader_program.begin();
shader_program.setUniformf("my_data", 1.0f, 1.0f, 1.0f);
shader_program.end();
}
But you should also call this code to set the default values for this uniform when you are first setting things up. Behavior might be undefined before you set their values.

Related

Shader gives wrong fragment color

I've run into the strangest problem I've ever had in my shader experience. I created some test shader code (see below) and ran it on a simple texture.
Basically what I was trying to do is make my shader check the color of a fragment, and if it was within a certain range it would color that fragment according to a uniform color variable. The problem I'm having is that my shader does not correctly recognize the color of a fragment. I even went as far as to check if the red portion of the color is equal to one and it always returns true for every fragment. Yet if I use the same shader to draw the original texture it works just fine.
Why is this happening? The shader compiles without any errors what so ever. I feel like I'm missing something obvious...
Code (if you have access to LibGDX you can run this code for yourself).
// Vertex
#version 330
in vec4 a_position;
in vec4 a_color;
in vec2 a_texCoord0;
out vec4 v_color;
out vec2 v_texCoord0;
uniform mat4 u_projTrans;
void main() {
v_color = a_color;
v_texCoord0 = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
// Fragment
#version 330
in vec4 v_color;
in vec2 v_texCoord0;
out vec4 outColor;
uniform vec4 color;
uniform sampler2D u_texture;
void main() {
// This is always true for some reason...
if(v_color.r == 1.0) {
outColor = color;
} else {
// But if I run this code it draws the original texture just fine with the correct colors.
outColor = v_color * texture2D(u_texture, v_texCoord0);
}
}
// Java code.
// Creating sprite, shader and sprite batch.
SpriteBatch batch = new SpriteBatch();
Sprite sprite = new Sprite(new Texture("testTexture.png"));
ShaderProgram shader = new ShaderProgram(Gdx.files.internal("vertex.vert"),
Gdx.files.internal("fragment.frag"));
// Check to see if the shader has logged any errors. Prints nothing.
System.out.println(shader.getLog());
// We start the rendering.
batch.begin();
// We begin the shader so we can load uniforms into it.
shader.begin();
// Set the uniform (works fine).
shader.setUniformf("color", Color.RED);
// We end the shader to tell it we've finished loading uniforms.
shader.end();
// We then tell our renderer to use this shader.
batch.setShader(shader);
// Then we draw our sprite.
sprite.draw(batch);
// And finally we tell our renderer that we're finished drawing.
batch.end();
// Dispose to release resources.
shader.dispose();
batch.dispose();
sprite.getTexture().dispose();
The texture:
You have 2 input colors for your fragment shader: one sent as a vertex attribute and one as a texture. You intend to check the texture color but instead you check for the color value sent as the vertex attribute.
// Vertex
#version 330
in vec4 a_position;
in vec4 a_color; // <--- A color value is passed as a vertex attribute
in vec2 a_texCoord0;
out vec4 v_color;
out vec2 v_texCoord0;
uniform mat4 u_projTrans;
void main() {
v_color = a_color; // <--- you are sending it to fragment shader
v_texCoord0 = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
// Fragment
#version 330
in vec4 v_color; // <--- coming from vertex buffer
in vec2 v_texCoord0;
out vec4 outColor;
uniform vec4 color;
uniform sampler2D u_texture;
void main() {
// This is always true for some reason...
if(v_color.r == 1.0) { // <--- and then checking this vertex attribute color
outColor = color; // instead of what you send from texture
} else {
...
}
}

GLSL Shader won't work on mac

I am trying to create a GLSL texture shader in java on a mac, but mac doesn't support any version above #version 120. How would I port this 330 shader:
//this is my Vertex Shader
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
out vec2 texCoord0;
uniform mat4 transform;
void main()
{
gl_Position=transform*vec4(position,1.0);
texCoord0=texCoord;
}
This is my Fragment Shader
#version 330
in vec2 texCoord0;
uniform sampler2D sampler;
out vec4 gl_FragColor;
void main()
{
gl_FragColor=texture2D(sampler,texCoord0.xy);
}
How do I convert these shaders to glsl 120 without losing functionality?
You just have to:
_Remove the layout qualifiers (including location assignment). You'll the have to use
void glBindAttribLocation(GLuint program,
GLuint index,
const GLchar *name);
for each input of your vertex shader (with index set to 0 and 1 for location 0 and 1 and the name of the variable in case you didn't understand) before linking your program
_In the vertex shader, replace in by attribute and out by varying
_In the fragment shader, replace in by varying and use gl_FragColor but without declaring it
In your case, you would have this just before linking your program:
//program is your shader program of course...
//Bind vertex shader attributes (ins) instead of using layout
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "texCoord");
//Then the program should be linked (or relinked, it doesn't matter)
glLinkProgram(program);
Your vertex shader:
#version 120
attribute vec3 position;
attribute vec2 texCoord;
varying vec2 texCoord0;
uniform mat4 transform;
void main()
{
gl_Position = transform*vec4(position, 1.0);
texCoord0 = texCoord;
}
And your fragment shader:
#version 120
varying vec2 texCoord0;
uniform sampler2D sampler;
void main()
{
gl_FragColor = texture2D(sampler, texCoord0.xy);
}

Libgdx shaders in a Stage?

In libgdx, I have a shader loaded, and I want to make my Stage object use that shader to draw. I tried setting a SpriteBatch's shader to my shader, and then the Stage's sprite batch to that one, but it shows up as a black screen. Why doesn't this work:
ShaderProgram shader = new ShaderProgram(Gdx.files.internal("shader.vert"), Gdx.files.internal("shader.frag"));
SpriteBatch batch = new SpriteBatch();
batch.setShader(shader);
Stage stage = new Stage(new StretchViewport(768, 576), batch);
...
stage.act();
shader.begin();
stage.draw();
shader.end();
My shaders look like:
shader.vert
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main()
{
v_color = a_color;
v_color.a = v_color.a * (256.0/255.0);
v_texCoords = a_texCoord + 0;
gl_Position = u_projTrans * a_position;
}
shader.frag
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
varying LOWP vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}
It seems to only work with one texture. Every other texture doesn't render. And also, making textures power of 2 doesn't make a difference.
SpriteBatch has certain expected attribute names. You are using a_texCoord, but it expects a_texCoord0, so the shader is going to treat all the UV's as if they are 0,0.
You mention setting the shader on both the SpriteBatch and the Stage's SpriteBatch, but in your code, they are one and the same.
You don't need to call begin and end on the shader, because SpriteBatch (and therefore Stage) does this automatically. I'm not sure if that could cause problems.
I can't explain why what you did would have worked with one of your textures. I would expect it to just draw everything as the same color as the lower left pixel of the texture.
There might be other issues afoot, but I'm assuming it was drawing correctly before you inserted your own shader.

Texture on mesh doesnt render, just shows black libgdx gl20

edit--
I've updated my code after TenFour04s answer but still just shows black.
I've updated my libgdx and its required me to use gl20 which has lead me to make a few changes
most of it works fine except when trying to do texture the mesh. This currently shows surface mesh as black and doesnt show the ground mesh at all. with some changes I can get it to show both surface and ground meshes as black.
I've played around with binding and the order of surTexture.bind and grdTexture.bind and using numbers less than 16 and render and i've got it to use the surface texture as the texture for everything except the surface and ground.
Can anyone see where I might be going wrong with this?
// creating a mesh with maxVertices set to vertices,size*3
groundMesh = new Mesh(true, vertices.size*3, vertices.size*3,
new VertexAttribute(Usage.Position,2,ShaderProgram.POSITION_ATTRIBUTE),
new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE));
groundMesh.setVertices(temp);
short[] indices = new short[vertices.size*2];
for(int i=0;i<vertices.size*2;i++){
indices[i] = (short)i;
}
groundMesh.setIndices(indices);
surfaceMesh = new Mesh(true, vertices.size*3, vertices.size*3,
new VertexAttribute(Usage.Position,3,ShaderProgram.POSITION_ATTRIBUTE),
new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE));
...
grdTexture = new Texture(Gdx.files.internal("data/img/leveltest/ground.png"));
// Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE16);
//says that setWrap and SetFilter bind the texture so I thought I might have to set
//activetexture here but does nothing.
grdTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
grdTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
surTexture = new Texture(Gdx.files.internal("data/img/leveltest/surface.png"));
// Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE17);
surTexture.setWrap(TextureWrap.Repeat, TextureWrap.ClampToEdge);
//TODO change these filters for better quality
surTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
drawWorld gets called inside render()
public void drawWorld(SpriteBatch batch,OrthographicCamera camera) {
batch.begin();
batch.setProjectionMatrix(camera.combined);
layers.drawLayers(batch);
if ((spatials != null) && (spatials.size > 0)){
for (int i = 0; i < spatials.size; i++){
spatials.get(i).render(batch);
}
}
batch.end();
drawGround(camera);
}
private void drawGround(OrthographicCamera camera){
shader.begin();
shader.setUniformMatrix("u_projTrans", camera.combined);
grdTexture.bind(0);
shader.setUniformi("u_texture", 0);
//changed GL_TRIANGLES to GL_TRIANGLE_STRIP to render meshes correctly after changing to GL20
groundMesh.render(shader, GL20.GL_TRIANGLE_STRIP);
surTexture.bind(0);
shader.setUniformi("u_texture", 0);
surfaceMesh.render(shader, GL20.GL_TRIANGLE_STRIP);
shader.end();
}
fragment.glsl
#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#else
#define LOWP
#endif
varying LOWP vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main()
{
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}
vertex.glsl
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_color.a = v_color.a * (256.0/255.0);
v_texCoords = a_texCoord;
gl_Position = u_projTrans * a_position;
}
In your vertex shader, you are using a_texCoord, but in your mesh constructor, you have effectively named your attributes a_texCoord16 and a_texCoord17 by using ShaderProgram.TEXCOORD_ATTRIBUTE+"16" and ShaderProgram.TEXCOORD_ATTRIBUTE+"17".
Since you are not multi-texturing, I would just replace those with "a_texCoord".
It looks like maybe you are conflating attribute name suffixes with what texture units are, although the two concepts are not necessarily related. The reason you might want to add number suffixes to your texCoords is if your mesh has multiple UV's for each vertex because it is multi-tetxtured. But really you can use any naming scheme you like. The reason you might want to bind to a unit other than 0 is if you're multi-texturing on a single mesh so you need multiple textures bound at once. So if you actually were multi-texturing, using attribute suffixes that match texture unit numbers might help avoid confusion when you are trying to match UV's to textures in the fragment shader.
ok so it turns out the problem was the vertex shader
They code from here doesnt work.
here is the working shader
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = vec4(1, 1, 1, 1);
v_texCoords = a_texCoord;
gl_Position = u_projTrans * a_position;
}

libgdx shaders- basic shader, but screen is blank

I'm trying to understand shaders using libgdx, coming from an XNA/HLSL background. I'm trying to get a vert/frag shader pair to reproduce the output I get without a shader, but it's not displaying anything.
Shader creation:
void SetupShader()
{
ShaderProgram.pedantic = false;
shader = new ShaderProgram(
Gdx.files.internal("assets/default.vert").readString(),
Gdx.files.internal("assets/default.frag").readString());
if(!shader.isCompiled()) {
Gdx.app.log("Problem loading shader:", shader.getLog());
}
batch.setShader(shader);
}
default.vert:
attribute vec4 a_Position;
attribute vec4 a_Normal;
attribute vec2 a_TexCoord;
attribute vec4 a_Color;
uniform mat4 u_projTrans;
varying vec2 v_texCoords;
varying vec4 v_color;
void main() {
v_color = a_Color;
v_texCoords = a_TexCoord;
gl_Position = u_projTrans * a_Position;
}
default.frag:
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoords;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
Rendering:
batch.begin();
for (GameObject gObj : gameObjects)
gObj.Draw(batch);
batch.end();
Any suggestions here? I'm new to OpenGL-ES as well, so I may be missing something obvious. I looked around a bit before posting, and the doc for SpriteBatch.setShader(ShaderProgram) was as follows:
Sets the shader to be used in a GLES 2.0 environment. Vertex position
attribute is called "a_position", the texture coordinates attribute is
called called "a_texCoords0", the color attribute is called "a_color".
See ShaderProgram.POSITION_ATTRIBUTE, ShaderProgram.COLOR_ATTRIBUTE
and ShaderProgram.TEXCOORD_ATTRIBUTE which gets "0" appened to
indicate the use of the first texture unit. The projection matrix is
uploaded via a mat4 uniform called "u_proj", the transform matrix is
uploaded via a uniform called "u_trans", the combined transform and
projection matrx is is uploaded via a mat4 uniform called
"u_projTrans". The texture sampler is passed via a uniform called
"u_texture". Call this method with a null argument to use the default
shader.
After looking at the code in SpriteBatch it seems that I had a few mistakes in my code. Below are the correct shaders:
default.vert:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
default.frag:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main() {
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
}

Categories

Resources