- Home /
,Implementing a Geometry shader for a pointcloud
I am working on a project for college in Unity that involves displaying a very big pointcloud. I have implemented the point cloud as a mesh with 1 vertex per point and no triangles. I want to implement a shader in Unity that creates a triangle for each vertex and colors it of the color of the vertex.
I have no experience with shaders and I have developed the code trying to follow multiple resources online.
At the current state the code simply makes the pointcloud disappear and nothing is displayed.
Thank you!
Shader "Custom/SpherePoint" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Radius ("Sphere Radius", float) = 0.01
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
#pragma target 4.0 // Use shader model 3.0 target, to get nicer looking lighting
#include "UnityCG.cginc"
struct vertexIn {
float4 pos : POSITION;
float4 color : COLOR;
float3 normal : NORMAL;
};
struct vertexOut {
float4 pos : POSITION;
float4 color : COLOR0;
float3 normal : NORMAL;
};
struct geomOut {
float4 pos : POSITION;
float4 color : COLO0R;
float3 normal : NORMAL;
};
//Vertex shader: computes normal wrt camera
vertexOut vert (vertexIn i) {
vertexOut o;
o.pos = UnityObjectToClipPos(i.pos);
//o.pos = mul(unity_ObjectToWorld, i.pos);
o.color = i.color;
//o.normal = normalize(_WorldSpaceCameraPos - mul(unity_ObjectToWorld, o.pos).xyz); //normal is towards the camera
o.normal = ObjSpaceViewDir(o.pos);
return o;
}
float _Radius;
//Geometry shaders: Creates an equilateral triangle with the original vertex in the orthocenter
[maxvertexcount(3)]
void geom(point vertexOut i[1], inout TriangleStream<geomOut> OutputStream)
{
geomOut o, p;
float3 perp = float3(i[0].normal.y - i[0].normal.x, i[0].normal.x, i[0].normal.x) * _Radius;
o.color = i[0].color;
o.normal = i[0].normal;
o.pos = i[0].pos;
o.pos = float4(i[0].pos.x * _Radius, i[0].pos.yz, 1);
//o.pos = float4(normalize(perp + i[0].pos) * _Radius , 1); //Generic perpendicular to the normal
OutputStream.Append(o);
p.color = i[0].color;
p.normal = i[0].normal;
p.pos = float4(i[0].pos.x, i[0].pos.y * _Radius, i[0].pos.z, 1);
//p.pos = float4( (normalize(cross(i[0].pos.xyz, perp.xyz)) - perp.xyz / 2 + i[0].pos) * _Radius,1);
OutputStream.Append(p);
o.color = i[0].color;
o.normal = i[0].normal;
o.pos = float4(i[0].pos.x * _Radius, i[0].pos.yz, 1);
//p.pos = float4(-1 * (normalize(cross(i[0].pos.xyz, perp.xyz)) * _Radius) /* - perp.xyz / 2 + i[0].pos*/, 1);
OutputStream.Append(p);
OutputStream.RestartStrip();
}
float4 frag(geomOut i) : COLOR
{
return i.color;
}
ENDCG
}
}
FallBack "Diffuse"
}
,I am working on a project for college in Unity that involves displaying a very big pointcloud. I have implemented the point cloud as a mesh with 1 vertex per point and no triangles. I want to implement a shader in Unity that creates a triangle for each vertex and colors it of the color of the vertex.
I have no experience with shaders and I have developed the code trying to follow multiple resources online.
At the current state the code simply makes the pointcloud disappear and nothing is displayed.
Thank you!
Shader "Custom/SpherePoint" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Radius ("Sphere Radius", float) = 0.01
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
#pragma target 4.0 // Use shader model 3.0 target, to get nicer looking lighting
#include "UnityCG.cginc"
struct vertexIn {
float4 pos : POSITION;
float4 color : COLOR;
float3 normal : NORMAL;
};
struct vertexOut {
float4 pos : POSITION;
float4 color : COLOR0;
float3 normal : NORMAL;
};
struct geomOut {
float4 pos : POSITION;
float4 color : COLO0R;
float3 normal : NORMAL;
};
//Vertex shader: computes normal wrt camera
vertexOut vert (vertexIn i) {
vertexOut o;
o.pos = UnityObjectToClipPos(i.pos);
//o.pos = mul(unity_ObjectToWorld, i.pos);
o.color = i.color;
//o.normal = normalize(_WorldSpaceCameraPos - mul(unity_ObjectToWorld, o.pos).xyz); //normal is towards the camera
o.normal = ObjSpaceViewDir(o.pos);
return o;
}
float _Radius;
//Geometry shaders: Creates an equilateral triangle with the original vertex in the orthocenter
[maxvertexcount(3)]
void geom(point vertexOut i[1], inout TriangleStream<geomOut> OutputStream)
{
geomOut o, p;
float3 perp = float3(i[0].normal.y - i[0].normal.x, i[0].normal.x, i[0].normal.x) * _Radius;
o.color = i[0].color;
o.normal = i[0].normal;
o.pos = i[0].pos;
o.pos = float4(i[0].pos.x * _Radius, i[0].pos.yz, 1);
//o.pos = float4(normalize(perp + i[0].pos) * _Radius , 1); //Generic perpendicular to the normal
OutputStream.Append(o);
p.color = i[0].color;
p.normal = i[0].normal;
p.pos = float4(i[0].pos.x, i[0].pos.y * _Radius, i[0].pos.z, 1);
//p.pos = float4( (normalize(cross(i[0].pos.xyz, perp.xyz)) - perp.xyz / 2 + i[0].pos) * _Radius,1);
OutputStream.Append(p);
o.color = i[0].color;
o.normal = i[0].normal;
o.pos = float4(i[0].pos.x * _Radius, i[0].pos.yz, 1);
//p.pos = float4(-1 * (normalize(cross(i[0].pos.xyz, perp.xyz)) * _Radius) /* - perp.xyz / 2 + i[0].pos*/, 1);
OutputStream.Append(p);
OutputStream.RestartStrip();
}
float4 frag(geomOut i) : COLOR
{
return i.color;
}
ENDCG
}
}
FallBack "Diffuse"
}
Hi,
I'm also working on a real-time kinect point-cloud visualization for an academic project. I've tried both of the provided answers, but they don't render any point at all. Did you found a working point cloud shader? Would be very helpful! thanks!
Then you do something wrong. Are you sure that you are actually rendering points? The shader is supposed to receive a mesh that consists of points ($$anonymous$$eshTopology.Points).
I just re-assembled the shader the OP posted with my changes applied. I quickly created a script that creates a point mesh with 2000 random points (`Random.insideUnitSphere * 20;`). The radius is set to "1" in the material and this is the result:
:) Yeah might be doing something wrong. I'm completely new to shader coding. Thus I wanted to take a look on a working code. I tried your pastbin code. It also produces an invisible pointcloud rendering. Are there any other settings necessary?
I'm using the right meshtopology: _mesh.SetIndices(_indecies, $$anonymous$$eshTopology.Points, 0);
I'm using the $$anonymous$$esh component and Points co$$anonymous$$g from a $$anonymous$$inect v2. Which is working so far. Only the points rendered are very small. And I was searching for a shader that could fix this.
As mentioned, I'm new to shader languages. The Unity $$anonymous$$esh component has this vertices limit of max 65535 Is it possible that the triangle generation somehow exceeds this limit?
If I switch to the editor window an select the pointcloud. I can clearly see the outline of triangles in the selection. But they are not visible to me. pointcloud invisible but outline indicates triangles are generated
EDIT: I've found this project on github: https://github.com/keijiro/Pcx The disc shader is working fine. Still I would be happy to understand what I'm doing wrong with the shader above :)
Answer by Bunny83 · Dec 01, 2017 at 01:59 PM
Sorry but your geometry shader code doesn't seem to make much sense to me. Keep in mind that the incoming position is in clipspace (range -1 to 1, the center point of the screen is 0,0). You multiply some components the position by radius. Your first and thrid point is identical so the triangle you generate is a degenerated triangle as all 3 points lie on the same line.
You may want to work with worldspace coordinates instead and do the clipspace conversion inside the geometry shader. However from the question it's not clear what the desired output should be.
edit Well, try something like this instead:
static const fixed SQRT3_6 = sqrt(3)/6;
float _Radius;
float4 _Color;
[maxvertexcount(3)]
void geom(point vertexOut i[1], inout TriangleStream<geomOut> OutputStream)
{
geomOut p;
float a = _ScreenParams.x / _ScreenParams.y; // aspect ratio
float s = _Radius;
float s2 = s*SQRT3_6 *a;
p.color = i[0].color * _Color;
p.normal = float3(0,0,1);
p.pos = i[0].pos + float4(0,s2*2,0,0);
OutputStream.Append(p);
p.pos = i[0].pos + float4(-s*0.5f,-s2,0,0);
OutputStream.Append(p);
p.pos = i[0].pos + float4(s*0.5f,-s2,0,0);
OutputStream.Append(p);
OutputStream.RestartStrip();
}
The rest should stay the same.
Thank you
I am trying to create a triangle facing the camera for every input vertex, possibly centered on the vertex itself.
Answer by Buckslice · Dec 01, 2017 at 11:28 PM
Ya you dont need to use the normal to calculate the positions in the geometry shader because they are already in clipspace as Bunny83 pointed out. You could use the normal to do some more complex lighting in the fragment shader if youre interested in that though.
I made a similar geometry shader a while ago so I changed up your shader a bit and added in some comments based on how i did it. Mainly changed your geom function, also added in random rotations of each particle and code for transparency if you want that. Hope this helps!
Shader "Custom/SpherePoint" {
Properties {
_Radius ("Sphere Radius", float) = 1.0
}
SubShader {
LOD 200
Tags { "RenderType"="Opaque" }
//if you want transparency
//Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
//Blend SrcAlpha OneMinusSrcAlpha
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma geometry geom
#pragma target 4.0 // Use shader model 3.0 target, to get nicer looking lighting
#include "UnityCG.cginc"
struct vertexIn {
float4 pos : POSITION;
float4 color : COLOR;
};
struct vertexOut {
float4 pos : SV_POSITION;
float4 color : COLOR0;
float3 normal : NORMAL;
float r : TEXCOORD0; // not sure if this is good to do lol
};
struct geomOut {
float4 pos : POSITION;
float4 color : COLO0R;
float3 normal : NORMAL;
};
float rand(float3 p){
return frac(sin(dot(p.xyz, float3(12.9898, 78.233, 45.5432))) * 43758.5453);
}
float2x2 rotate2d(float a){
float s = sin(a);
float c = cos(a);
return float2x2(c,-s,s,c);
}
//Vertex shader: computes normal wrt camera
vertexOut vert (vertexIn i) {
vertexOut o;
o.pos = UnityObjectToClipPos(i.pos);
o.color = i.color;
o.normal = ObjSpaceViewDir(o.pos);
o.r = rand(i.pos);// calc random value based on object space pos
// from world space instead (particles will spin when mesh moves, kinda funny lol)
//o.r = rand(mul(unity_ObjectToWorld,i.pos));
return o;
}
float _Radius;
//Geometry shaders: Creates an equilateral triangle with the original vertex in the orthocenter
[maxvertexcount(3)]
void geom(point vertexOut IN[1], inout TriangleStream<geomOut> OutputStream)
{
float2 dim = float2(_Radius,_Radius);
float2 p[3]; // equilateral tri
p[0] = float2(-dim.x, dim.y * .57735026919);
p[1] = float2(0., -dim.y * 1.15470053838);
p[2] = float2(dim.x, dim.y * .57735026919);
float2x2 r = rotate2d(IN[0].r * 3.14159);
geomOut OUT;
OUT.color = IN[0].color;
OUT.normal = IN[0].normal;
for (int i = 0; i < 3; i++) {
p[i] = mul(r,p[i]); // apply rotation
p[i].x *= _ScreenParams.y / _ScreenParams.x; // make square
OUT.pos = IN[0].pos + float4(p[i],0,0) / 2.;
OutputStream.Append(OUT);
}
}
float4 frag(geomOut i) : COLOR
{
return i.color;
// could do some additional lighting calculation here based on normal
}
ENDCG
}
}
FallBack "Diffuse"
}
Your answer

Follow this Question
Related Questions
Geometry Shader not writing to depth texture 0 Answers
Getting triangle center in fragment shader 1 Answer
Geometry Shader showing wrong geometry 0 Answers
How to set an index buffer primitive restart value. 0 Answers
What is more efficent? Multiple passes or a single pass with iterative loop? 0 Answers