Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Geometry shader support #28237

Closed
wants to merge 1 commit into from
Closed

Conversation

Chaosus
Copy link
Member

@Chaosus Chaosus commented Apr 20, 2019

This PR is adding the geometry shader support. I decided to try to create it and (after several hours of moderate suffering) I get success ! Fix #10817

image

The geometry shader is optional stage between vertex and fragment and can be used to achieve complex effects which are almost impossible to replicate without it.

A basic GLSL shader which replicate the surface on which it applyed, has looking like this :

layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;

void main()
{	
  for(int i=0; i<gl_in.length(); i++)
  {
    gl_Position = gl_in[i].gl_Position;
    EmitVertex();
  }
  EndPrimitive();
}  

in the proposal geometry shader for similar code currently looking like this:

shader_type spatial;
render_mode geometry_in_triangles, geometry_out_triangles, geometry_max_vertices(3);

void geometry()
{
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = IN_VERTEX;
		EmitVertex();
	} 
	
	EndPrimitive();
}

Current Parts:

  • IN_VERTEX - internally this is array of vertexes in generated primitive. It's vec4 type.
  • INDEX - index of the primitive applied to IN_VERTEX and varyings, 0 by default
  • OUT_VERTEX - the output for the vertex(should be setted up before EmitVertex(). It's vec4 type.
  • OUT_NORMAL,OUT_BINORMAL,OUT_TANGENT,OUT_UV,OUT_UV2,OUT_COLOR - they are similar to their alternatives in Vertex shaders, use them before EmitVertex to setup your geometry.
  • EmitVertex(), EndPrimitive() - these GLSL functions are required to create and send primitives from the geometry shader.

New render mode flags

  • geometry_in_points
  • geometry_in_lines
  • geometry_in_triangles
  • geometry_out_points
  • geometry_out_lines
  • geometry_out_triangles

These flags contolling the type of the geometry, 'in' types should be used on geometry with this type, otherwise the output will be invisible, while 'out' can be used freely.

  • geometry_max_vertices

This mode is required to be defined before usage of geometry shader. The maximum value can be larger than actual invokation. The larger value can cause geometry shader crash due to increased amount of shader inputs.

This flag also belongs to new "range" render mode family. You need to specify an integer constant in quotes after it.

Notes

  • Currently travis / appveyor cannot accept this due to changed signature of the input function in the GLES3 shader headers. You should manually removes auto-generated shader headers from your drivers/gles3/shaders folder before compile.

  • Only spatial shader mode for now, no visual shader support (yet) of course..

  • If you merge this PR, you can run this demo -
    blast.zip

Current goals

  • Configurable max_vertices
  • CanvasItem shader support

Q/A

How to pass data from Vertex Shader to Geometry Shader ?

In order to simplify the internal code the embedded varyings such as COLOR or NORMAL are not defined, but you can define it yourself using varyings. Note that each varying is internally converted into array type for using with geometry shader, so you should configurate max_vertices(WIP) amount in render_mode if you dont want to reach a hardware limit.

For example to pass Color use code like this:

varying vec4 test;

void vertex()
{
	COLOR = vec4(1, 0, 0, 1);	
	test = COLOR;
}

void geometry()
{
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = IN_VERTEX;
		OUT_COLOR = test;
		EmitVertex();
	}
	
	EndPrimitive();
}

My initial geometry is dissappear !?

The geometry shader override the output vertexes of the Vertex shader, so you need to generate it again, to replace it with correct COLOR, UV, NORMAL etc.. For example you wanted to add geometry shader to the following shader code -

shader_type spatial;

void vertex()
{
	COLOR = vec4(1, 1, 1, 1);
}

void fragment()
{
	ALBEDO = COLOR.rgb;
}

To replicate the result - for example

image

you need to write similar code

shader_type spatial;

render_mode geometry_max_vertices(3);

varying vec4 color;
varying vec3 normal;

void vertex()
{
	COLOR = vec4(1, 1, 1, 1);
	color = COLOR;
	normal = NORMAL;
}

