potree
Version:
WebGL point cloud viewer - WORK IN PROGRESS
847 lines (622 loc) • 19.6 kB
JavaScript
Potree.Shaders["pointcloud.vs"] = `
precision mediump float;
precision mediump int;
attribute vec3 position;
attribute vec3 color;
attribute vec3 normal;
attribute float intensity;
attribute float classification;
attribute float returnNumber;
attribute float numberOfReturns;
attribute float pointSourceID;
attribute vec4 indices;
//attribute float indices;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;
uniform float pcIndex;
//uniform mat4 toModel;
uniform float screenWidth;
uniform float screenHeight;
uniform float fov;
uniform float spacing;
uniform float near;
uniform float far;
uniform mat4 clipBoxes[max_clip_boxes];
uniform float heightMin;
uniform float heightMax;
uniform float size; // pixel size factor
uniform float minSize; // minimum pixel size
uniform float maxSize; // maximum pixel size
uniform float octreeSize;
uniform vec3 bbSize;
uniform vec3 uColor;
uniform float opacity;
uniform float clipBoxCount;
uniform float level;
uniform float vnStart;
uniform vec2 intensityRange;
uniform float intensityGamma;
uniform float intensityContrast;
uniform float intensityBrightness;
uniform float rgbGamma;
uniform float rgbContrast;
uniform float rgbBrightness;
uniform float transition;
uniform float wRGB;
uniform float wIntensity;
uniform float wElevation;
uniform float wClassification;
uniform float wReturnNumber;
uniform float wSourceID;
uniform sampler2D visibleNodes;
uniform sampler2D gradient;
uniform sampler2D classificationLUT;
uniform sampler2D depthMap;
varying float vOpacity;
varying vec3 vColor;
varying float vLinearDepth;
varying float vLogDepth;
varying vec3 vViewPosition;
varying float vRadius;
varying vec3 vWorldPosition;
varying vec3 vNormal;
// ---------------------
// OCTREE
// ---------------------
/**
* number of 1-bits up to inclusive index position
* number is treated as if it were an integer in the range 0-255
*
*/
float numberOfOnes(float number, float index){
float tmp = mod(number, pow(2.0, index + 1.0));
float numOnes = 0.0;
for(float i = 0.0; i < 8.0; i++){
if(mod(tmp, 2.0) != 0.0){
numOnes++;
}
tmp = floor(tmp / 2.0);
}
return numOnes;
}
/**
* checks whether the bit at index is 1
* number is treated as if it were an integer in the range 0-255
*
*/
bool isBitSet(float number, float index){
return mod(floor(number / pow(2.0, index)), 2.0) != 0.0;
}
/**
* find the LOD at the point position
*/
float getLOD(){
vec3 offset = vec3(0.0, 0.0, 0.0);
float iOffset = vnStart;
float depth = level;
for(float i = 0.0; i <= 30.0; i++){
float nodeSizeAtLevel = octreeSize / pow(2.0, i + level + 0.0);
vec3 index3d = (position-offset) / nodeSizeAtLevel;
index3d = floor(index3d + 0.5);
float index = 4.0 * index3d.x + 2.0 * index3d.y + index3d.z;
vec4 value = texture2D(visibleNodes, vec2(iOffset / 2048.0, 0.0));
float mask = value.r * 255.0;
if(isBitSet(mask, index)){
// there are more visible child nodes at this position
iOffset = iOffset + value.g * 255.0 * 256.0 + value.b * 255.0 + numberOfOnes(mask, index - 1.0);
depth++;
}else{
// no more visible child nodes at this position
return depth;
}
offset = offset + (vec3(1.0, 1.0, 1.0) * nodeSizeAtLevel * 0.5) * index3d;
}
return depth;
}
float getPointSizeAttenuation(){
return pow(1.9, getLOD());
}
// ---------------------
// KD-TREE
// ---------------------
float getLOD(){
vec3 offset = vec3(0.0, 0.0, 0.0);
float iOffset = 0.0;
float depth = 0.0;
vec3 size = bbSize;
vec3 pos = position;
for(float i = 0.0; i <= 1000.0; i++){
vec4 value = texture2D(visibleNodes, vec2(iOffset / 2048.0, 0.0));
int children = int(value.r * 255.0);
float next = value.g * 255.0;
int split = int(value.b * 255.0);
if(next == 0.0){
return depth;
}
vec3 splitv = vec3(0.0, 0.0, 0.0);
if(split == 1){
splitv.x = 1.0;
}else if(split == 2){
splitv.y = 1.0;
}else if(split == 4){
splitv.z = 1.0;
}
iOffset = iOffset + next;
float factor = length(pos * splitv / size);
if(factor < 0.5){
// left
if(children == 0 || children == 2){
return depth;
}
}else{
// right
pos = pos - size * splitv * 0.5;
if(children == 0 || children == 1){
return depth;
}
if(children == 3){
iOffset = iOffset + 1.0;
}
}
size = size * ((1.0 - (splitv + 1.0) / 2.0) + 0.5);
depth++;
}
return depth;
}
float getPointSizeAttenuation(){
return 0.5 * pow(1.3, getLOD());
}
// formula adapted from: http://www.dfstudios.co.uk/articles/programming/image-programming-algorithms/image-processing-algorithms-part-5-contrast-adjustment/
float getContrastFactor(float contrast){
return (1.0158730158730156 * (contrast + 1.0)) / (1.0158730158730156 - contrast);
}
vec3 getRGB(){
vec3 rgb = color;
rgb = pow(rgb, vec3(rgbGamma));
rgb = rgb + rgbBrightness;
rgb = (rgb - 0.5) * getContrastFactor(rgbContrast) + 0.5;
rgb = clamp(rgb, 0.0, 1.0);
//rgb = indices.rgb;
//rgb.b = pcIndex / 255.0;
return rgb;
}
float getIntensity(){
float w = (intensity - intensityRange.x) / (intensityRange.y - intensityRange.x);
w = pow(w, intensityGamma);
w = w + intensityBrightness;
w = (w - 0.5) * getContrastFactor(intensityContrast) + 0.5;
w = clamp(w, 0.0, 1.0);
return w;
}
vec3 getElevation(){
vec4 world = modelMatrix * vec4( position, 1.0 );
float w = (world.z - heightMin) / (heightMax-heightMin);
vec3 cElevation = texture2D(gradient, vec2(w,1.0-w)).rgb;
return cElevation;
}
vec4 getClassification(){
vec2 uv = vec2(classification / 255.0, 0.5);
vec4 classColor = texture2D(classificationLUT, uv);
return classColor;
}
vec3 getReturnNumber(){
if(numberOfReturns == 1.0){
return vec3(1.0, 1.0, 0.0);
}else{
if(returnNumber == 1.0){
return vec3(1.0, 0.0, 0.0);
}else if(returnNumber == numberOfReturns){
return vec3(0.0, 0.0, 1.0);
}else{
return vec3(0.0, 1.0, 0.0);
}
}
}
vec3 getSourceID(){
float w = mod(pointSourceID, 10.0) / 10.0;
return texture2D(gradient, vec2(w,1.0 - w)).rgb;
}
vec3 getCompositeColor(){
vec3 c;
float w;
c += wRGB * getRGB();
w += wRGB;
c += wIntensity * getIntensity() * vec3(1.0, 1.0, 1.0);
w += wIntensity;
c += wElevation * getElevation();
w += wElevation;
c += wReturnNumber * getReturnNumber();
w += wReturnNumber;
c += wSourceID * getSourceID();
w += wSourceID;
vec4 cl = wClassification * getClassification();
c += cl.a * cl.rgb;
w += wClassification * cl.a;
c = c / w;
if(w == 0.0){
//c = color;
gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
}
return c;
}
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vViewPosition = mvPosition.xyz;
gl_Position = projectionMatrix * mvPosition;
vOpacity = opacity;
vLinearDepth = gl_Position.w;
vLogDepth = log2(gl_Position.w);
vNormal = normalize(normalMatrix * normal);
// ---------------------
// POINT COLOR
// ---------------------
vec4 cl = getClassification();
vColor = getRGB();
vColor = getElevation();
vec3 cHeight = getElevation();
vColor = (1.0 - transition) * getRGB() + transition * cHeight;
float linearDepth = -mvPosition.z ;
float expDepth = (gl_Position.z / gl_Position.w) * 0.5 + 0.5;
vColor = vec3(linearDepth, expDepth, 0.0);
float w = getIntensity();
vColor = vec3(w, w, w);
float w = getIntensity();
vColor = texture2D(gradient, vec2(w,1.0-w)).rgb;
vColor = uColor;
float depth = getLOD();
float w = depth / 5.0;
vColor = texture2D(gradient, vec2(w,1.0-w)).rgb;
//vColor = indices.rgb * 255.0;
vColor = indices.rgb;
//vColor.r = mod(indices, 256.0) / 255.0;
//vColor.g = mod(indices / 256.0, 256.0) / 255.0;
//vColor.b = 0.0;
vColor = cl.rgb;
vColor = getReturnNumber();
vColor = getSourceID();
vColor = (modelMatrix * vec4(normal, 0.0)).xyz;
vColor = color;
vColor = getCompositeColor();
if(cl.a == 0.0){
gl_Position = vec4(100.0, 100.0, 100.0, 0.0);
return;
}
// ---------------------
// POINT SIZE
// ---------------------
float pointSize = 1.0;
float slope = tan(fov / 2.0);
float projFactor = -0.5 * screenHeight / (slope * vViewPosition.z);
float r = spacing * 1.5;
vRadius = r;
pointSize = size;
pointSize = size * projFactor;
float worldSpaceSize = size * r / getPointSizeAttenuation();
pointSize = worldSpaceSize * projFactor;
pointSize = max(minSize, pointSize);
pointSize = min(maxSize, pointSize);
vRadius = pointSize / projFactor;
gl_PointSize = pointSize;
//gl_Position = vec4(1000.0, 1000.0, 1000.0, 1.0);
// ---------------------
// CLIPPING
// ---------------------
bool insideAny = false;
for(int i = 0; i < max_clip_boxes; i++){
if(i == int(clipBoxCount)){
break;
}
vec4 clipPosition = clipBoxes[i] * modelMatrix * vec4( position, 1.0 );
bool inside = -0.5 <= clipPosition.x && clipPosition.x <= 0.5;
inside = inside && -0.5 <= clipPosition.y && clipPosition.y <= 0.5;
inside = inside && -0.5 <= clipPosition.z && clipPosition.z <= 0.5;
insideAny = insideAny || inside;
}
if(!insideAny){
gl_Position = vec4(1000.0, 1000.0, 1000.0, 1.0);
float c = (vColor.r + vColor.g + vColor.b) / 6.0;
}else{
vColor.r += 0.5;
//vec3 hsv = rgb2hsv(vColor);
//hsv.x = hsv.x - 0.3;
//hsv.z = hsv.z + 0.1;
//vColor = hsv2rgb(hsv);
}
//vColor = indices.rgb * 255.0;
}
`
Potree.Shaders["pointcloud.fs"] = `
precision mediump float;
precision mediump int;
uniform mat4 viewMatrix;
uniform vec3 cameraPosition;
uniform mat4 projectionMatrix;
uniform float opacity;
uniform float blendHardness;
uniform float blendDepthSupplement;
uniform float fov;
uniform float spacing;
uniform float near;
uniform float far;
uniform float pcIndex;
uniform float screenWidth;
uniform float screenHeight;
uniform sampler2D depthMap;
varying vec3 vColor;
varying float vOpacity;
varying float vLinearDepth;
varying float vLogDepth;
varying vec3 vViewPosition;
varying float vRadius;
varying vec3 vNormal;
float specularStrength = 1.0;
void main() {
vec3 color = vColor;
float depth = gl_FragCoord.z;
float u = 2.0 * gl_PointCoord.x - 1.0;
float v = 2.0 * gl_PointCoord.y - 1.0;
float cc = u*u + v*v;
if(cc > 1.0){
discard;
}
vec2 uv = gl_FragCoord.xy / vec2(screenWidth, screenHeight);
float sDepth = texture2D(depthMap, uv).r;
if(vLinearDepth > sDepth + vRadius + blendDepthSupplement){
discard;
}
gl_FragColor = vec4(color, pcIndex / 255.0);
gl_FragColor = vec4(color, vOpacity);
vec3 normal = normalize( vNormal );
normal.z = abs(normal.z);
vec3 viewPosition = normalize( vViewPosition );
// code taken from three.js phong light fragment shader
vec3 pointDiffuse = vec3( 0.0 );
vec3 pointSpecular = vec3( 0.0 );
for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {
vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );
vec3 lVector = lPosition.xyz + vViewPosition.xyz;
float lDistance = 1.0;
if ( pointLightDistance[ i ] > 0.0 )
lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );
lVector = normalize( lVector );
// diffuse
float dotProduct = dot( normal, lVector );
float pointDiffuseWeightFull = max( dotProduct, 0.0 );
float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );
vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );
float pointDiffuseWeight = max( dotProduct, 0.0 );
pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;
// specular
vec3 pointHalfVector = normalize( lVector + viewPosition );
float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );
float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );
float specularNormalization = ( shininess + 2.0 ) / 8.0;
vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );
pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;
pointSpecular = vec3(0.0, 0.0, 0.0);
}
vec3 dirDiffuse = vec3( 0.0 );
vec3 dirSpecular = vec3( 0.0 );
for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );
vec3 dirVector = normalize( lDirection.xyz );
// diffuse
float dotProduct = dot( normal, dirVector );
float dirDiffuseWeightFull = max( dotProduct, 0.0 );
float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );
vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );
float dirDiffuseWeight = max( dotProduct, 0.0 );
dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;
// specular
vec3 dirHalfVector = normalize( dirVector + viewPosition );
float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );
float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );
float specularNormalization = ( shininess + 2.0 ) / 8.0;
vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );
dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;
}
vec3 totalDiffuse = vec3( 0.0 );
vec3 totalSpecular = vec3( 0.0 );
totalDiffuse += pointDiffuse;
totalSpecular += pointSpecular;
totalDiffuse += dirDiffuse;
totalSpecular += dirSpecular;
gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;
//float w = pow(1.0 - (u*u + v*v), blendHardness);
float wx = 2.0 * length(2.0 * gl_PointCoord - 1.0);
float w = exp(-wx * wx * 0.5);
//float distance = length(2.0 * gl_PointCoord - 1.0);
//float w = exp( -(distance * distance) / blendHardness);
gl_FragColor.rgb = gl_FragColor.rgb * w;
gl_FragColor.a = w;
float wi = 0.0 - ( u*u + v*v);
vec4 pos = vec4(vViewPosition, 1.0);
pos.z += wi * vRadius;
float linearDepth = -pos.z;
pos = projectionMatrix * pos;
pos = pos / pos.w;
float expDepth = pos.z;
depth = (pos.z + 1.0) / 2.0;
gl_FragDepthEXT = depth;
color.r = linearDepth;
color.g = expDepth;
gl_FragColor.a = log2(linearDepth);
gl_FragColor.a = vLogDepth;
}
`
Potree.Shaders["normalize.vs"] = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}`
Potree.Shaders["normalize.fs"] = `
uniform sampler2D depthMap;
uniform sampler2D texture;
varying vec2 vUv;
void main() {
float depth = texture2D(depthMap, vUv).g;
if(depth <= 0.0){
discard;
}
vec4 color = texture2D(texture, vUv);
color = color / color.w;
gl_FragColor = vec4(color.xyz, 1.0);
gl_FragDepthEXT = depth;
}`
Potree.Shaders["edl.vs"] = `
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4(position,1.0);
gl_Position = projectionMatrix * mvPosition;
}`
Potree.Shaders["edl.fs"] = `//
// adapted from the EDL shader code from Christian Boucheny in cloud compare:
// https://github.com/cloudcompare/trunk/tree/master/plugins/qEDL/shaders/EDL
//
uniform float screenWidth;
uniform float screenHeight;
uniform vec2 neighbours[NEIGHBOUR_COUNT];
uniform float edlStrength;
uniform float radius;
uniform float opacity;
uniform sampler2D colorMap;
varying vec2 vUv;
float response(float depth){
vec2 uvRadius = radius / vec2(screenWidth, screenHeight);
float sum = 0.0;
for(int i = 0; i < NEIGHBOUR_COUNT; i++){
vec2 uvNeighbor = vUv + uvRadius * neighbours[i];
float neighbourDepth = texture2D(colorMap, uvNeighbor).a;
if(neighbourDepth != 0.0){
if(depth == 0.0){
sum += 100.0;
}else{
sum += max(0.0, depth - neighbourDepth);
}
}
}
return sum / float(NEIGHBOUR_COUNT);
}
void main(){
vec4 color = texture2D(colorMap, vUv);
float depth = color.a;
float res = response(depth);
float shade = exp(-res * 300.0 * edlStrength);
if(color.a == 0.0 && res == 0.0){
discard;
}else{
gl_FragColor = vec4(color.rgb * shade, opacity);
}
}
`
Potree.Shaders["blur.vs"] = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}`
Potree.Shaders["blur.fs"] = `
uniform mat4 projectionMatrix;
uniform float screenWidth;
uniform float screenHeight;
uniform float near;
uniform float far;
uniform sampler2D map;
varying vec2 vUv;
void main() {
float dx = 1.0 / screenWidth;
float dy = 1.0 / screenHeight;
vec3 color = vec3(0.0, 0.0, 0.0);
color += texture2D(map, vUv + vec2(-dx, -dy)).rgb;
color += texture2D(map, vUv + vec2( 0, -dy)).rgb;
color += texture2D(map, vUv + vec2(+dx, -dy)).rgb;
color += texture2D(map, vUv + vec2(-dx, 0)).rgb;
color += texture2D(map, vUv + vec2( 0, 0)).rgb;
color += texture2D(map, vUv + vec2(+dx, 0)).rgb;
color += texture2D(map, vUv + vec2(-dx, dy)).rgb;
color += texture2D(map, vUv + vec2( 0, dy)).rgb;
color += texture2D(map, vUv + vec2(+dx, dy)).rgb;
color = color / 9.0;
gl_FragColor = vec4(color, 1.0);
}`