Skip to content

Commit af13c73

Browse files
committed
Adding GLSL 1-pass volume renderer
1 parent 73f9960 commit af13c73

File tree

7 files changed

+918
-0
lines changed

7 files changed

+918
-0
lines changed

cppvolrend/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ add_executable(cppvolrend
3030

3131
# Null Bounding Box Grid
3232
volrendernull.cpp volrendernull.h
33+
34+
# GPU Image Order Ray Casting
35+
structured/rc1pass/rc1prenderer.cpp structured/rc1pass/rc1prenderer.h
3336

3437
${CMAKE_EXTERNAL_DIRECTORY}/imgui/imconfig.h ${CMAKE_EXTERNAL_DIRECTORY}/imgui/imgui_demo.cpp
3538
${CMAKE_EXTERNAL_DIRECTORY}/imgui/imgui.h ${CMAKE_EXTERNAL_DIRECTORY}/imgui/imgui.cpp

cppvolrend/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
2121
#include "volrendernull.h"
22+
// 1-pass - Ray Casting - GLSL
23+
#include "structured/rc1pass/rc1prenderer.h"
2224
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
2325

2426
#ifdef USING_FREEGLUT
@@ -47,6 +49,9 @@ int main (int argc, char **argv)
4749
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
4850
RenderingManager::Instance()->AddVolumeRenderer(new NullRenderer());
4951
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
52+
// 1-pass - Ray Casting - GLSL
53+
RenderingManager::Instance()->AddVolumeRenderer(new RayCasting1Pass());
54+
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
5055

5156
app.InitImGui();
5257
RenderingManager::Instance()->InitData();
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
#version 430
2+
3+
layout (binding = 1) uniform sampler3D TexVolume;
4+
layout (binding = 2) uniform sampler1D TexTransferFunc;
5+
layout (binding = 3) uniform sampler3D TexVolumeGradient;
6+
layout (binding = 4) uniform sampler3D TexVolumeLightCache;
7+
8+
uniform vec3 VolumeScaledSizes;
9+
10+
uniform vec3 CameraEye;
11+
12+
uniform mat4 ViewMatrix;
13+
uniform mat4 ProjectionMatrix;
14+
15+
uniform float fov_y_tangent;
16+
uniform float aspect_ratio;
17+
18+
uniform float StepSize;
19+
20+
uniform vec3 VolumeScales;
21+
22+
uniform int ApplyPhongShading;
23+
24+
uniform float Kambient;
25+
uniform float Kdiffuse;
26+
uniform float Kspecular;
27+
uniform float Nshininess;
28+
29+
uniform vec3 Ispecular;
30+
31+
uniform vec3 WorldEyePos;
32+
uniform vec3 WorldLightingPos;
33+
34+
uniform int ApplyOcclusion;
35+
uniform int ApplyShadow;
36+
37+
// size of each work group
38+
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
39+
layout (rgba16f, binding = 0) uniform image2D OutputFrag;
40+
41+
struct Ray {
42+
vec3 Origin;
43+
vec3 Dir;
44+
};
45+
46+
// Intersect ray with a box
47+
// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm
48+
bool IntersectBox (Ray r, vec3 boxmin, vec3 boxmax, out float tnear, out float tfar)
49+
{
50+
vec3 invR = vec3(1.0) / r.Dir;
51+
52+
vec3 tbbmin = invR * (boxmin - r.Origin);
53+
vec3 tbbmax = invR * (boxmax - r.Origin);
54+
55+
vec3 tmin = min(tbbmin, tbbmax);
56+
vec3 tmax = max(tbbmin, tbbmax);
57+
58+
tnear = max(max(tmin.x, tmin.y), tmin.z);
59+
tfar = min(min(tmax.x, tmax.y), tmax.z);
60+
61+
return tfar > tnear;
62+
}
63+
64+
bool RayAABBIntersection (vec3 vert_eye, vec3 vert_dir, out Ray r, out float rtnear, out float rtfar)
65+
{
66+
vec3 aabbmin = -VolumeScaledSizes * 0.5;
67+
vec3 aabbmax = VolumeScaledSizes * 0.5;
68+
69+
r.Origin = vert_eye;
70+
r.Dir = normalize(vert_dir);
71+
72+
float tnear, tfar;
73+
bool hit = IntersectBox(r, aabbmin, aabbmax, tnear, tfar);
74+
75+
tnear = max(tnear, 0.0);
76+
77+
rtnear = tnear;
78+
rtfar = tfar;
79+
80+
return hit;
81+
}
82+
83+
#if 0
84+
bool Shade = ApplyOcclusion == 1 || ApplyShadow == 1;
85+
vec4 ShadeSample (vec4 clr, vec3 tx_pos)
86+
{
87+
vec4 L = clr;
88+
float ka = 0.0, kd = 0.0, ks = 0.0;
89+
90+
if (Shade)
91+
{
92+
vec2 IaIs = texture(TexVolumeLightCache, tx_pos / VolumeScaledSizes).rg;
93+
94+
// Directional Cone Occlusion
95+
float IOcclusion = 0.0;
96+
if (ApplyOcclusion == 1)
97+
{
98+
ka = Kambient;
99+
IOcclusion = IaIs.r;
100+
}
101+
102+
// Directional Cone Shadow
103+
float IShadow = 0.0;
104+
if (ApplyShadow == 1)
105+
{
106+
kd = Kdiffuse;
107+
ks = Kspecular;
108+
IShadow = IaIs.g;
109+
}
110+
111+
if (ApplyPhongShading == 1)
112+
{
113+
vec3 Wpos = tx_pos - (VolumeScaledSizes * 0.5);
114+
vec3 gradient_normal = texture(TexVolumeGradient, tx_pos / VolumeScaledSizes).xyz;
115+
116+
if (gradient_normal != vec3(0, 0, 0))
117+
{
118+
gradient_normal = normalize(gradient_normal);
119+
120+
vec3 light_direction = normalize(WorldLightingPos - Wpos);
121+
vec3 eye_direction = normalize(CameraEye - Wpos);
122+
vec3 halfway_vector = normalize(eye_direction + light_direction);
123+
124+
float dot_diff = max(0, dot(gradient_normal, light_direction));
125+
float dot_spec = max(0, dot(halfway_vector, gradient_normal));
126+
127+
L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + IShadow * (L.rgb * kd * dot_diff))
128+
+ IShadow * (ks * Ispecular * pow(dot_spec, Nshininess));
129+
}
130+
}
131+
else
132+
{
133+
L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + L.rgb * IShadow * kd);
134+
}
135+
}
136+
137+
return L;
138+
}
139+
140+
void main ()
141+
{
142+
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
143+
144+
ivec2 size = imageSize(OutputFrag);
145+
if (storePos.x < size.x && storePos.y < size.y)
146+
{
147+
vec2 fpos = vec2(storePos) + 0.5;
148+
149+
// Transform from [0, 1] to [-1, 1]
150+
vec3 VerPos = (vec3(fpos.x / float(size.x), fpos.y / float(size.y), 0.0) * 2.0) - 1.0;
151+
// Camera direction
152+
vec3 camera_dir = vec3(VerPos.x * fov_y_tangent * aspect_ratio, VerPos.y * fov_y_tangent, -1.0) * mat3(ViewMatrix);
153+
camera_dir = normalize(camera_dir);
154+
155+
Ray r; float tnear, tfar;
156+
bool inbox = RayAABBIntersection(CameraEye, camera_dir, r, tnear, tfar);
157+
158+
if(inbox)
159+
{
160+
// Distance to be evaluated
161+
float D = abs(tfar - tnear);
162+
163+
// Initialize Transparency and Radiance color
164+
vec4 dst = vec4(0.0);
165+
166+
// World position at tnear, translating the volume to [0, VolumeAABB]
167+
vec3 wd_pos = r.Origin + r.Dir * tnear;
168+
wd_pos = wd_pos + (VolumeScaledSizes * 0.5);
169+
vec3 InvVolumeScaledSizes = 1.0 / VolumeScaledSizes;
170+
171+
// Evaluate from 0 to D...
172+
for (float s = 0.0; s < D;)
173+
{
174+
// Get the current step or the remaining interval
175+
float h = min(StepSize, D - s);
176+
177+
// Texture position at tnear + (s + h/2)
178+
vec3 tx_pos = wd_pos + r.Dir * (s + h * 0.5);
179+
180+
// Get normalized density from volume
181+
float density = texture(TexVolume, tx_pos * InvVolumeScaledSizes).r;
182+
183+
// Get color from transfer function given the normalized density
184+
vec4 src = texture(TexTransferFunc, density);
185+
186+
// Shade sample
187+
if (src.a > 0.0)
188+
{
189+
src = ShadeSample(src, tx_pos);
190+
191+
// Evaluate the current opacity
192+
src.a = 1.0 - exp(-src.a * h);
193+
194+
// Front-to-back composition
195+
src.rgb = src.rgb * src.a;
196+
dst = dst + (1.0 - dst.a) * src;
197+
198+
// early termination
199+
if (dst.a > 0.99) break;
200+
}
201+
202+
// Go to the next interval
203+
s = s + h;
204+
}
205+
imageStore(OutputFrag, storePos, dst);
206+
}
207+
}
208+
}
209+
210+
#else
211+
vec4 ShadeSample (vec4 clr, vec3 tx_pos)
212+
{
213+
vec4 L = clr;
214+
215+
vec2 IaIs = texture(TexVolumeLightCache, tx_pos / VolumeScaledSizes).rg;
216+
217+
float ka = 0.0, kd = 0.0, ks = 0.0;
218+
219+
// Directional Cone Occlusion
220+
float IOcclusion = 0.0;
221+
if (ApplyOcclusion == 1)
222+
{
223+
ka = Kambient;
224+
IOcclusion = IaIs.r;
225+
}
226+
227+
// Directional Cone Shadow
228+
float IShadow = 0.0;
229+
if (ApplyShadow == 1)
230+
{
231+
kd = Kdiffuse;
232+
ks = Kspecular;
233+
IShadow = IaIs.g;
234+
}
235+
236+
if (ApplyPhongShading == 1)
237+
{
238+
vec3 Wpos = tx_pos - (VolumeScaledSizes * 0.5);
239+
vec3 gradient_normal = texture(TexVolumeGradient, tx_pos / VolumeScaledSizes).xyz;
240+
241+
if (gradient_normal != vec3(0, 0, 0))
242+
{
243+
gradient_normal = normalize(gradient_normal);
244+
245+
vec3 light_direction = normalize(WorldLightingPos - Wpos);
246+
vec3 eye_direction = normalize(CameraEye - Wpos);
247+
vec3 halfway_vector = normalize(eye_direction + light_direction);
248+
249+
float dot_diff = max(0, dot(gradient_normal, light_direction));
250+
float dot_spec = max(0, dot(halfway_vector, gradient_normal));
251+
252+
L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + IShadow * (L.rgb * kd * dot_diff))
253+
+ IShadow * (ks * Ispecular * pow(dot_spec, Nshininess));
254+
}
255+
}
256+
else
257+
{
258+
L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + L.rgb * IShadow * kd);
259+
}
260+
261+
return L;
262+
}
263+
264+
void main ()
265+
{
266+
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
267+
268+
ivec2 size = imageSize(OutputFrag);
269+
if (storePos.x < size.x && storePos.y < size.y)
270+
{
271+
vec2 fpos = vec2(storePos) + 0.5;
272+
273+
// Transform from [0, 1] to [-1, 1]
274+
vec3 VerPos = (vec3(fpos.x / float(size.x), fpos.y / float(size.y), 0.0f) * 2.0f) - 1.0f;
275+
// Camera direction
276+
vec3 camera_dir = vec3(VerPos.x * fov_y_tangent * aspect_ratio, VerPos.y * fov_y_tangent, -1.0f) * mat3(ViewMatrix);
277+
camera_dir = normalize(camera_dir);
278+
279+
Ray r; float tnear, tfar;
280+
bool inbox = RayAABBIntersection(CameraEye, camera_dir, r, tnear, tfar);
281+
282+
if(inbox)
283+
{
284+
// Distance to be evaluated
285+
float D = abs(tfar - tnear);
286+
287+
// Initialize Transparency and Radiance color
288+
vec4 color = vec4(0.0f);
289+
290+
// World position at tnear, translating the volume to [0, VolumeAABB]
291+
vec3 wd_pos = r.Origin + r.Dir * tnear;
292+
wd_pos = wd_pos + (VolumeScaledSizes * 0.5f);
293+
vec3 InvVolumeScaledSizes = 1.0f / VolumeScaledSizes;
294+
bool Shade = ApplyOcclusion == 1 || ApplyShadow == 1;
295+
296+
// Evaluate from 0 to D...
297+
for (float s = 0.0f; s < D;)
298+
{
299+
// Get the current step or the remaining interval
300+
float h = min(StepSize, D - s);
301+
302+
// Texture position at tnear + (s + h/2)
303+
vec3 tx_pos = wd_pos + r.Dir * (s + h * 0.5f);
304+
305+
// Get normalized density from volume
306+
float density = texture(TexVolume, tx_pos * InvVolumeScaledSizes).r;
307+
308+
// Get color from transfer function given the normalized density
309+
vec4 src = texture(TexTransferFunc, density);
310+
311+
// Shade sample
312+
if (src.a > 0.0 && Shade)
313+
{
314+
src = ShadeSample(src, tx_pos);
315+
316+
// Evaluate the current opacity
317+
src.a = 1.0f - exp(-src.a * h);
318+
319+
// Front-to-back composition
320+
src.rgb = src.rgb * src.a;
321+
color = color + (1.0f - color.a) * src;
322+
323+
// Opacity threshold: a > 0.95
324+
if (color.a > 0.99f) break ;
325+
}
326+
327+
// Go to the next interval
328+
s = s + h;
329+
}
330+
imageStore(OutputFrag, storePos, color);
331+
}
332+
}
333+
}
334+
#endif

0 commit comments

Comments
 (0)