Skip to content

Instantly share code, notes, and snippets.

@cnlohr
Created February 6, 2026 09:50
Show Gist options
  • Select an option

  • Save cnlohr/8d28a0768ad53eb81b1561c776d51b0a to your computer and use it in GitHub Desktop.

Select an option

Save cnlohr/8d28a0768ad53eb81b1561c776d51b0a to your computer and use it in GitHub Desktop.
Example geometry shader running in Unity on Quest.
Shader "Unlit/QuestGEO"
{
Properties
{
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
GLSLPROGRAM
#version 320 es
// See discussion here https://discussions.unity.com/t/geometry-shaders-in-opengl-multiview/911294
// It's not "perfect"
#ifdef STEREO_INSTANCING_ON
// Not used.
#extension GL_NV_viewport_array2 : enable
#extension GL_AMD_vertex_shader_layer : enable
#extension GL_ARB_fragment_layer_viewport : enable
#endif
// ON QUEST, STEREO_MULTIVIEW_ON is enabled.
#ifdef STEREO_MULTIVIEW_ON
#extension GL_EXT_multiview_tessellation_geometry_shader : enable
#extension GL_OVR_multiview2 : enable
#endif
#include "UnityCG.glslinc"
#include "UnityStereoSupport.glslinc"
#pragma vertex vert
#pragma fragment frag
#pragma geometry geo
#ifdef VERTEX
in vec2 in_TEXCOORD0;
in vec4 in_POSITION0;
out VS_OUT {
vec2 ouv;
float eye;
} vs_out;
uniform OVR_multiview
{
uint _ViewID;
uint numViews_2;
};
layout(std140) uniform UnityStereoEyeIndices {
vec4 unity_StereoEyeIndices[2];
};
void main ()
{
vs_out.ouv = in_TEXCOORD0;
vs_out.eye = 0.0;
//vs_out.eye = float(gl_ViewID);
//vs_out.eye = float(_ViewID); // Always 0.
//vs_out.eye = float(gl_InstanceID); // Always 0.
//vs_out.eye = float(unity_StereoEyeIndices[gl_ViewID_OVR].x); // Flashes back and forth, just as gl_ViewID_OVR is random.
//vs_out.eye = float(gl_ViewID_OVR&uint(1)); // view ID is kinda random.
//vs_out.eye = float(unity_StereoEyeIndex); // Always 0
gl_Position = in_POSITION0;
}
#endif
#ifdef GEOMETRY
layout(triangles) in;
layout(triangle_strip, max_vertices=6) out;
/*
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
};
*/
in VS_OUT {
vec2 ouv;
float eye;
} gs_in[];
out vec2 ouvf;
layout(num_views = 2) in;
// For now, each invocation outputs a triangle to each eye.
void main()
{
int eyeid = 0;
#if defined(STEREO_MULTIVIEW_ON) || defined(STEREO_INSTANCING_ON)
for( eyeid = 0; eyeid < 2; eyeid++ )
//eyeid = int(gs_in[0].eye); // If testing the input instance ID code, uncomment this, and comment out the above line.
#endif
{
#if defined(STEREO_MULTIVIEW_ON) || defined(STEREO_INSTANCING_ON)
mat4 stereoVP = unity_StereoMatrixVP[eyeid];
#else
mat4 stereoVP = unity_MatrixVP;
#endif
for(int i=0; i<3; i++)
{
gl_Position = stereoVP * unity_ObjectToWorld * gl_in[i].gl_Position;
vec2 o = vec2( gs_in[i].ouv );
gl_Layer = eyeid;
ouvf = o;
EmitVertex();
}
EndPrimitive();
}
}
#endif
#ifdef FRAGMENT
in vec2 ouvf;
layout (location = 0) out vec4 color;
void main()
{
color = vec4( mod((ouvf *10.0), 1.0), .1, 1.0 );
}
#endif
ENDGLSL
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment