I am trying to figure out how to switch outputs in the geometry shader, specifically these two outputs:
layout(points, max_vertices = 1) out; // OUTPUT 1
layout(triangle_strip, max_vertices = 4) out; // OUTPUT 2
I am doing a rendering of starclusters and have a dataset of 100 000+ stars using sprites generated in the geometry shader. But, the sprite "halos" are to only appear if we move closer to the target star.
Geometry Shader
#version 440
const vec2 corners[4] = {
vec2(0.0, 1.0),
vec2(0.0, 0.0),
vec2(1.0, 1.0),
vec2(1.0, 0.0)
};
layout(points) in;
layout(points, max_vertices = 1) out;
//layout(triangle_strip, max_vertices = 4) out;
uniform vec4 campos;
float spriteSize = 0.000005; // set here for now.
out vec2 texCoord;
void main(){
float distToPoint = 1; //(1.f/((length(gl_in[0].gl_Position - campos)) ));
if(distToPoint == 1){ // dumb condition just to illustrate my point
// EMIT QUAD
for(int i=0; i<4; ++i){
vec4 pos = gl_in[0].gl_Position;
pos.xy += spriteSize *(corners[i] - vec2(0.5));
gl_Position = pos;
texCoord = corners[i];
EmitVertex();
}
EndPrimitive();
}else{
// EMIT POINT
gl_Position = gl_in[0].gl_Position;
EmitVertex();
EndPrimitive();
}
}
Fragment Shader
void main(void){
... // First I do a bunch of depth computation, irrelevant to this question
gl_FragDepth = depth;
// Here I want to switch between these two outputs!
//diffuse = texture2D(texture1, texCoord); // OUTPUT 1
diffuse = vec4(Color, 1.0); // OUTPUT 2
}
I have recently encountered streams for geometry shader but cant find a decent example of how this can be done in my instance.
Please let me know if more code needs to be posted.
Related
I am trying to implement geometry shader for line thickness using OpenGL 4.3.
I followed accepted answer and other given solutions of stackoverflow, but it is wrong according to the screenshot. Is there any proper way how can I get a normal of a screen? It seems correct in the first frame but the moment I move my mouse, the camera changes and offset direction is not correct. The shader is updated by camera matrix in while loop.
GLSL Geometry shader to replace glLineWidth
Vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 projection_view_model;
void main()
{
gl_Position = projection_view_model * vec4(aPos, 1.0);
}
Fragment shader
#version 330 core
//resources:
//https://stackoverflow.com/questions/6017176/gllinestipple-deprecated-in-opengl-3-1
out vec4 FragColor;
uniform vec4 uniform_fragment_color;
void main()
{
FragColor = uniform_fragment_color;
}
Geometry shader
#version 330 core
layout (lines) in;
layout(triangle_strip, max_vertices = 4) out;
uniform float u_thickness ;
uniform vec2 u_viewportSize ;
in gl_PerVertex
{
vec4 gl_Position;
//float gl_PointSize;
//float gl_ClipDistance[];
} gl_in[];
void main() {
//https://stackoverflow.com/questions/54686818/glsl-geometry-shader-to-replace-gllinewidth
vec4 p1 = gl_in[0].gl_Position;
vec4 p2 = gl_in[1].gl_Position;
vec2 dir = normalize((p2.xy - p1.xy) * u_viewportSize);
vec2 offset = vec2(-dir.y, dir.x) * u_thickness*100 / u_viewportSize;
gl_Position = p1 + vec4(offset.xy * p1.w, 0.0, 0.0);
EmitVertex();
gl_Position = p1 - vec4(offset.xy * p1.w, 0.0, 0.0);
EmitVertex();
gl_Position = p2 + vec4(offset.xy * p2.w, 0.0, 0.0);
EmitVertex();
gl_Position = p2 - vec4(offset.xy * p2.w, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
To get the direction of the line in normalized device space, the x and y components of the clip space coordinated must be divided by the w component (perspective divide):
vec2 dir = normalize((p2.xy - p1.xy) * u_viewportSize);
vec2 dir = normalize((p2.xy / p2.w - p1.xy / p1.w) * u_viewportSize);
I want to use geometry shader to draw triangles of mesh, but encounter a really odd issue.
Result As follow: The wrong output.
The Right output.
The only diff between wrong and right in code, is when converting 3d position vector to 4d position vector. The right one did in vertex shader. The wrong one did in geometry shader.
Code as follow. Why this happend?
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 project;
out vec3 normal_;
out vec4 pos_;
out vec3 pos_bug_;
out mat4 mvp_;
void main()
{
mvp_ = project * view * model;
normal_ = normal;
pos_ = vec4(pos, 1.0);
pos_bug_ = pos;
}
#version 330 core
layout (triangles) in;
layout (line_strip, max_vertices = 12) out;
uniform float length = 0.4f;
out vec4 color;
in mat4 mvp_[];
in vec3 normal_[];
in vec4 pos_[];
in vec3 pos_bug_[];
void GenNormal(int index) {
color = vec4(1, 1, 0, 1);
gl_Position = mvp_[0] * pos_[index];
EmitVertex();
gl_Position = mvp_[0] * pos_[index] + vec4(normal_[index], 0.0) * length;
EmitVertex();
EndPrimitive();
}
void GenTriangle(int index0, int index1) {
color = vec4(1, 1, 1, 1);
gl_Position = mvp_[0] * pos_[index0]; // Right
// gl_Position = mvp_[0] * vec4(pos_bug_[index0], 1.0); // Wrong
EmitVertex();
gl_Position = mvp_[0] * pos_[index1]; // Right
// gl_Position = mvp_[0] * vec4(pos_bug_[index1], 1.0); // Wrong
EmitVertex();
EndPrimitive();
}
void main()
{
GenNormal(0);
GenNormal(1);
GenNormal(2);
GenTriangle(0, 1);
GenTriangle(1, 2);
GenTriangle(0, 2);
}
The problem is that artifacts appear in the shadows at a great distance. I want to try to make a logarithmic depth buffer, but I don’t understand where it should be done and how ... I use point light method for omnidirectional shadow maps
Vertex shader:
#version 460 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform float zCoef;
//out vec4 pos;
void main() {
gl_Position = model * vec4(aPos, 1.0f);
// gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;
// gl_Position.z *= gl_Position.w;
}
Geometry shader:
#version 460 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 18) out;
uniform mat4 shadowMatrices[6];
uniform float zCoef;
out vec4 FragPos; // FragPos from GS (output per emitvertex)
void main()
{
for(int face = 0; face < 6; ++face)
{
gl_Layer = face; // встроенная переменная, указывающая на то, какую грань мы рендерим
for(int i = 0; i < 3; ++i) // для каждой вершины треугольника
{
FragPos = gl_in[i].gl_Position;
gl_Position = shadowMatrices[face] * FragPos;
// gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;
// gl_Position.z *= gl_Position.w;
EmitVertex();
}
EndPrimitive();
}
}
Fragment shader:
#version 460 core
in vec4 FragPos;
uniform vec3 lightPos;
uniform float farPlane;
uniform float zCoef;
void main() {
float lightDistance = length(FragPos.xyz - lightPos);
lightDistance = lightDistance / farPlane;
gl_FragDepth = lightDistance;
}
Guys, pls help me,i tried to use the linearization depth, it didn't work too..
I have been researching different techniques for rendering grass. I've decided to go with a Geometry shader generated grass mainly so I can generate triangle fans on the fly when I render them as GL_POINTS but I'm not seeing the performance I'd like to see. I'm getting maybe 20-50 fps with 100,000 blades of grass, and I have a decent GPU. I'm wondering if my approach is wrong, or if I'm reaching the limitations of my GPU or If I am doing something incorrectly or maybe if their is a faster way (My aim is individual blades where I can manipulate the vertices ideally). The texture I am using 256x256
My rendering steps are:
Creation of the VAO and VBO and storing locations and binding once:
float[] GrassLocations= new float[100000];
int vaoID = createVAO();
. //bind VBO to VAO
storeDataInAttributeList(0, 3, GrassLocations,0,0);
I then render:
GL30.glBindVertexArray(VAO);
GL20.glEnableVertexAttribArray(0);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glDrawArrays(GL11.GL_POINTS, 0, 100000);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
then My Vertex Shader:
#version 400
layout (location = 0) in vec3 VertexLocation;
uniform float time;
out vec3 offsets;
out vec3 Position;
out vec3 Normal;
out vec2 TexCoord;
out float visibility;
uniform mat4 transformationMatrix;
uniform mat4 viewMatrix;
uniform mat4 MVPmatrix;
uniform mat4 modelViewMatrix;
const float density = .007;
const float gradient = 1.5;
out float Time;
void main()
{
Time = time;
vec4 worldPosition = transformationMatrix * vec4(VertexLocation,1.0);
vec4 positionRelativeToCam = modelViewMatrix* vec4(VertexLocation,1.0);
Normal = vec3(0,1,0);
Position = vec3( worldPosition );
gl_Position = MVPmatrix* vec4(VertexLocation,1.0);
float distance = length(positionRelativeToCam.xyz);
visibility = exp(-pow((distance * density), gradient));
visibility = clamp(visibility,0.0,1.0);
offsets = offset;
}
I did gut the vertex shader and left only GL_POSITION and still not the issue.
My Geometry Shader:
#version 400
layout( points ) in;
layout( triangle_strip, max_vertices = 10 ) out;
float Size2=1; // Half the width of the quad
in vec3 Position[];
in vec3 Normal[];
in vec3 offsets[];
out vec3 position;
out vec3 normal;
in float Time[];
out vec2 TexCoord;
out vec3 color;
const float width = 5;
void main()
{
position = Position[0];
normal = Normal[0];
color = offsets[0];
gl_Position = (vec4(-Size2*width,-Size2,0.0,0.0) + gl_in[0].gl_Position);
TexCoord = vec2(0.0,0.0);
EmitVertex();
gl_Position = (vec4(Size2*width,-Size2,0.0,0.0) + gl_in[0].gl_Position);
TexCoord = vec2(1.0,0.0);
EmitVertex();
gl_Position = (vec4(-Size2*width+(Time[0].x),10,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(0.0,.25);
EmitVertex();
gl_Position = (vec4(Size2*width+(Time[0].x),10,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(1.0,.25);
EmitVertex();
///////////////////////////////////////////////////
gl_Position = (vec4(-Size2*width+(Time[0].x)*2,15,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(0.0,.50);
EmitVertex();
gl_Position = (vec4(Size2*width+(Time[0].x)*2,15,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(1.0,.50);
EmitVertex();
///////////////////////////////////////////////////
gl_Position = (vec4(-Size2*width+(Time[0].x)*3,25,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(0.0,.75);
EmitVertex();
gl_Position = (vec4(Size2*width+(Time[0].x)*3,25,0.0,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(1.0,.75);
EmitVertex();
///////////////////////////////////////////////////
gl_Position = (vec4(-Size2*width,Size2*7,Time[0].x,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(0.0,1.0);
EmitVertex();
gl_Position = (vec4(Size2*width,Size2*7,Time[0].x,0.0) +
gl_in[0].gl_Position);
TexCoord = vec2(1.0,1.0);
EmitVertex();
}
and my fragment Shader: (This is in a deferred engine, I've tried it with forward rendering also and I don't think performance hit is here)
#version 400
in vec2 TexCoord;
layout (binding=0) uniform sampler2D SpriteTex;
in vec3 color;
in vec3 normal;
in vec3 position;
layout( location = 0 ) out vec4 FragColor;
void main() {
vec4 texColor = texture(SpriteTex,TexCoord);
vec4 posColor = vec4(position.xyz,0);
gl_FragData[1] = posColor;
gl_FragData[2] = vec4(normal,1);
if(texColor.a<.5){
discard;
}
gl_FragData[0] = texColor;
}
What you want is a technique called Instancing. The tutorial I've linked is fantastic for figuring out how to do instancing.
I would probably advise that you avoid the geometry shader (since the geometry shader doesn't usually scale well when its purpose is to expand the quantity of vertices), and instead just define a buffer containing all the vertices necessary to draw a single blade (or patch) of grass, then use instancing to redraw that object thousands of times.
When I add my tesselation control shader to my rendering program, the viewport gets black. Without the TSC the vertex and fragment shader work fine. I also checked for compile errors but no occurs.
Vertex shader:
#version 410 core
layout (location = 0) in vec4 offset;
layout (location = 1) in vec4 color;
out VS_OUT {
vec4 color;
} vs_out;
void main(void) {
const vec4 vertices[3] = vec4[3]
(
vec4( 0.25, -0.25, 0.5, 1.0),
vec4(-0.25, -0.25, 0.5, 1.0),
vec4( 0.25, 0.25, 0.5, 1.0)
);
// Add "offset" to our hard-coded vertex position
gl_Position = vertices[gl_VertexID] + offset;
// Output the color from input attrib
vs_out.color = color;
}
Tessellation control shader:
#version 410 core
layout (vertices = 3) out;
void main(void) {
if (gl_InvocationID == 0) {
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
Tessellation evaluation shader:
#version 410 core
layout (triangles, equal_spacing, cw) in;
void main(void) {
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +
gl_TessCoord.y * gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position);
}
Fragment shader:
#version 410 core
in VS_OUT {
vec4 color;
} fs_in;
out vec4 color;
void main(void) {
color = fs_in.color;
}
I forgot to check for shader linking errors. And this is what I get:
WARNING: Output of vertex shader '<out VS_OUT.color>' not read by tessellation control shader
ERROR: Input of fragment shader '<in VS_OUT.color>' not written by tessellation evaluation shader
How can I fix this?
Without the code of the other shaders it's hard to help you.
Make sure your tessellation evaluation shader is correct too. A default one should look like this :
#version 410 core
layout(triangles, equal_spacing, ccw) in;
layout(packed) uniform MatrixBlock
{
mat4 projmat;
mat4 viewmat;
} matTransform;
void main ()
{
vec4 pos = gl_TessCoord.x * gl_in[0].gl_Position
+ gl_TessCoord.y * gl_in[1].gl_Position
+ gl_TessCoord.z * gl_in[2].gl_Position;
gl_Position = matTransform.projmat * matTransform.viewmat * pos;
}
The important part is the interpolation using the barycentric coordinates on the patch triangle. Also if the transformations are done in your vertex shader instead of the tess eval shader you may have strange results too.
Edit :
Now that you added tessellation stages you can't pass varying data from the vertex shader to the fragment shader. Indeed their are new triangles in the original patch triangle so you have to set the color for all these new triangles too. Actually when you use tessellation stages, the vertex shader and the tess control usually forward the vertices input to the tess eval shader.
So your tess control shader should be like :
#version 410 core
layout (vertices = 3) out;
in VS_OUT { vec4 color; } tcs_in[]; /* new */
out TCS_OUT { vec4 color; } tcs_out[]; /* new */
void main(void) {
if (gl_InvocationID == 0) {
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
tcs_out[gl_InvocationID].color = tcs_in[gl_InvocationID].color; /* forward the data */
}
And you tess eval shader must also interpolate the color :
#version 410 core
layout (triangles, equal_spacing, cw) in;
in TCS_OUT { vec4 color; } tes_in[]; /* new */
out TES_OUT { vec4 color; } tes_out; /* new */
void main(void) {
tes_out.color = (gl_TessCoord.x * tes_in[0].color + /* Interpolation */
gl_TessCoord.y * tes_in[1].color +
gl_TessCoord.z * tes_in[2].color );
gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +
gl_TessCoord.y * gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position);
}
And of course in your fragment shader you now have a TES_OUT instead of VS_OUT.
I know this question is two years old now, but I this might help people in the future who experience the same issue and find this question.
After many hours of trying I figured out the problem. It seems as though the gl_in[].gl_Position inputs of the Tessellation Control Shader are not written to by the vertex shader. I suspect this must be a driver bug (maybe in the NVidia drivers?) because I cannot think of any reason this shouldn't work.
Solution:
Instead of relying on the gl_in[].gl_Position inputs of the Tessellation Control Shader just pass them yourself in a custom output/input.
This can be done by (roughly )adding the following lines to the respective shader:
// vertex shader
// ...
out vec4 vVertexOut;
void main() {
// ...
vVertexOut = uMVPMatrix * inVertex; // output your transformed vertex
}
// tesselation control shader
// ...
in vec4 vVertexOut[];
out vec4 tVertexOut[];
void main() {
// ...
tVertexOut[gl_InvocationID] = vVertexOut[gl_InvocationID];
}
// tesselation evaluation shader
// ...
in vec4 tVertexOut[];
void main() {
// ...
gl_Position = (tVertexOut[0] * gl_TessCoord[0]) + (tVertexOut[1] * gl_TessCoord[1]) + (tVertexOut[2] * gl_TessCoord[2]);
}