Skip to content

Commit 6ba0123

Browse files
committed
fix gradient calculation
1 parent 57b54ad commit 6ba0123

File tree

3 files changed

+115
-110
lines changed

3 files changed

+115
-110
lines changed

src/lib/data/tasks.json

Lines changed: 2 additions & 1 deletion
Large diffs are not rendered by default.

src/lib/data/tasks/VolumeRaymarching.md

Lines changed: 112 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -153,152 +153,157 @@ out vec4 fragColor;
153153
uniform vec3 cameraPosition;
154154
uniform vec3 cameraDirection;
155155
uniform 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;
159159
const int maxSteps = 1024;
160160
const vec3 lightDir = normalize(vec3(1.0, 1.0, 0.0));
161161
const 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
266262
void 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

src/lib/renderer/ShaderTaskMaterial.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,12 @@ export class ShaderTaskMaterial extends THREE.RawShaderMaterial {
3939
super({
4040
vertexShader: params.vertexShader,
4141
fragmentShader: params.fragmentShader,
42-
uniforms: {}, // This correctly initializes the *inherited* `this.uniforms`
42+
uniforms: {}, // This initializes the inherited `this.uniforms`
4343
glslVersion: THREE.GLSL3
4444
});
4545

4646
this.vertexShader = params.vertexShader;
4747
this.fragmentShader = params.fragmentShader;
48-
// `this.uniforms` is now correctly initialized to {} by the `super()` call.
4948
this.needsUpdate = true;
5049

5150
if (params.inputs) {

0 commit comments

Comments
 (0)