@@ -153,152 +153,157 @@ out vec4 fragColor;
153153uniform vec3 cameraPosition;
154154uniform vec3 cameraDirection;
155155uniform sampler3D volumeTexture;
156- uniform ivec2 iResolution; // <-- aspect correction
156+ uniform ivec2 iResolution;
157157
158- const float stepSize = 0.005 ;
158+ const float stepSize = 0.0015 ;
159159const int maxSteps = 1024;
160160const vec3 lightDir = normalize(vec3(1.0, 1.0, 0.0));
161161const float orthoScale = 0.5;
162162
163- // Gradient computation
164- vec3 computeGradient(vec3 uvw) {
165- float h = 0.005;
166- float fx1 = texture(volumeTexture, clamp(uvw + vec3(h,0,0), 0.0, 1.0)).r;
167- float fx2 = texture(volumeTexture, clamp(uvw - vec3(h,0,0), 0.0, 1.0)).r;
168- float fy1 = texture(volumeTexture, clamp(uvw + vec3(0,h,0), 0.0, 1.0)).r;
169- float fy2 = texture(volumeTexture, clamp(uvw - vec3(0,h,0), 0.0, 1.0)).r;
170- float fz1 = texture(volumeTexture, clamp(uvw + vec3(0,0,h), 0.0, 1.0)).r;
171- float fz2 = texture(volumeTexture, clamp(uvw - vec3(0,0,h), 0.0, 1.0)).r;
172- return -vec3(fx1 - fx2, fy1 - fy2, fz1 - fz2);
163+ vec3 ComputeGradient(vec3 UVW) {
164+ vec3 H = 1.0 / vec3(textureSize(volumeTexture, 0)); // Texelgröße
165+
166+ float Fx1 = texture(volumeTexture, clamp(UVW + vec3(H.x, 0.0, 0.0), 0.0, 1.0)).r;
167+ float Fx2 = texture(volumeTexture, clamp(UVW - vec3(H.x, 0.0, 0.0), 0.0, 1.0)).r;
168+
169+ float Fy1 = texture(volumeTexture, clamp(UVW + vec3(0.0, H.y, 0.0), 0.0, 1.0)).r;
170+ float Fy2 = texture(volumeTexture, clamp(UVW - vec3(0.0, H.y, 0.0), 0.0, 1.0)).r;
171+
172+ float Fz1 = texture(volumeTexture, clamp(UVW + vec3(0.0, 0.0, H.z), 0.0, 1.0)).r;
173+ float Fz2 = texture(volumeTexture, clamp(UVW - vec3(0.0, 0.0, H.z), 0.0, 1.0)).r;
174+
175+ vec3 grad = vec3(
176+ (Fx1 - Fx2) / (2.0 * H.x),
177+ (Fy1 - Fy2) / (2.0 * H.y),
178+ (Fz1 - Fz2) / (2.0 * H.z)
179+ );
180+ return grad; // nthält auch die stärke über die Länge
173181}
174182
175- // Transfer function
176- vec4 transferFunction(float f, float gradMag) {
177- // Representative CT numbers (HU)
178- const float f_air = -750.0;
179- const float f_tissue = 50.0;
180- const float f_bone = 700.0;
181-
182- // Assigned alpha values (Opacity)
183- const float a_air = 0.0; // Transparent
184- const float a_tissue = 0.2; // Medium opacity
185- const float a_bone = 1.0; // Strong opacity
186-
187- // Assigned colors
188- const vec3 c_air = vec3(0.0); // Air
189- const vec3 c_tissue = vec3(0.9, 0.7, 0.6); // Skin-tone
190- const vec3 c_bone = vec3(1.0, 1.0, 0.95); // White/Ivory
191-
192- // initial
193- float alpha = 0.0;
194- vec3 color = c_air;
195-
196- if (f >= f_air && f <= f_tissue) {
197- // Between air and soft tissue
198- float t = (f - f_air) / (f_tissue - f_air);
199- alpha = mix(a_air, a_tissue, t);
200- color = mix(c_air, c_tissue, t);
201- } else if (f >= f_tissue && f <= f_bone) {
202- // Between tissue and bone
203- float t = (f - f_tissue) / (f_bone - f_tissue);
204- alpha = mix(a_tissue, a_bone, t);
205- color = mix(c_tissue, c_bone, t);
206- } else if (f > f_bone) {
207- // Denser than bone
208- alpha = a_bone;
209- color = c_bone;
183+ vec4 TransferFunction(float F, float gradientMagnitude)
184+ {
185+ const float huAir = -750.0;
186+ const float huTissue = 50.0;
187+ const float huBone = 700.0;
188+
189+ const float alphaAir = 0.0;
190+ const float alphaTissue = 0.02;
191+ const float alphaBone = 1.0;
192+
193+ const vec3 colorAir = vec3(0.0);
194+ const vec3 colorTissue = vec3(0.929, 0.675, 0.522);
195+ const vec3 colorBone = vec3(0.949, 0.898, 0.643);
196+
197+ float alpha;
198+ vec3 color;
199+ if (F <= huAir) {
200+ alpha = alphaAir;
201+ color = colorAir;
202+ }
203+ else if (F < huTissue) {
204+ float t = (F - huAir) / (huTissue - huAir);
205+ alpha = mix(alphaAir, alphaTissue, t);
206+ color = mix(colorAir, colorTissue, t);
207+ }
208+ else if (F < huBone) {
209+ float t = (F - huTissue) / (huBone - huTissue);
210+ alpha = mix(alphaTissue, alphaBone, t);
211+ color = mix(colorTissue, colorBone, t);
212+ }
213+ else {
214+ alpha = alphaBone;
215+ color = colorBone;
210216 }
211217
212- // Multiply opacity by gradient magnitude
213- // alpha = clamp(alpha * gradMag * 2 .0, 0.0, 1.0);
218+ // Gewichtung mit Gradient um die Kanten zwischen Oberflächen deutlich zu machen
219+ alpha *= 1.0 - exp(-5.0 * clamp(gradientMagnitude / 8 .0, 0.0, 1.0)); // 0 -> flat region, 1 -> sharp edge
214220
215221 return vec4(color, alpha);
216222}
217223
224+ vec3 PhongShade(vec3 N, vec3 BaseColor, vec3 ViewDir, vec3 lightDir) {
225+ const vec3 Ka = vec3(0.01); // Ambient
226+ const vec3 Kd = vec3(1.0); // Diffus
227+ const vec3 Ks = vec3(0.3); // Spekular
228+ const float NExp = 120.0; // Rauheit
218229
219- // Phong shading
220- vec3 phongShade(vec3 N, vec3 baseColor, vec3 viewDir, vec3 lightDir) {
221- const vec3 ka = vec3(0.5);
222- const vec3 kd = vec3(0.6);
223- const vec3 ks = vec3(0.3);
224- const float n = 20.0;
225-
226- vec3 H = normalize(viewDir + lightDir);
227- float diff = max(dot(N, lightDir), 0.0);
228- float spec = pow(max(dot(N, H), 0.0), n);
230+ vec3 H = normalize(ViewDir + lightDir); // Halfvector
231+ float Diff = max(dot(N, lightDir), 0.0); // Diffus
232+ float Spec = pow(max(dot(N, H), 0.0), NExp); // Spekular
229233
230- return baseColor * (ka + kd * diff ) + ks * spec ;
234+ return BaseColor * (Ka + Kd * Diff ) + Ks * Spec ;
231235}
232236
233- // Ray generation (aspect-corrected)
234- void generateRay(out vec3 rayOrigin, out vec3 rayDir) {
235- // compute aspect ratio from iResolution
236- float aspect = float(iResolution.x) / float(iResolution.y);
237-
238- // If vUv is already in -1..1, you may not want to remap; here we follow the existing use
239- // and simply scale the X component to correct for aspect.
240- vec2 uv = vUv;
241- uv.x *= aspect;
237+ void GenerateRay(out vec3 rayOrigin, out vec3 rayDir) {
238+ float Aspect = float(iResolution.x) / float(iResolution.y); // Seitenverhältnis aus Uniform
239+ vec2 UV = vUv;
240+ UV.x *= Aspect; // Korrigiert X-Skalierung
242241
242+ // Orthogonale Basis bilden
243243 vec3 forward = normalize(cameraDirection);
244- vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
245- vec3 up = cross(right, forward);
244+ vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
245+ vec3 up = cross(right, forward);
246246
247247 rayDir = forward;
248- // scale the right offset by the corrected uv.x
249- rayOrigin = cameraPosition + uv.x * right * orthoScale + uv.y * up * orthoScale;
248+ rayOrigin = cameraPosition + UV.x * right * orthoScale + UV.y * up * orthoScale; // Ortho Offset
250249}
251250
252- // Sample volume
253- vec4 sampleVolume(vec3 uvw, vec3 rayDir) {
254- float f = texture(volumeTexture, uvw).r - 1100.0; // texture is raised by 1100
255- vec3 grad = computeGradient(uvw);
256- float gradMag = length(grad);
251+ vec4 SampleVolume(vec3 UVW, vec3 rayDir) {
252+ float F = texture(volumeTexture, UVW).r - 1100.0; // HU-Korrektur weil Textur Werte um 1100 angehoben
253+ vec3 Grad = ComputeGradient(UVW); // Gradient berechnen für Phong Normale
254+ float gradientMagnitude = length(Grad);
257255
258- // Call transfer function to get material properties
259- vec4 material = transferFunction(f, gradMag);
260-
261- vec3 shaded = phongShade(normalize(grad), material.rgb, normalize(-rayDir), lightDir);
256+ vec4 Mat = TransferFunction(F, gradientMagnitude); // Materialdaten
257+ vec3 Shaded = PhongShade(normalize(-Grad), Mat.rgb, normalize(-rayDir), lightDir); // Beleuchtung
262258
263- return vec4(shaded, material .a);
259+ return vec4(Shaded, Mat .a); // Farbe + alpha
264260}
265261
266262void main() {
267263 vec3 rayOrigin, rayDir;
268- generateRay (rayOrigin, rayDir);
264+ GenerateRay (rayOrigin, rayDir); // Strahl erzeugen
269265
270- float tNear = 0.01 ; // Start slightly away from the camera
271- float tFar = 2.0; // March a distance guaranteed to pass through the volume
266+ float TNear = 0.001 ; // Start
267+ float TFar = 2.0; // Ende
272268
273- vec3 colorAccum = vec3(0.0);
274- float alphaAccum = 0.0;
269+ vec3 ColorAccum = vec3(0.0); // Farbspeicher
270+ float alphaAccum = 0.0; // alphaakkumulation
275271
276- // Calculate number of steps based on the assumed marching length
277- float rayLength = tFar - tNear;
278- int steps = min(int(rayLength / stepSize), maxSteps);
272+ float RayLength = TFar - TNear;
273+ int Steps = min(int(RayLength / stepSize), maxSteps); // Schrittanzahl
279274
280- // Ray marching loop
281- // Back-to-front compositing
282- for (int i = steps - 1; i >= 0; --i) {
283- float t = tNear + float(i) * stepSize;
284- vec3 p = rayOrigin + rayDir * t;
285- vec3 uvw = p + 0.5;
275+ for (int I = Steps - 1; I >= 0; --I) { // Rückwärtslauf wegen Back to Front
276+ float T = TNear + float(I) * stepSize; // Distanz auf dem Strahl
277+ vec3 P = rayOrigin + rayDir * T; // Punkt im Raum
278+ vec3 UVW = P + 0.5; // Sample In Texturraum
286279
287- // Bounding box check (to ensure we only sample the texture)
288- // This acts as an implicit boundary for the volume.
289- if (any(lessThan(uvw, vec3(0.0))) || any(greaterThan(uvw, vec3(1.0))))
280+ if (any(lessThan(UVW, vec3(0.0))) || any(greaterThan(UVW, vec3(1.0)))) // Bounds check
290281 continue;
291282
292- vec4 s = sampleVolume(uvw , rayDir);
293- float a = s .a;
294- vec3 c = s .rgb;
283+ vec4 S = SampleVolume(UVW , rayDir); // Volume Abtasten
284+ float A = S .a;
285+ vec3 C = S .rgb;
295286
296- // 'Over' operator
297- colorAccum = c * a + colorAccum * (1.0 - a);
298- alphaAccum = a + alphaAccum * (1.0 - a);
287+ ColorAccum = C * A + ColorAccum * (1.0 - A); // Over Operator
288+ alphaAccum = A + alphaAccum * (1.0 - A); // alpha add
299289 }
300290
301- fragColor = vec4(colorAccum, 1.0);
291+ fragColor = vec4(ColorAccum, 1.0);
292+ }
293+ ```
294+
295+ # Starter Vertex Shader
296+ ``` glsl
297+ precision highp float;
298+
299+ in vec3 position;
300+ in vec2 uv;
301+
302+ out vec2 vUv;
303+
304+ void main() {
305+ vUv = uv * 2.0 - 1.0;
306+ gl_Position = vec4(position, 1.0);
302307}
303308```
304309
0 commit comments