This is mostly a general question, since I can't get any shader to work at all. The usual sprites and textures render just fine, it just doesn't happen anything with the shaders. Not getting any error messages from the shader log either. As far as I understand, for a filter of the type below, one only need to set the shader to the batch, like batch.setShader(shader), and set any uniforms, and the batch will take care of the rest. If I am wrong, please tell me my errors.
Fragment shader, supposed to blur
//"in" attributes from our vertex shader
varying vec2 v_texCoord0;
//declare uniforms
uniform sampler2D uImage0;
uniform vec2 uResolution;
uniform float radius;
uniform float dirx;
uniform float diry;
void main()
{
//this will be our RGBA sum
vec4 sum = vec4(0.0);
//our original texcoord for this fragment
vec2 tc = v_texCoord0;
//the amount to blur, i.e. how far off center to sample from
//1.0 -> blur by one pixel
//2.0 -> blur by two pixels, etc.
float blur = radius / uResolution.x;
//the direction of our blur
//(1.0, 0.0) -> x-axis blur
//(0.0, 1.0) -> y-axis blur
float hstep = dirx;
float vstep = diry;
//apply blurring, using a 9-tap filter with predefined gaussian weights
sum += texture2D(uImage0, vec2(tc.x - 4.0*blur*hstep, tc.y - 4.0*blur*vstep)) * 0.0162162162;
sum += texture2D(uImage0, vec2(tc.x - 3.0*blur*hstep, tc.y - 3.0*blur*vstep)) * 0.0540540541;
sum += texture2D(uImage0, vec2(tc.x - 2.0*blur*hstep, tc.y - 2.0*blur*vstep)) * 0.1216216216;
sum += texture2D(uImage0, vec2(tc.x - 1.0*blur*hstep, tc.y - 1.0*blur*vstep)) * 0.1945945946;
sum += texture2D(uImage0, vec2(tc.x, tc.y)) * 0.2270270270;
sum += texture2D(uImage0, vec2(tc.x + 1.0*blur*hstep, tc.y + 1.0*blur*vstep)) * 0.1945945946;
sum += texture2D(uImage0, vec2(tc.x + 2.0*blur*hstep, tc.y + 2.0*blur*vstep)) * 0.1216216216;
sum += texture2D(uImage0, vec2(tc.x + 3.0*blur*hstep, tc.y + 3.0*blur*vstep)) * 0.0540540541;
sum += texture2D(uImage0, vec2(tc.x + 4.0*blur*hstep, tc.y + 4.0*blur*vstep)) * 0.0162162162;
//discard alpha for our simple demo, multiply by vertex color and return
gl_FragColor = vec4(sum.rgb, 1.0);
}
Vertex shader
attribute vec4 a_color;
attribute vec2 a_texCoord0;
attribute vec3 a_position;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoord0;
void main(){
v_color = a_color;
v_texCoord0 = a_texCoord0;
gl_Position = u_projTrans * vec4(a_position,1.0) ;
}
Setting up the shader. Tried different values here
public void setupShader(){
ShaderProgram.pedantic=true;
shader = new ShaderProgram(Gdx.files.internal("shaders/pass.vert"),Gdx.files.internal("shaders/scanlines.frag"));
shader.begin();
shader.setUniformf("radius", 5f);
shader.setUniformf("dirx", 5f);
shader.setUniformf("diry", 5f);
shader.end();
if(shader.isCompiled())
batch.setShader(shader);
else
Settings.log(shader.getLog());
}
The render method. I've not put anything concerning shaders here.
#Override
public void render(float delta) {
Settings.clearScreen(); //usual clear screen calls from here
batch.setProjectionMatrix(cam.combined);
cam.update();
detectClicks();
checkBallScreenEdges();
batch.begin();
draw(delta);
batch.end();
}
Thanks to Tenfour04 I got a nice scanlines shader to work (tested with another than the one above):
#Override
public void render(float delta) {
Settings.clearScreen();
batch.setProjectionMatrix(cam.combined);
cam.update();
batch.setShader(SpriteBatch.createDefaultShader());
main.buffer.begin();
batch.begin();
draw(delta);
batch.end();
main.buffer.end();
//POST PROCESSING
Texture bufferedTexture = main.buffer.getColorBufferTexture();
batch.setShader(main.shader);
batch.begin();
batch.draw(bufferedTexture, 0, 0, Settings.WIDTH, Settings.HEIGHT, 0, 0, Settings.WIDTH, Settings.HEIGHT, false, true); //need to flip texture
batch.end();
}
and setting up the shader:
buffer = new FrameBuffer(Pixmap.Format.RGBA8888,Settings.WIDTH,Settings.HEIGHT,false);
ShaderProgram.pedantic=false;
shader = new ShaderProgram(Gdx.files.internal("shaders/pass.vert"),Gdx.files.internal("shaders/scanlines.frag"));
shader.begin();
shader.setUniformf("uResolution",(float)Settings.WIDTH,(float)Settings.HEIGHT);
shader.end();
Wished the libgdx wiki had more examples.
Related
Introduction to the problem:
I'm working on a game engine using the LWJGL library following this tutorial. However, I'm trying to make it so that there is a real division between the main engine and the game itself. I've therefore complicated the project a whole lot and I think this is causing some problems as the ProjectionMatrix doesn't work as explained in the video.
What am I doing:
Creating the ProjectionMatrix:
In order to create a ProjectionMatrix I created the a method which creates it for me:
public static Matrix4f createProjectionMatrix(float aspectRatio, float fov, float nearPlane, float farPlane) {
float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = nearPlane - farPlane;
Matrix4f projectionMatrix = new Matrix4f();
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((farPlane + nearPlane) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * nearPlane * farPlane) / frustum_length);
projectionMatrix.m33 = 0;
return projectionMatrix;
}
I create the ProjectionMatrix with the following values:
aspectRatio = width/height = 640/480 = 1.33333
fov = 100
nearPlane = -0.5
farPlane = 100
This results in the following values for my ProjectionMatrix:
0.83909965 0.0 0.0 0.0
0.0 0.83909965 0.0 0.0
0.0 0.0 0.9990005 -0.9995003
0.0 0.0 -1.0 0.0
Using the ProjectionMatrix:
In order to use the ProjectionMatrix I created the following shaders:
vertex.vs:
#version 150
in vec3 position;
in vec2 textureCoordinates;
out vec2 passTextureCoordinates;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform int useProjectionMatrix;
void main(void){
if (useProjectionMatrix == 1) {
gl_Position = projectionMatrix * transformationMatrix * vec4(position,1.0);
} else {
gl_Position = transformationMatrix * vec4(position,1.0);
}
passTextureCoordinates = textureCoordinates;
}
fragment.fs:
#version 150
in vec2 passTextureCoordinates;
out vec4 out_Color;
uniform sampler2D textureSampler;
void main(void){
out_Color = texture(textureSampler,passTextureCoordinates);
}
Finally in order to render the entity I've created the following renderer class:
public class TexturedEntityRenderer extends AbstractEntityRenderer{
private float aspectRatio;
private float fov;
private float nearPlane;
private float farPlane;
public void prepare() {
GL11.glClearColor(0,0,0,1);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
}
public void render (AbstractEntity entity, AbstractShader shader) {
if(shader instanceof TexturedEntityShader) {
if(entity.getModel() instanceof TexturedModel) {
TexturedModel model = (TexturedModel)entity.getModel();
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
Matrix4f transformationMatrix = MatrixMaths.createTransformationMatrix(entity.getPosition(), entity.getRx(), entity.getRy(), entity.getRz(), entity.getScale());
((TexturedEntityShader)shader).loadTransformationMatrix(transformationMatrix);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, ((TexturedModel)entity.getModel()).getTexture().getTextureID());
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, model.getVaoID());
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
} else {
ExceptionThrower.throwException(new ModelInvalidException());
}
} else {
ExceptionThrower.throwException(new ShaderIncompatableException(shader.toString()));
}
}
public void setup(AbstractShader shader) {
nearPlane = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWNEARPLANE_KEY, OptionHandler.GRAPHIC_OPTION_ID));
farPlane = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWFARPLANE_KEY, OptionHandler.GRAPHIC_OPTION_ID));
aspectRatio = DisplayManager.getWidth() / DisplayManager.getHeight();
fov = Float.parseFloat(OptionHandler.getProperty(GraphicOptions.WINDOWFOV_KEY, OptionHandler.GRAPHIC_OPTION_ID));
((TexturedEntityShader)shader).loadProjectionMatrix(MatrixMaths.createProjectionMatrix(aspectRatio, fov, nearPlane, farPlane));
((TexturedEntityShader)shader).loadUseProjectionMatrix();
}
}
The Optionhandler.getProperty() function in the setup() returns the property for a given key(like fov or nearPlane value) from a text file. (I've checked that this works by printing all loaded options.) Also, the DisplayManager.getWidth() and DisplayManager.getHeight() functions, obviously, obtain the width and height for calculating the aspectRatio variable.
Updating the entity:
Last but not least, I'm updating the entity using a class called EntityModifier which looks like this:
public class EntityModifier {
private Vector3f dposition;
private float drx;
private float dry;
private float drz;
private float dscale;
public BasicEntityModifier(Vector3f dposition, float drx, float dry, float drz, float dscale) {
this.dposition = dposition;
this.drx = drx;
this.dry = dry;
this.drz = drx;
this.dscale = dscale;
}
public Vector3f getDposition() {
return dposition;
}
public float getDrx() {
return drx;
}
public float getDry() {
return dry;
}
public float getDrz() {
return drz;
}
public float getDscale() {
return dscale;
}
#Override
public String toString() {
return "BasicEntityModifier [dposition=" + dposition + ", drx=" + drx + ", dry=" + dry + ", drz=" + drz + ", dscale=" + dscale + "]";
}
}
Each entity I create has one of these classes and I cal call an update method which adds the values to the entity's transformation:
public void update() {
increasePosition(modifier.getDposition().getX(),modifier.getDposition().getY(),modifier.getDposition().getZ());
increaseRotation(modifier.getDrx(), modifier.getDry(), modifier.getDrz());
increaseScale(modifier.getDscale());
}
private void increasePosition(float dx, float dy, float dz) {
position.x += dx;
position.y += dy;
position.z += dz;
}
private void increaseRotation(float drx, float dry, float drz) {
rx += drx;
ry += dry;
rz += drz;
}
private void increaseScale(float dscale) {
scale += dscale;
}
The problem:
I'm able to change the position of the x and y values of the entity normally but whenever I change the z position, using an EntityModifier, the entity loads but then dissapears from the screen. It's loaded for about 60 frames before dissapearing and changing dz's value doesn't seem to affect the speed at which it dissapears in any way(It does, see EDIT 2). Also there the entity doesn't have the scale effect as shown in the tutorial here (same link but with timestamp).
Changing the dz value to 0 stops the dissapearing of the entity.
What is going on here? How can I fix this?
EDIT:
I've been pointed out in the comments that the nearPlane value should be positive so I changed it to 0.5 but I still get the same results. I also changed: float frustum_length = nearPlane - farPlane; to float frustum_length = farPlane - nearPlane; which was also suggested there (this also did not solve the problem).
EDIT 2:
After some more investigation I found a few intresting things:
1. Changing the speed at which the z value changes does affect how long it takes for the entity to dissapear. After finding this out I tried timing a few different dz(with dz being the change per frame of z) values and I got this:
`for dz = -0.002 -> frames before dissapear: 515 frames.`
`for dz = -0.001 -> frames before dissapear: 1024 frames.`
`for dz = 0.02 -> frames before dissapear: 63 frames.`
If we take into account reaction times (I made the program output the total ammount of rendered frames on closure and just closed it as fast as possible when the entity dissapeared) we can calculate the values for z at which the entity dissapears.
-0.002 * 515 ≈ -1
-0.001 * 1024 ≈ -1
0.02 * 63 ≈ 1
This probably has to do with the way the coordinate system works in OpenGL but it still doesn't explain why the entity isn't becoming smaller as it does in the tutorial mentioned above.
2. Removing the code which adds the ProjectionMatrix to the renderer class does not change the behavior. This means the error is elsewere.
New Problem:
I think there is no problem with the ProjectionMatrix (or at least not a problem that is causing this behavior) but the problem is with the entity's position surpassing 1 or -1 on the z axes. However this still doesn't explain why there is no "zoom effect". Therefor I don't think that restricting the z movement between -1 and 1 will solve this problem, infact, I think it will work against us as the entity should not be rendered anyway if it's totaly "zoomed" out or in.
What can cause this problem if it isn't the ProjectionManager?
EDIT 3:
Someone on reddit pointed out that the following classes might also be of intrest for solving the problem:
AbstractShader: contains basic shader functionality common for all shader classes.
TexturedEntityShader: used to render a texturedEntity (shown above)
DisplayManager: class which handles rendering.
EDIT 4:
After some more discussion on reddit about this problem we've come across a problem and were able to fix it: The value for useProjectionMatrix was not loaded because the shader was stopped when I tried to load it. Changing the loadUseProjectionMatrix() method to:
public void loadUseProjectionMatrix() {
super.start();
super.loadBoolean(useProjectionMatrixLocation, useProjectionMatrix);
System.out.println("loaded useProjectionMatrix: " + useProjectionMatrix + "\n\n");
super.stop();
}
seems to partially solve the problem as the projectionMatrix now can be used inside the shader (before it would not be used due to the fact that the useProjectionMatrix value would always be 0 as we did not load a value for it.).
However, this did not fix the entire problem as there is still an issue with the projectionMatrix I think. The entity does not want to render at all when using the projectionMatrix but it renders fine when not using it. I've tried hardcoding the values of the projectionMatrix by using the following shader:
#version 150
in vec3 position;
in vec2 textureCoordinates;
out vec2 passTextureCoordinates;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform int useProjectionMatrix;
mat4 testMat;
void main(void){
testMat[0] = vec4(0.83909965, 0, 0, 0);
testMat[1] = vec4(0, 0.83909965, 0, 0);
testMat[2] = vec4(0, 0, 0.9990005, -0.9995003);
testMat[3] = vec4(0, 0, -1, 0);
if (true) {
gl_Position = testMat * transformationMatrix * vec4(position,1.0);
} else {
gl_Position = transformationMatrix * vec4(position,1.0);
}
passTextureCoordinates = textureCoordinates;
}
However that does not seem to work. Are these values OK?
Fow who wants to see it here are the 2 posts I created on reddit about this problem: post 1, post 2.
I am trying to implement a color grading shader using LUT into processing as described here by Matt DesLauriers and here by Lev Zelensky but I get a strange result when I apply the shader with a standard lut :
image test|690x345
On the left you can see the result I get when applying the LUT shader vs the desired result on the right.
Here my implementation on processing :
PImage source;
PShader PP_LUT;
PGraphics buffer;
PGraphics lut;
PImage lutsrc;
void setup() {
size(512, 512), P2D);
source = loadImage("test.png");
lutsrc = loadImage("_LUT/lookup.png");
lut = createGraphics(lutsrc.width, lutsrc.height, P2D);
((PGraphicsOpenGL)lut).textureSampling(2);
lut.beginDraw();
lut.image(lutsrc, 0, 0);
lut.endDraw();
buffer = createGraphics(source.width, source.height, P3D);
PP_LUT = loadShader("PP_LUT.glsl");
PP_LUT.set("resolution", (float) buffer.width, (float) buffer.height);
PP_LUT.set("lut", lut);
}
void draw() {
buffer.beginDraw();
buffer.background(0);
buffer.shader(PP_LUT);
buffer.image(source, 0, 0);
buffer.endDraw();
image(buffer, 0, 0, width, height);
image(lut, 0, 0, width * 0.25, height * 0.25);
}
and the shader part :
#version 150
#ifdef GL_ES
#endif
uniform sampler2D texture;
uniform sampler2D lut;
in vec4 vertTexCoord;
out vec4 fragColor;
//https://github.com/mattdesl/glsl-lut
vec4 lookup(vec4 color_, sampler2D lut_){
color_ = clamp(color_, vec4(0), vec4(1));
//define blue
mediump float blue = color_.b * 63.0;
//define quad 1
mediump vec2 quaduv1;
quaduv1.y = floor(floor(blue) / 8.0); //devide blue by the number of col on the LUT
quaduv1.x = floor(blue) - (quaduv1.y * 8.0);
//define quad 2
mediump vec2 quaduv2;
quaduv2.y = floor(ceil(blue) / 8.0); //devide blue by the number of col on the LUT
quaduv2.x = ceil(blue) - (quaduv2.y * 8.0);
//define colorUV 1
highp vec2 coloruv1;
coloruv1.x = (quaduv1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color_.r);
coloruv1.y = (quaduv1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color_.g);
//define colorUV 2
highp vec2 coloruv2;
coloruv2.x = (quaduv2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color_.r);
coloruv2.y = (quaduv2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color_.g);
//PROCESSING NEED TO FLIP y uv
//coloruv1.y = 1.0 - coloruv1.y;
//coloruv2.y = 1.0 - coloruv2.y;
//define new color 1 & 2
lowp vec4 ncolor1 = texture2D(lut_, coloruv1);
lowp vec4 ncolor2 = texture2D(lut_, coloruv2);
//return looked up color
lowp vec4 lookedcolor = mix(ncolor1, ncolor2, fract(blue));
return vec4(lookedcolor.rgb, color_.w);
}
void main()
{
vec2 uv = vertTexCoord.xy;
vec4 color = texture2D(texture, uv);
vec4 lutColor = lookup(color, lut);
fragColor = lutColor;
}
As I understand it seems to be a problem on the texture filtering part so I tried to write my lut into an offscreen buffer and set the texture filtering mode as nearest as described on the wiki page of processing but the result is quite the same
I don't know what I am missing here. Can anyone has an idea on this ?
Thanks
I'm trying to implement depth testing for 2D isometric game. To get something working, I started off with this sample, but I cannot get it to work correctly.
I'm trying to draw 2 images in a specific order.
first.png
second.png
first.png is drawn first, and second.png is drawn on top. Using fragment shader, I compute that red color has lower depth than green color, hence green fragments should be discarded when drawn on top of red fragments. The end result is that when second.png is drawn directly on top of first.png, the resulting square colored only red.
At the end of render function, I get the pixels of depth buffer, and looping over them I check if the values have been changed from defaults ones. It seems that no matter what I do, the values in depth buffer never change.
The depth test itself is working, if I set green fragments to depth=1.0, red fragments to depth=0.0 and my depth function is GL_LESS, only red fragments are drawn, but the depth buffer is not changed.
The code is in Java, but OpenGL functions are the same.
private SpriteBatch mBatch;
private Texture mTexture1;
private Texture mTexture2;
#Override
public void create() {
mBatch = new SpriteBatch();
mBatch.setShader(new ShaderProgram(Gdx.files.internal("test.vsh"), Gdx.files.internal("test.fsh")));
mTexture1 = new Texture("first.png");
mTexture2 = new Texture("second.png");
Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl20.glDepthFunc(GL20.GL_LESS);
Gdx.gl20.glDepthMask(true);
}
#Override
public void render() {
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
mBatch.begin();
float scale = 4.0f;
float x = Gdx.graphics.getWidth() / 2;
float y = Gdx.graphics.getHeight() / 2;
mBatch.draw(mTexture1, x - mTexture1.getWidth() / 2 * scale, y - mTexture1.getHeight() / 2 * scale,
mTexture1.getWidth() * scale, mTexture1.getHeight() * scale);
mBatch.flush();
mBatch.draw(mTexture2, x - mTexture2.getWidth() / 2 * scale, y - mTexture2.getHeight() / 2 * scale,
mTexture2.getWidth() * scale, mTexture2.getHeight() * scale);
mBatch.end();
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
FloatBuffer buffer = BufferUtils.newFloatBuffer(width * height);
Gdx.gl20.glReadPixels(0, 0, width, height, GL20.GL_DEPTH_COMPONENT, GL20.GL_FLOAT,
buffer);
for (int i = 0; i < width * height; i++) {
float pixel = buffer.get(i);
if (pixel != 1.0f && pixel != 0.0f) {
// why is this never thrown??
// it means depth buffer wasn't changed.
throw new IllegalStateException("OMG IT WORKS!! " + pixel);
}
}
if (Gdx.gl20.glGetError()!=0) {
throw new Error("OPENGL ERROR: " + Gdx.gl20.glGetError());
}
}
Vertex shader
#ifdef GL_ES
precision mediump float;
#endif
attribute vec3 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoord;
void main()
{
gl_Position = u_projTrans * vec4(a_position, 1);
v_color = a_color * 2.0;
v_texCoord = a_texCoord0;
}
Fragment shader
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_texCoord;
void main()
{
vec4 texel = v_color * texture2D(u_texture, v_texCoord);
if (texel.r > texel.g)
{
gl_FragDepth = 0.0;
}
else
{
gl_FragDepth = 0.5;
}
gl_FragColor = texel;
}
Ok, I found the problem.
SpriteBatch.begin() does
glDepthMask(false)
Setting glDepthMask to false prevents OpenGL from writing to depth buffer.
The solution is to call glDepthMask(true) after SpriteBatch.begin()
I can't get my depth to render correctly. No errors are thrown, the glCheckFramebufferStatus says it is complete as well.
Below is the code, the screen always shows up white. The depth values are not 1, but very very close:
EDIT:
So I tried linearizing the depth inside of my depth fragment shader and then drawing that directly to the screen to make sure the values were correct. They are correct. However, even if I send that linearized depth to my full screen quad shader (the 2nd one below), the screen is still all white.
public void initFramebuffers() {
glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);
depthShader.initTexture(width, height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
public void initTexture(int width, int height, int format, int internalFormat) {
tex = glGenTextures();
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_FLOAT, (ByteBuffer)null);
}
Depth Shader:
#version 400
in vec3 pos;
in float radius;
uniform mat4 mView;
uniform mat4 projection;
uniform vec2 screenSize;
uniform vec3 lightPos;
out float depth;
float linearizeDepth(float depth) {
float n = 0.01;
float f = 100;
return (2.0 * n) / (f + n - depth * (f - n));
}
void main() {
//calculate normal
vec3 normal;
normal.xy = gl_PointCoord * 2.0 - 1.0;
float r2 = dot(normal.xy, normal.xy);
if (r2 > 1.0) {
discard;
}
normal.z = sqrt(1.0 - r2);
//calculate depth
vec4 pixelPos = vec4(pos + normal * radius, 1.0);
vec4 clipSpacePos = projection * pixelPos;
depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
depth = linearizeDepth(depth);
}
Shader that reads in the depth. The values in linearizeDepth are my near and far distances:
#version 400
in vec2 coord;
uniform sampler2D depthMap;
uniform vec2 screenSize;
uniform mat4 projection;
out vec4 color;
float linearizeDepth(float depth) {
float n = 0.01;
float f = 100;
return (2.0 * n) / (f + n - depth * (f - n));
}
void main() {
float curDepth = texture2D(depthMap, coord).x;
//float d = linearizeDepth(curDepth);
color = vec4(d, d, d, 1.0f);
}
Code for drawing everything:
//--------------------Particle Depth-----------------------
{
glUseProgram(depthShader.program);
glBindFramebuffer(GL_FRAMEBUFFER, depthShader.fbo);
depthShader.particleDepthVAO(points);
//Sets uniforms
RenderUtility.addMatrix(depthShader, mView, "mView");
RenderUtility.addMatrix(depthShader, projection, "projection");
RenderUtility.addVector2(depthShader, screenSize, "screenSize");
RenderUtility.addVector3(depthShader, lightPosition, "lightPos");
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(depthShader.vao);
glDrawArrays(GL_POINTS, 0, points.size());
}
//Draw full screen
{
glUseProgram(blurShader.program);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
blurShader.blurDepthVAO();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthShader.tex);
glUniform1i(blurShader.depthMap, 0);
//Sets uniforms
RenderUtility.addMatrix(blurShader, mView, "mView");
RenderUtility.addMatrix(blurShader, projection, "projection");
RenderUtility.addVector2(blurShader, screenSize, "screenSize");
//glEnable(GL_DEPTH_TEST);
glBindVertexArray(blurShader.vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glViewport(0, 0, width, height);
}
The problem ended up being that my vertex shader's out variable name didn't match the fragment shader's in variable name (doh). The code posted above is 100% correct in case anyone sees this in the future.
There are a few issues with the posted code.
Inconsistent use of render target
In the setup of the FBO, there is only a depth attachment, and no color attachment. The color draw buffer is also explicitly disabled:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthShader.tex, 0);
glDrawBuffer(GL_NONE);
However, the fragment shader writes a color output:
out float depth;
...
depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
depth = linearizeDepth(depth);
To write to the depth attachment of the framebuffer, you will have to set the value of the predefined gl_FragDepth variable. Just because the out variable is named depth does not mean that it's actually used as the depth output. If you want to use the color output, you'll have to create a regular texture, and attach it to GL_COLOR_ATTACHMENT0. Which would actually seem easier.
linearizeDepth() calculation
float linearizeDepth(float depth) {
float n = 0.01;
float f = 100;
return (2.0 * n) / (f + n - depth * (f - n));
}
depth = clipSpacePos.z / clipSpacePos.w * 0.5f + 0.5f;
depth = linearizeDepth(depth);
The way the clipSpacePos is processed, it looks like the arguments to linarizeDepth() will be between 0.0 and 1.0. The calculation inside the function for these extreme values is then:
0.0 --> (2.0 * n) / (f + n)
1.0 --> 1.0
This looks fine for 1.0, but questionable for 0.0. I believe it would actually be more correct to make the preparation step:
depth = clipSpacePos.z / clipSpacePos.w;
This will then pass arguments between -1.0 and 1.0 to the function, which then produces:
-1.0 --> n / f
1.0 --> 1.0
It would actually make even more sense to me to scale the whole thing to produce results between 0.0 and 1.0, but at least this version makes intuitive sense, producing the relative distance to the far plane.
Calculation more complex than necessary
The above looks unnecessarily convoluted to me. You're applying the projection matrix, take the depth from the result, and then effectively invert the depth calculation applied by the projection matrix.
It would seem a whole lot simpler to not apply the projection matrix in the first place, and simply take the original distance. You can still divide by the far distance if you want a relative distance. At least as long as you use a standard projection matrix, I believe the following is equivalent to the corrected calculation above:
vec4 pixelPos = vec4(pos + normal * radius, 1.0);
float f = 100.0; // far plane
depth = -pixelPos.z / f;
The minus sign comes in because the most commonly used eye coordinate system assumes that you're looking down the negative z-axis.
If you wanted results between 0.0 and 1.0, you could also change this to:
float n = 0.01; // near plane
float f = 100.0; // far plane
depth = (-pixelPos.z - n) / (f - n);
I wish to blur my background, with the following fragment shader:
varying vec4 vColor;
varying vec2 vTexCoord;
uniform vec2 screenSize;
uniform sampler2D u_texture;
uniform vec4 v_time;
const float RADIUS = 0.75;
const float SOFTNESS = 0.6;
const float blurSize = 1.0/1000.0;
void main() {
vec4 texColor = vec4(0.0); // texture2D(u_texture, vTexCoord)
texColor += texture2D(u_texture, vTexCoord - 4.0*blurSize) * 0.05;
texColor += texture2D(u_texture, vTexCoord - 3.0*blurSize) * 0.09;
texColor += texture2D(u_texture, vTexCoord - 2.0*blurSize) * 0.12;
texColor += texture2D(u_texture, vTexCoord - blurSize) * 0.15;
texColor += texture2D(u_texture, vTexCoord) * 0.16;
texColor += texture2D(u_texture, vTexCoord + blurSize) * 0.15;
texColor += texture2D(u_texture, vTexCoord + 2.0*blurSize) * 0.12;
texColor += texture2D(u_texture, vTexCoord + 3.0*blurSize) * 0.09;
texColor += texture2D(u_texture, vTexCoord + 4.0*blurSize) * 0.05;
vec4 timedColor = (vColor + v_time);
vec2 position = (gl_FragCoord.xy / screenSize.xy) - vec2(0.5);
float len = length(position);
float vignette = smoothstep(RADIUS, RADIUS-SOFTNESS, len);
texColor.rgb = mix(texColor.rgb, texColor.rgb * vignette, 0.5);
gl_FragColor = vec4(texColor.rgb * timedColor.rgb, texColor.a);
}
But the problem being is that the shader blurs all screen.. what should i write to make it focus on my background texture instead of all the screen?
Fragment shader applies to every pixel of triangle that you draw with that shader.
May be you apply shader to wrong triangles and problem is not shader.
That shader looks strange to me.
vTexCoord - blurSize
vTexCoord - is vec2
blurSize - is float
The code will look more correct if you write something
vTexCoord - vec2(blurSize, 0.0)
OK, I gonna answer my question.
I wanted my shader program to blur only the background texture instead of all the screen.
so I created two shader programs, one for the background and one for the rest.
when the program draws the background it switches to the background shader, and after that is switches to the default shader.
Simple is that.