localambientocclusion.frag 5.63 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
// 
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
// 
// ================================================================================================

// (c) 2017 Jakob Weiss <jakob.weiss@tum.de>

#include "tools/transferfunction.frag"
Jakob Weiss's avatar
Jakob Weiss committed
28
#include "tools/texture3d.frag"
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

// The number of rays in each direction
#ifndef NUM_AO_RAYS
#define NUM_AO_RAYS 12
#endif

// The number of steps in each direction
#ifndef NUM_AO_RAY_STEPS
#define NUM_AO_RAY_STEPS 12
#endif

// The gamma factor that controls the visual strength of the AO term
#ifndef AO_GAMMA
#define AO_GAMMA 1.0
#endif

// factor to control the strength of emissive materials.
#ifndef AO_EMISSIVE_SCALE
#define AO_EMISSIVE_SCALE 5.0
#endif

// factor to control the transparency used when computing the AO effect
#ifndef AO_OPACITY_SCALE
#define AO_OPACITY_SCALE 1.0
#endif

const float AO_SAMPLING_BASE_INTERVAL_RCP = 200.0;

vec3 nthSphereSample(float R, int n, int N) {
    float golden_angle = 3.1415926535 * (3. - sqrt(5.));
    float theta = golden_angle * float(n);
    float t = float(n) / float(N - 1);
    float z = (1. - t) * (1 - 1.0 / float(N)) + t * (1.0 / float(N) - 1); // TODO use mix() here
    float radius = sqrt(1 - z * z);

    return R * vec3(radius * cos(theta), radius * sin(theta), z);
}


vec4 computeLAORay(vec3 pos, vec3 dir, float aoStepSize, sampler3D tex, sampler1D volumeTF, TFParameters1D volumeTFParams, sampler1D aoEmissiveTF, TFParameters1D aoEmissiveTFParams)
{
    vec3 aoStep = dir;
    vec3 aoRayPos = pos + aoStep; // offset
    vec4 aoColor = vec4(vec3(0), 1.0);

    for(int i=0; i < NUM_AO_RAY_STEPS; ++i) {
        // sample AO ray
        float aoIntensity = texture(tex, aoRayPos).r;
        vec4 aoSampleColor = lookupTF(volumeTF, volumeTFParams, aoIntensity);
        float aoSampleOpacity = aoSampleColor.a * AO_OPACITY_SCALE; // Volume tf sample is used for it's opacity value
        vec4 aoSampleEmissive = lookupTF(aoEmissiveTF, aoEmissiveTFParams, aoIntensity); // AO sample is used for the material's emissive color

        // compensate step size
        aoSampleOpacity = 1.0 - pow(1.0 - aoSampleOpacity, AO_GAMMA * aoStepSize * AO_SAMPLING_BASE_INTERVAL_RCP);
Jakob Weiss's avatar
Jakob Weiss committed
83
        aoSampleEmissive.rgb *= aoStepSize * AO_SAMPLING_BASE_INTERVAL_RCP  * aoSampleEmissive.a; // ao emissive color is multiplied by alpha for controlling the intensity
84

Jakob Weiss's avatar
Jakob Weiss committed
85
        // accumulate
86 87 88 89 90 91 92 93 94
        aoColor.rgb += (vec3(1) + AO_EMISSIVE_SCALE * aoSampleEmissive.rgb) * aoColor.a;
        aoColor.a *= (1 - aoSampleOpacity);

        aoRayPos += aoStep;
    }

    return aoColor;
}

Jakob Weiss's avatar
Jakob Weiss committed
95 96
void initLAODirs(inout vec4 aoRayDirs[NUM_AO_RAYS], float aoSphereRadius, TextureParameters3D volumeParameters)
{
97
    //Normalize for anisotropic voxel sizes
Jakob Weiss's avatar
Jakob Weiss committed
98
    vec3 anisotropicVoxel = volumeParameters._sizeRCP * volumeParameters._voxelSizeRCP;
99
    vec3 anisotropicRayStep = anisotropicVoxel / NUM_AO_RAY_STEPS;
Jakob Weiss's avatar
Jakob Weiss committed
100 101 102
    float voxelSize = length(volumeParameters._sizeRCP) / sqrt(3);
    float scale = aoSphereRadius * voxelSize / NUM_AO_RAY_STEPS;

103
    for(int i=0; i < NUM_AO_RAYS; ++i) {
Jakob Weiss's avatar
Jakob Weiss committed
104 105 106 107 108 109 110
        vec4 dir = vec4( nthSphereSample(1.0, i, NUM_AO_RAYS), 0.0);
        aoRayDirs[i].xyz = scale * normalize((volumeParameters._worldToTextureMatrixInvTransp * dir).xyz);

        //this is somehow slower to compute...
        //aoRayDirs[i].xyz = anisotropicRayStep * nthSphereSample(aoSphereRadius, i, NUM_AO_RAYS);

        aoRayDirs[i].w = length(aoRayDirs[i].xyz);
111 112 113 114 115 116 117 118 119 120 121 122
    }
}

vec3 computeLAO(vec3 position, in vec4 aoRayDirs[NUM_AO_RAYS], sampler3D tex, sampler1D volumeTF, TFParameters1D volumeTFParams, sampler1D aoEmissiveTF, TFParameters1D aoEmissiveTFParams, inout vec3 minOcclusionDir)
{
    minOcclusionDir = vec3(0);

    if(NUM_AO_RAYS*NUM_AO_RAY_STEPS > 0) {
        vec3 ambient = vec3(0);
        for(int i=0; i < NUM_AO_RAYS; ++i) {
            //vec3 dir = nthSphereSample(1.0, i, NUM_AO_RAYS);
            vec4 dir = aoRayDirs[i];
Jakob Weiss's avatar
Jakob Weiss committed
123
            vec4 aoRayColor = computeLAORay(position, dir.xyz, dir.w, tex, volumeTF, volumeTFParams, aoEmissiveTF, aoEmissiveTFParams);
124 125
            ambient += aoRayColor.rgb;

Jakob Weiss's avatar
Jakob Weiss committed
126
            minOcclusionDir += (1.- aoRayColor.a) * dir.xyz;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
        }

        minOcclusionDir = normalize(minOcclusionDir);
        // normalize against number of samples
        return ambient / (NUM_AO_RAYS * NUM_AO_RAY_STEPS);
   }
   else
        return vec3(1);
}

vec3 computeLAO(vec3 position, in vec4 aoRayDirs[NUM_AO_RAYS], sampler3D tex, sampler1D volumeTF, TFParameters1D volumeTFParams, sampler1D aoEmissiveTF, TFParameters1D aoEmissiveTFParams)
{
    vec3 minOcclusionDir;
    return computeLAO(position, aoRayDirs, tex, volumeTF, volumeTFParams, aoEmissiveTF, aoEmissiveTFParams, minOcclusionDir);
}