void geometry()
{
        // Duplicate initial geometry inputs

	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = IN_VERTEX;
		OUT_COLOR = color;
		OUT_NORMAL = normal;
		EmitVertex();
	}
	EndPrimitive();

        // Your code 
}

void fragment()
{
	ALBEDO = COLOR.rgb;
}

Screenshots

image

Lines generation can be used to visualize geometry normals

image

Points generation

image

@eon-s
Copy link
Contributor

eon-s commented Apr 20, 2019

Cool! But geometry shaders are only supported since GLES 3.2, right? This still would be nice to have on desktop targets only at least while we wait for the next renderer.

@Chaosus
Copy link
Member Author

Chaosus commented Apr 20, 2019

Cool! But geometry shaders are only supported since GLES 3.2, right? This still would be nice to have on desktop targets only at least while we wait for the next renderer.

Yeah, only for GLES3 and Vulkan

@fire
Copy link
Member

fire commented Apr 20, 2019

If it matters, compute shaders is opengles 3.2 too. https://github.com/guoyejun/gles32_compute_shader_basic

@BastiaanOlij
Copy link
Contributor

BastiaanOlij commented Apr 20, 2019 via email

@eon-s
Copy link
Contributor

eon-s commented Apr 21, 2019

BastiaanOlij https://open.gl/geometry sorry, this does not mention GL ES, it was somewhere else...

It could be disabled by default, to avoid problems, and lock the user to GLES3/Vulkan and/or limit exporting platforms in case they want to use it.

@BastiaanOlij
Copy link
Contributor

@eon-s yeah the problem is ES, I've looked at the wrong specs before thinking something was supported :)

Personally I feel geometry shaders are a much needed addition (as well as tesselation shaders) even if they won't be supported on anything but desktop machines. I think a warning somewhere would be enough to make sure users don't get into trouble.

@Chaosus , I haven't tried it out but having a read through your code changes now that I'm on a normal computer, looks pretty good.

@Chaosus Chaosus force-pushed the geometry_shader branch 2 times, most recently from 1135a39 to a9539b4 Compare April 21, 2019 15:29
@Chaosus Chaosus marked this pull request as ready for review April 21, 2019 15:56
@Chaosus Chaosus requested a review from reduz as a code owner April 21, 2019 15:56
@Chaosus Chaosus changed the title [WIP] Geometry shader support Geometry shader support Apr 21, 2019
@Chaosus Chaosus changed the title Geometry shader support [WIP] Geometry shader support Apr 21, 2019
@Chaosus Chaosus force-pushed the geometry_shader branch 4 times, most recently from e080e4a to 0248e35 Compare April 23, 2019 04:00
@Chaosus
Copy link
Member Author

Chaosus commented Apr 23, 2019

  • Added tpos method - this method transforms the coordinates to the camera space.

For example, if you write it using vector

void geometry()
{ 
	OUT_VERTEX = IN_VERTEX + vec4(0.1, 0, 0, 0);
	OUT_COLOR = vec4(1, 1, 0, 0);
	EmitVertex();
	
	OUT_VERTEX = IN_VERTEX + vec4(-0.1, 0, 0, 0);
	OUT_COLOR = vec4(1, 1, 0, 0);
	EmitVertex();
	
	OUT_VERTEX = IN_VERTEX + vec4(0.0, 1, 0, 0);
	OUT_COLOR = vec4(1, 0, 0, 0);
	EmitVertex();
	
	EndPrimitive();
}

the result can be undesired (unless you making a billboards):

image

if you rewrite it to this:

void geometry()
{ 
	OUT_VERTEX = IN_VERTEX + tpos(0.1, 0, 0);
	OUT_COLOR = vec4(1, 1, 0, 0);
	EmitVertex();
	
	OUT_VERTEX = IN_VERTEX + tpos(-0.1, 0, 0);
	OUT_COLOR = vec4(1, 1, 0, 0);
	EmitVertex();
	
	OUT_VERTEX = IN_VERTEX + tpos(0, 1, 0);
	OUT_COLOR = vec4(1, 0, 0, 0);
	EmitVertex();
	
	EndPrimitive();
}

