File: shader_synthesis.frag

package info (click to toggle)
meshlab 2022.02%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 47,348 kB
  • sloc: cpp: 536,635; ansic: 27,783; sh: 539; makefile: 36
file content (183 lines) | stat: -rw-r--r-- 5,150 bytes parent folder | download | duplicates (10)
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
28
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* Synthesis step */
#version 120

#extension GL_ARB_draw_buffers : enable

// canvas_height / canvas_width
uniform float canvas_ratio;

// 0.5* size of current level / size of one level up
uniform vec2 level_ratio;

// half the pixel size of current level
uniform vec2 half_pixel_size;

uniform int level;

uniform sampler2D textureA;
uniform sampler2D textureB;

uniform float reconstruction_filter_size;
uniform float prefilter_size;
uniform float minimum_size;

uniform bool depth_test;

// tests if a point is inside an ellipse.
// Ellipse is centered at origin and point displaced by d.
// Radius is the half the ellipse's major axis.
// Minor axis is computed by normal direction.
// @param d Difference vector from center of ellipse to point.
// @param radius Ellipse major axis length * 0.5.
// @param normal Normal vector.
float pointInEllipse(in vec2 d, in float radius, in vec3 normal){
 	float len = length(normal.xy);

	if (len == 0.0)
	normal.y = 0.0;
	else
	normal.y /= len;

	// angle between normal and z direction
	float angle = acos(normal.y);
	if (normal.x > 0.0)
	angle *= -1.0;

	// scale pixel distance according to screen dimensions
	d.x *= canvas_ratio;

  	// rotate point to ellipse coordinate system
	vec2 rotated_pos = vec2(d.x*cos(angle) + d.y*sin(angle),
						  -d.x*sin(angle) + d.y*cos(angle));
	// major and minor axis
	float a = 2.0*radius;

	//  float b = a*normal.z;
	float b = a * max(pow(normal.z, prefilter_size), minimum_size);

	// include antialiasing filter (increase both axis)
	/*   a += prefilter_size; */
	/*   b += prefilter_size; */

	// inside ellipse test
	float test = ((rotated_pos.x*rotated_pos.x)/(a*a)) + ((rotated_pos.y*rotated_pos.y)/(b*b));

	if (test <= reconstruction_filter_size)
	return test;
	else return -1.0;
}


void main (void) {

	// first buffer = (n.x, n.y, n.z, weight)
	vec4 bufferA = vec4(0.0, 0.0, 0.0, 0.0);
	// second buffer = (depth, dx, dy, radius)
	vec4 bufferB = vec4(0.0, 0.0, 0.0, 0.0);
	vec4 pixelA[4], pixelB[4];

	// retrieve pixel from analysis pyramid
	bufferA = texture2DLod (textureA, gl_TexCoord[0].st, level).xyzw;
	bufferB = texture2DLod (textureB, gl_TexCoord[0].st, level).xyzw;  

	// Occlusion test - if this pixel is far behind this position
	// one level up in the pyramid, it is synthesized since it is
	// occluded
	// (test the pixel z value with the depth range of the above pixel)
	bool occluded = false;

	if (depth_test) {
		if  (bufferA.w != 0.0) {
			vec4 up_pixelA = texture2DLod (textureA, gl_TexCoord[0].st, float(level+1)).xyzw;
			vec4 up_pixelB = texture2DLod (textureB, gl_TexCoord[0].st, float(level+1)).xyzw;

			if ( (up_pixelA.w != 0.0) && (bufferB.x > up_pixelB.x + up_pixelB.y) ) {
				occluded = true;
			}
		}
	}

  // unspecified pixel (weight == 0.0) or occluded pixel
  // synthesize pixel
  if ((bufferA.w == 0.0) || occluded)
	{		
	// first find coordinates for center of the four pixels in lower resolution level
	// the level_ratio already compensates for non power of two mipmapping with floor strategy
	vec2 center_coord = gl_TexCoord[0].st * level_ratio;

	vec2 tex_coord[4];
	//up-right
	tex_coord[0].st = center_coord + half_pixel_size.st;
	//up-left
	tex_coord[1].st = center_coord + vec2(-half_pixel_size.s, half_pixel_size.t);
	//down-right
	tex_coord[2].st = center_coord + vec2( half_pixel_size.s, -half_pixel_size.t);
	//down-left
	tex_coord[3].st = center_coord - half_pixel_size;

	vec2 dist_to_pixel;
	vec2 curr_coords = gl_TexCoord[0].st;
	float dist_test;
	float total_weight = 0.0;
	vec4 weights = vec4(0.0);
	for (int i = 0; i < 4; ++i) {
	  pixelA[i] = texture2DLod(textureA, tex_coord[i], float(level+1));

	  if (pixelA[i].w > 0.0) {
		pixelB[i] = texture2DLod(textureB, tex_coord[i], float(level+1));
	  
		dist_to_pixel = pixelB[i].zw - curr_coords;

		dist_test = pointInEllipse(dist_to_pixel, pixelA[i].w, pixelA[i].xyz);
		if (dist_test == -1)
		  pixelA[i].w = 0;
		else {
		  //		  weights[i] = 1.0 - dist_test;
		  weights[i] = exp(-0.5*dist_test);
		  total_weight += 1.0;
		}
	  }
	}

	// If the pixel was set as occluded but there is an ellipse
	// in range that does not occlude it, do not synthesize
	// Usually means that pixel is in a back surface near an internal silhouette
	if (occluded) {
	  for (int i = 0; i < 4; ++i)
		if ((bufferB.x <= pixelB[i].x + pixelB[i].y) && (weights[i] != 0.0))
		  occluded = false;
	}

	// If the pixel was set as occluded but there are no valid
	// pixels in range to synthesize, leave as it is
	if (occluded && (total_weight == 0.0))
	  occluded = false;


	if ((bufferA.w == 0.0) || occluded) 
	  {
	  bufferA = vec4(0.0);
	  bufferB = vec4(0.0);
	  total_weight = 0;
	  for (int i = 0; i < 4; ++i) {
		if (pixelA[i].w > 0.0)
		  {
			total_weight += weights[i];
			bufferA += pixelA[i] * weights[i];
			bufferB += pixelB[i] * weights[i];
		  }
	  }

	  if (total_weight > 0.0) {
		bufferA /= total_weight;
		bufferA.xyz = normalize(bufferA.xyz);
		bufferB /= total_weight;
	  }
	}
  }

  // first buffer = (n.x, n.y, n.z, radius)
  gl_FragData[0] = bufferA;
  // second buffer = (depth min, depth range, dx, dy)
  gl_FragData[1] = bufferB;
}