From 169a4d638c6c1b6634ffcfd19c4fe3cb94cf27d5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 13 Aug 2014 15:09:36 +0300 Subject: Implement volume rendering support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New subclass of QCustom3DItem, QCustom3DVolume is provided. The documentation for the example will be done in a separate commit. Change-Id: Idb3fdb0654c6bec7606ca012b75852a5a8412397 Reviewed-by: Tomi Korpipää --- src/datavisualization/engine/shaders/default.frag | 1 + .../engine/shaders/texture3d.frag | 70 ++++++++++++ .../engine/shaders/texture3d.vert | 12 +++ .../engine/shaders/texture3dslice.frag | 119 +++++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 src/datavisualization/engine/shaders/texture3d.frag create mode 100644 src/datavisualization/engine/shaders/texture3d.vert create mode 100644 src/datavisualization/engine/shaders/texture3dslice.frag (limited to 'src/datavisualization/engine/shaders') diff --git a/src/datavisualization/engine/shaders/default.frag b/src/datavisualization/engine/shaders/default.frag index c03b1054..0276ed95 100644 --- a/src/datavisualization/engine/shaders/default.frag +++ b/src/datavisualization/engine/shaders/default.frag @@ -33,5 +33,6 @@ void main() { materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance + materialSpecularColor * lightStrength * pow(cosAlpha, 5) / distance; gl_FragColor.a = color_mdl.a; + gl_FragColor = clamp(gl_FragColor, 0.0, 1.0); } diff --git a/src/datavisualization/engine/shaders/texture3d.frag b/src/datavisualization/engine/shaders/texture3d.frag new file mode 100644 index 00000000..054b59cb --- /dev/null +++ b/src/datavisualization/engine/shaders/texture3d.frag @@ -0,0 +1,70 @@ +#version 120 + +varying highp vec3 pos; + +uniform highp sampler3D textureSampler; +uniform highp vec3 cameraPositionRelativeToModel; +uniform highp vec4 colorIndex[256]; +uniform highp int color8Bit; + +const float maxDist = sqrt(2.0); +const int sampleCount = 1024; +const float alphaThreshold = 0.001; +void main() { + // Raytrace into volume, need to sample pixels along the eye ray until we hit opacity 1 + + // Find out where ray intersects the object + highp vec3 rayDir = -(cameraPositionRelativeToModel - pos); + highp vec3 invRayDir = 1.0 / rayDir; + highp vec3 minCorner = vec3(-1.0); + highp vec3 maxCorner = vec3(1.0); + highp vec3 t1 = invRayDir * (minCorner - pos); + highp vec3 t2 = invRayDir * (maxCorner - pos); + highp vec3 tmin = min(t1, t2); + highp vec3 tmax = max(t1, t2); + highp vec2 t = max(tmin.xx, tmin.yz); + t = min(tmax.xx, tmax.yz); + float tFar = min(t.x, t.y); + highp vec3 rayStart = pos; + // Flip Y and Z so QImage bits work directly for texture and first image is in the front + rayStart.yz = -rayStart.yz; + highp vec3 rayStop = pos + rayDir * tFar; + rayStop.yz = -rayStop.yz; + + // Convert intersections to texture coords + rayStart = 0.5 * (rayStart + 1.0); + rayStop = 0.5 * (rayStop + 1.0); + + highp vec3 curPos = rayStart; + highp float fullDist = distance(rayStop, rayStart); + highp float stepSize = maxDist / float(sampleCount); // TODO: Stepsize needs to be improved + highp vec3 step = normalize(rayStop - rayStart) * stepSize; + highp float totalDist = 0.0; + highp float totalAlpha = 0.0; + highp vec4 destColor = vec4(0, 0, 0, 0); + highp vec4 curColor = vec4(0, 0, 0, 0); + highp vec3 curRgb = vec3(0, 0, 0); + highp float curAlpha = 0.0; + + for (int i = 0; i < sampleCount; i++) { + curColor = texture3D(textureSampler, curPos); + if (color8Bit != 0) + curColor = colorIndex[int(curColor.r * 255.0)]; + + curAlpha = curColor.a; + if (curAlpha > alphaThreshold) { + curRgb = curColor.rgb * curAlpha * (1.0 - totalAlpha); + destColor.rgb += curRgb; + totalAlpha += curAlpha; + } + curPos += step; + totalDist += stepSize; + if (totalDist > fullDist || totalAlpha >= 1.0) { + break; + } + } + + destColor.a = totalAlpha; + gl_FragColor = clamp(destColor, 0.0, 1.0); +} + diff --git a/src/datavisualization/engine/shaders/texture3d.vert b/src/datavisualization/engine/shaders/texture3d.vert new file mode 100644 index 00000000..cad1ce06 --- /dev/null +++ b/src/datavisualization/engine/shaders/texture3d.vert @@ -0,0 +1,12 @@ +uniform highp mat4 MVP; + +attribute highp vec3 vertexPosition_mdl; +attribute highp vec2 vertexUV; +attribute highp vec3 vertexNormal_mdl; + +varying highp vec3 pos; + +void main() { + gl_Position = MVP * vec4(vertexPosition_mdl, 1.0); + pos = vertexPosition_mdl; +} diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag new file mode 100644 index 00000000..641b32a5 --- /dev/null +++ b/src/datavisualization/engine/shaders/texture3dslice.frag @@ -0,0 +1,119 @@ +#version 120 + +varying highp vec3 pos; + +uniform highp sampler3D textureSampler; +uniform highp vec3 cameraPositionRelativeToModel; +uniform highp vec3 volumeSliceIndices; +uniform highp vec4 colorIndex[256]; +uniform highp int color8Bit; + +const highp vec3 xPlaneNormal = vec3(1.0, 0, 0); +const highp vec3 yPlaneNormal = vec3(0, 1.0, 0); +const highp vec3 zPlaneNormal = vec3(0, 0, 1.0); + +const float alphaThreshold = 0.001; +void main() { + // Raytrace into volume, need to sample pixels along the eye ray until we hit opacity 1 + + // Find out where ray intersects the slice planes + highp vec3 rayDir = -(cameraPositionRelativeToModel - pos); + highp vec3 rayStart = pos; + // Flip Y and Z so QImage bits work directly for texture and first image is in the front + rayStart.yz = -rayStart.yz; + rayDir.yz = -rayDir.yz; + highp vec3 invRayDir = 1.0 / rayDir; + highp vec3 minCorner = vec3(-1.0); + highp vec3 maxCorner = vec3(1.0); + highp vec3 t1 = invRayDir * (minCorner - rayStart); + highp vec3 t2 = invRayDir * (maxCorner - rayStart); + highp vec3 tmin = min(t1, t2); + highp vec3 tmax = max(t1, t2); + highp vec2 t = max(tmin.xx, tmin.yz); + t = min(tmax.xx, tmax.yz); + float tFar = min(t.x, t.y); + + highp vec3 xPoint = vec3(volumeSliceIndices.x, 0, 0); + highp vec3 yPoint = vec3(0, volumeSliceIndices.y, 0); + highp vec3 zPoint = vec3(0, 0, volumeSliceIndices.z); + highp float firstD = tFar + 1.0; + highp float secondD = firstD; + highp float thirdD = firstD; + if (volumeSliceIndices.x >= -1.0) { + highp float dx = dot(xPoint - rayStart, xPlaneNormal) / dot(rayDir, xPlaneNormal); + if (dx >= 0.0 && dx <= tFar) + firstD = min(dx, firstD); + } + if (volumeSliceIndices.y >= -1.0) { + highp float dy = dot(yPoint - rayStart, yPlaneNormal) / dot(rayDir, yPlaneNormal); + if (dy >= 0.0 && dy <= tFar) { + if (dy < firstD) { + secondD = firstD; + firstD = dy; + } else { + secondD = dy; + } + } + } + if (volumeSliceIndices.z >= -1.0) { + highp float dz = dot(zPoint - rayStart, zPlaneNormal) / dot(rayDir, zPlaneNormal); + if (dz >= 0.0) { + if (dz < firstD && dz <= tFar) { + thirdD = secondD; + secondD = firstD; + firstD = dz; + } else if (dz < secondD){ + thirdD = secondD; + secondD = dz; + } else { + thirdD = dz; + } + } + } + + highp vec4 destColor = vec4(0.0, 0.0, 0.0, 0.0); + highp float totalAlpha = 0.0; + highp vec3 curRgb = vec3(0, 0, 0); + + // Convert intersection to texture coords + + if (firstD <= tFar) { + highp vec3 firstTex = rayStart + rayDir * firstD; + firstTex = 0.5 * (firstTex + 1.0); + highp vec4 firstColor = texture3D(textureSampler, firstTex); + if (color8Bit != 0) + firstColor = colorIndex[int(firstColor.r * 255.0)]; + + if (firstColor.a > alphaThreshold) { + destColor.rgb = firstColor.rgb * firstColor.a; + totalAlpha = firstColor.a; + } + if (secondD <= tFar && totalAlpha < 1.0) { + highp vec3 secondTex = rayStart + rayDir * secondD; + secondTex = 0.5 * (secondTex + 1.0); + highp vec4 secondColor = texture3D(textureSampler, secondTex); + if (color8Bit != 0) + secondColor = colorIndex[int(secondColor.r * 255.0)]; + if (secondColor.a > alphaThreshold) { + curRgb = secondColor.rgb * secondColor.a * (1.0 - totalAlpha); + destColor.rgb += curRgb; + totalAlpha += secondColor.a; + } + if (thirdD <= tFar && totalAlpha < 1.0) { + highp vec3 thirdTex = rayStart + rayDir * thirdD; + thirdTex = 0.5 * (thirdTex + 1.0); + highp vec4 thirdColor = texture3D(textureSampler, thirdTex); + if (color8Bit != 0) + thirdColor = colorIndex[int(thirdColor.r * 255.0)]; + if (thirdColor.a > alphaThreshold) { + curRgb = thirdColor.rgb * thirdColor.a * (1.0 - totalAlpha); + destColor.rgb += curRgb; + totalAlpha += thirdColor.a; + } + } + } + } + destColor.a = totalAlpha; + gl_FragColor = clamp(destColor, 0.0, 1.0); +} + -- cgit v1.2.3