1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
27
#include "WGEShadingTools.glsl"
29
// commonly used variables
30
#include "WMSuperquadricGlyphs-varyings.glsl"
32
// tollerance value for float comparisons
33
float zeroTollerance = 0.01;
35
#define RenderMode_Superquadric
36
//#define RenderMode_Ellipsoid
38
/////////////////////////////////////////////////////////////////////////////////////////////
39
// GPU Super Quadrics -- fragment shader -- sPow
41
// This function extends the "pow" function with features to handle negative base values.
42
/////////////////////////////////////////////////////////////////////////////////////////////
43
float sPow( float x, float y )
51
return pow( abs( x ), y );
55
/////////////////////////////////////////////////////////////////////////////////////////////
56
// GPU Super Quadrics -- fragment shader -- superquadric
58
// This function calculates allmost every value at a given point (the value of the
59
// superquadric function, gradient and derivate)
62
// viewDir: viewing direction vector
63
// planePoint: point on projection plane
64
// t: current point on ray
65
// ray: returns position on ray
66
// gradient: the gradient vector at current ray point
67
// sqd: value of derived function at current ray point
70
// The function value of the superquadrics function at current point
71
/////////////////////////////////////////////////////////////////////////////////////////////
72
float superquadric( vec3 viewDir, vec3 planePoint, float t, out vec3 ray, out vec3 gradient, out float sqd )
74
ray = planePoint.xyz + t*viewDir.xyz;
76
// those values will be needed multiple times ...
77
float rayXYPow = sPow( ray.x, v_alphaBeta.x ) + sPow( ray.y, v_alphaBeta.x );
78
float rayZPow = sPow( ray.z, v_alphaBeta.y );
80
// the value at given position
81
float sq = sPow( rayXYPow, v_alphaBeta.z ) + rayZPow - 1.0;
83
// calculate squadric value for current t
85
// if we get a hit we need those values for calculating the gradient at the hit point
86
// if we do not get a hit we use those values for calculating the derivation at the current point
87
// for doing the next newton step
89
/////////////////// HINT ///////////////////
90
// If we derive sign(x)*pow(abs(x),y) we use product rule to get:
91
// sign' * pow + sign * pow'
92
// Well the derived sign function is nothing else than the unit impulse delta.
93
// It is delta<>0 iff x=0
94
// And also x=0 -> pow(x, y)=0
95
// so delta(x)*pow(x) will allways be 0 ... we can drop it
97
// ==> y * sign(x)* sPow(x, y-1.0);
100
float a = sign( rayXYPow ) * sPow( rayXYPow, v_alphaBeta.z - 1.0 );
101
float b1 = sign( ray.x ) * sPow( ray.x, v_alphaBeta.x - 1.0 );
103
float b2 = sign( ray.y ) * sPow( ray.y, v_alphaBeta.x - 1.0 );
104
float c = v_alphaBeta.y * sign( ray.z ) * sPow( ray.z, v_alphaBeta.y - 1.0 );
106
// now we can reuse some values to calculate the gradient vector at the hit point
107
gradient = vec3( v_alphaBeta.y * a * b1, v_alphaBeta.y * a * b2, c );
109
// calculate the derived function, reuse as much previously calculated values as possible
110
sqd = dot( gradient, viewDir );
112
// thats it, return value at current point
116
/////////////////////////////////////////////////////////////////////////////////////////////
117
// GPU Super Quadrics -- fragment shader -- superquadric
119
// This function is the "light" version of the above one. It just calculates the result of
120
// the superquadrics function.
123
// viewDir: viewing direction vector
124
// planePoint: point on projection plane
125
// t: current point on ray
128
// The function value of the superquadrics function at current point
129
/////////////////////////////////////////////////////////////////////////////////////////////
130
float superquadric( vec3 viewDir, vec3 planePoint, float t )
132
vec3 ray = planePoint.xyz + t*viewDir.xyz;
134
// those values will be needed multiple times ...
135
float rayXYPow = sPow( ray.x, v_alphaBeta.x ) + sPow( ray.y, v_alphaBeta.x );
136
float rayZPow = sPow( ray.z, v_alphaBeta.y );
138
// the value at given position
139
float sq = sPow( rayXYPow, v_alphaBeta.z ) + rayZPow - 1.0;
141
// thats it, return value at current point
145
/////////////////////////////////////////////////////////////////////////////////////////////
146
// GPU Super Quadrics -- fragment shader -- main
147
/////////////////////////////////////////////////////////////////////////////////////////////
150
// filter out glyphs whose anisotropy is smaller than the threshold or where the eigenvalues
151
// are below the threshold (alphaBeta.w is != if this is the case)
152
if( v_alphaBeta.w > 0.0 )
157
/////////////////////////////////////////////////////////////////////////////////////////////
158
// 1: try to find a goot start value for newton iteration
159
/////////////////////////////////////////////////////////////////////////////////////////////
161
// well the following value is quite empiric but it works well with squadrics whose beta<=alpha<=1.0
162
// HINT: if the ray hits the surface of the glyph lastT will allways be negative!
164
int numNewtonLoops = 10;
166
// this vector stores the gradient if there has been a hit
167
vec3 grad = vec3( 0.0, 0.0, 1.0 );
169
// some vars that will be needed later
172
vec3 hitPoint = vec3( 0.0, 0.0, 0.0 );
174
#ifdef RenderMode_Superquadric // Superquadric based rendermode
176
/////////////////////////////////////////////////////////////////////////////////////////////
177
// 2: newton iteration to determine roots of the superquadric-ray intersection
178
/////////////////////////////////////////////////////////////////////////////////////////////
180
// now try to calculate the intersection of the given ray with the superquadric.
181
// here we are using newtons iterative method for finding roots
183
// the iteration loop (NOTE: due to the fact that the shaders do not support an at compile time unknown loop count we set it to
184
// this quite empiric value (which works well (for at least the squadrics with beta<=alpha<=1.0))
185
for( int i = 0; i < numNewtonLoops; i++ )
187
// calculate all needed values
189
float sq = superquadric( v_viewDir.xyz, v_planePoint.xyz, lastT, hitPoint, grad, sqd );
192
float newT = lastT - ( sq / sqd );
195
// or has t not changed much since last iteration?
196
if( !hit && ( ( abs( sq ) <= zeroTollerance ) || ( abs( newT - lastT ) < zeroTollerance ) ) )
202
// if the ray parameter starts to jump around (it should get smaller step by step (because lastT is negative))
203
// NOTE: this speeds up rendering at rays that will miss the glyph (round about 50% faster!)
207
// not near enough -> another newton step
213
#ifdef RenderMode_Ellipsoid // Render ellipsoids
215
/////////////////////////////////////////////////////////////////////////////////////////////
216
// 2: solve ellipsoid equation to determine roots of the intersection
217
/////////////////////////////////////////////////////////////////////////////////////////////
219
float A = dot( v_viewDir.xyz, v_viewDir.xyz );
220
float B = 2.0 * dot( v_viewDir.xyz, v_planePoint.xyz );
221
float C = dot( v_planePoint.xyz, v_planePoint.xyz ) - 1.0;
223
// try to solve At^2 + Bt + C = 0
224
float discriminant = ( B * B ) - ( 4.0 * A * C );
227
if( discriminant <= 0.0 )
232
// there will be a solution
235
// use solution formula
236
float twoAinv = 1.0 / ( 2.0 * A );
237
float root = sqrt( discriminant );
238
float t1 = ( -B + root ) * twoAinv;
239
float t2 = ( -B - root ) * twoAinv;
241
lastT = min( t1, t2 );
247
// on a sphere surface the normal is allways the vector from the middle point (in our case (0,0,0))
248
// to the surface point
249
grad = -( v_planePoint.xyz + v_viewDir.xyz * lastT );
253
/////////////////////////////////////////////////////////////////////////////////////////////
254
// 3: draw or discard the pixel
255
/////////////////////////////////////////////////////////////////////////////////////////////
260
gl_FragColor = blinnPhongIllumination(
261
// material properties
262
gl_Color.rgb * 0.2, // ambient color
263
gl_Color.rgb * 2.0, // diffuse color
264
gl_Color.rgb, // specular color
267
// light color properties
268
gl_LightSource[0].diffuse.rgb, // light color
269
gl_LightSource[0].ambient.rgb, // ambient light
272
normalize( grad ), // normal
273
v_viewDir.xyz, // viewdir
274
v_lightDir.xyz ); // light direction
276
else // no hit: discard
278
// want to see the bounding box? uncomment this line
279
// gl_FragColor=vec4(0.5, 0.5, 1., 1.0);