The result will be a correct 3D representation

image

  • Added CanvasItem support

Now, you can apply geometry shader to your spirtes !

IN_VERTEX, INDEX, LENGTH, OUT_VERTEX - similar to Spatial geometry shader
Outputs : OUT_COLOR, OUT_UV

Example

image

shader_type canvas_item;

render_mode geometry_max_vertices(15);

varying vec4 color;
varying vec2 uv;

void vertex()
{
	color = COLOR;
	uv = UV;
}

void geometry()
{
	// center(original)
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = IN_VERTEX;
		OUT_UV = uv + vec2(0.0, 0);
		EmitVertex();
	}
	EndPrimitive();
	
	// left
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = (IN_VERTEX - tpos(vec2(100, 0)) + tpos(IN_VERTEX / 2.0));
		OUT_UV = uv;
		EmitVertex();
	}
	EndPrimitive();
	
	// right
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = (IN_VERTEX + tpos(vec2(100, 0)) + tpos(IN_VERTEX / 2.0));
		OUT_UV = uv;
		EmitVertex();
	}
	EndPrimitive();
	
	// up
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = (IN_VERTEX + tpos(vec2(0, 100)) + tpos(IN_VERTEX / 2.0));
		OUT_UV = uv;
		EmitVertex();
	}
	EndPrimitive();

	// down
	for(int i = 0; i < LENGTH; i++)
	{
		INDEX = i;
		OUT_VERTEX = (IN_VERTEX + tpos(vec2(0, -100)) + tpos(IN_VERTEX / 2.0));
		OUT_UV = uv;
		EmitVertex();
	}
	EndPrimitive();
}

void fragment()
{
	COLOR = texture(TEXTURE, UV.xy);
}

@Chaosus
Copy link
Member Author

Chaosus commented Apr 23, 2019

Ok, I think it's ready to review for @reduz. Yeah, I know that gles3 will be wiped out sooner or later, but the code from it can be transfered to Vulkan. This geometry shader proposal - is easy to understand, safer, lighter and extendable as much as possible(as much as I can) - I think it's good to merge for 3.2.

@Chaosus Chaosus changed the title [WIP] Geometry shader support Geometry shader support Apr 23, 2019
@Chaosus Chaosus added this to the 3.2 milestone Apr 23, 2019
@Chaosus Chaosus force-pushed the geometry_shader branch 4 times, most recently from 4405fed to 6c45c92 Compare April 23, 2019 09:32
@Chaosus Chaosus force-pushed the geometry_shader branch 2 times, most recently from 96ca539 to 82c4ddf Compare April 23, 2019 09:58
@reduz
Copy link
Member

reduz commented Apr 23, 2019

Sorry, the effort is enormously appreciated and admired, but going this way is the wrong decision for the project for the following reasons:

  • Geometry shaders are being deprecated in modern API versions. They are inefficient and can be better replaced with Compute.
  • Geometry shaders are not well supported in modern hardware. They remain there for compatibility but they are not very efficient.
  • Godot uses OpenGL ES 3.0, which does not support them, so they won't work on mobile.
  • There is not high demand for the feature.

For Godot 4.0, the plan is to create compute shaders that do a similar functions, but merging this for 3.x branch does not make much sense if it's going to be removed in 4.0 months later.

@reduz reduz closed this Apr 23, 2019
@Chaosus
Copy link
Member Author

Chaosus commented Apr 23, 2019

(I didnt knew that geometry shader become deprecated technology) No problem, at least it was an interesting journey to the depths of the Godot !

@panicq
Copy link

panicq commented Apr 1, 2020

Wow, that's sad :( @reduz Do you have any visibility on when compute shaders will be implemented in the 4.0 branch ? Thanks :)

@clayjohn
Copy link
Member

clayjohn commented Apr 1, 2020

@panicq please don't revive old PRs with unrelated questions.

But, to answer your question, compute shaders are already in 4.0, we make heavy use of them. But they have not been exposed to users yet in an easy to access fashion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Support for Geometry Shaders
8 participants