Просмотр исходного кода

add a webgl renderer for distance functions

usable via firefox's scratchpad, but should become a page with an inline
editor, some sliders and maybe even storage of the shaders via
localStorage.
Lucas Stadler лет назад: 10
Родитель
Сommit
008f49a584
1 измененных файлов с 253 добавлено и 0 удалено
  1. 253 0
      glsl/raymarching.js

+ 253 - 0
glsl/raymarching.js

@ -0,0 +1,253 @@
1
// # Resources
2
//
3
// - [Raw WebGL](http://nickdesaulniers.github.io/RawWebGL) ([video](https://www.youtube.com/watch?v=H4c8t6myAWU))
4
// - [WebGL Fundamentals](http://webglfundamentals.org/webgl/lessons/webgl-fundamentals.html)
5
6
try {
7
  function compileShader(gl, type, shaderSrc) {
8
    var shader = gl.createShader(type);
9
    gl.shaderSource(shader, shaderSrc);
10
    gl.compileShader(shader);
11
12
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
13
      throw new Error(gl.getShaderInfoLog(shader));
14
    }
15
16
    return shader;
17
  }
18
  
19
  function linkShaders(gl, vertexShader, fragmentShader) {
20
    var program = gl.createProgram();
21
    gl.attachShader(program, vertexShader);
22
    gl.attachShader(program, fragmentShader);
23
    gl.linkProgram(program);
24
    
25
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
26
      throw new Error(gl.getProgramInfoLog(program));
27
    }
28
    
29
    return program;
30
  }
31
  
32
  function initBuffer(gl, data, elemPerVertex, attribute) {
33
    var buffer = gl.createBuffer();
34
    if (!buffer) {
35
      throw new Error('failed to create buffer');
36
    }
37
    
38
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
39
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
40
    gl.vertexAttribPointer(attribute, elemPerVertex, gl.FLOAT, false, 0, 0);
41
    gl.enableVertexAttribArray(attribute);
42
  }
43
44
  var vertexShaderSrc = `
45
attribute vec4 aPosition;
46
attribute vec2 aSize;
47
varying vec3 pos;
48
49
void main() {
50
  gl_Position = aPosition;
51
  gl_PointSize = 10.0;
52
  pos = aPosition.xyz;
53
}
54
`
55
56
  var fragmentShaderSrc = `
57
precision highp float;
58
59
uniform vec2 uSize;
60
uniform vec3 iMouse;
61
varying vec3 pos;
62
63
const int MaximumRaySteps = 150;
64
const float MinimumDistance = 0.0000001;
65
66
float DistanceEstimator(vec3 pos);
67
68
float trace(vec3 from, vec3 direction) {
69
	float totalDistance = 0.0;
70
  int stepsDone = 0;
71
	for (int steps=0; steps < MaximumRaySteps; steps++) {
72
		vec3 p = from + totalDistance * direction;
73
		float distance = DistanceEstimator(p);
74
		totalDistance += distance;
75
    stepsDone = steps;
76
		if (distance < MinimumDistance) break;
77
	}
78
	return 1.0-float(stepsDone)/float(MaximumRaySteps);
79
}
80
81
float DistanceEstimator(vec3 pos) {
82
  return length(pos) - 1.0;
83
}
84
85
const float bailout = 4.0;
86
const int MaxIterations = 50;
87
const float power = 8.0;
88
const float phaseX = 0.0;
89
const float phaseY = 0.0;
90
91
/*float DistanceEstimator(vec3 z0) {
92
	vec3 c = z0;
93
	vec3 z = z0;
94
	float pd = power - 1.0; // power for derivative
95
	
96
	// Convert z to polar coordinates
97
	float r = length(z);
98
	float th = atan(z.y, z.x);
99
	float ph = asin(z.z / r);
100
	
101
	vec3 dz;
102
	float ph_dz = 0.0;
103
	float th_dz = 0.0;
104
	float r_dz	= 1.0;
105
	float powR, powRsin;
106
	
107
	// Iterate to compute the distance estimator.
108
	for (int n = 0; n < MaxIterations; n++) {
109
		// Calculate derivative of
110
		powR = power * pow(r, pd);
111
		powRsin = powR * r_dz * sin(ph_dz + pd*ph);
112
		dz.x = powRsin * cos(th_dz + pd*th) + 1.0;
113
		dz.y = powRsin * sin(th_dz + pd*th);
114
		dz.z = powR * r_dz * cos(ph_dz + pd*ph);
115
		
116
		// polar coordinates of derivative dz
117
		r_dz  = length(dz);
118
		th_dz = atan(dz.y, dz.x);
119
		ph_dz = acos(dz.z / r_dz);
120
		
121
		// z iteration
122
		powR = pow(r, power);
123
		powRsin = sin(power*ph);
124
		z.x = powR * powRsin * cos(power*th);
125
		z.y = powR * powRsin * sin(power*th);
126
		z.z = powR * cos(power*ph);
127
		z += c;
128
		
129
		r  = length(z);
130
		if (r > bailout) break;
131
		
132
		th = atan(z.y, z.x) + phaseX;
133
		ph = acos(z.z / r) + phaseY;
134
		
135
	}
136
	
137
	// Return the distance estimation value which determines the next raytracing
138
	// step size, or if whether we are within the threshold of the surface.
139
	return 0.5 * r * log(r)/r_dz;
140
}*/
141
142
mat3 setCamera( in vec3 ro, in vec3 ta, float cr ) {
143
	vec3 cw = normalize(ta-ro);
144
	vec3 cp = vec3(sin(cr), cos(cr),0.0);
145
	vec3 cu = normalize( cross(cw,cp) );
146
	vec3 cv = normalize( cross(cu,cw) );
147
  return mat3( cu, cv, cw );
148
}
149
150
void main() {
151
  vec2 q = gl_FragCoord.xy / uSize.xy;
152
  vec2 p = -1.0 + 2.0*q;
153
  p.x *= uSize.x / uSize.y;
154
  //vec2 iMouse = uSize / 2.0;
155
  vec2 mo = iMouse.xy/uSize.xy;
156
157
  float time = 15.0 + 0.0; // iGlobalTime
158
159
  // camera	
160
  vec3 ro = vec3(1.0, 2.0, -1.0); //vec3( -0.5+3.2*cos(0.1*time + 6.0*mo.x), 1.0 + 2.0*mo.y, 0.5 + 3.2*sin(0.1*time + 6.0*mo.x) );
161
  vec3 ta = vec3(0.0); //vec3( -0.5, -0.4, 0.5 );
162
163
  // camera-to-world transformation
164
  mat3 ca = setCamera( ro, ta, 0.0 );
165
166
  // ray direction
167
  vec3 rd = ca * normalize( vec3(p.xy, 2.5) );
168
169
  // render	
170
  float dist = trace(ro, rd);
171
  vec3 col = vec3(dist, dist, dist);
172
173
  col = mix(vec3(1.0, 0.0, 0.0), col, 0.9);
174
  //col = pow( col, vec3(0.4545));
175
176
  gl_FragColor = vec4( col, 1.0 );
177
}
178
`
179
  
180
  document.body.style = "margin: 0; overflow: hidden;";
181
  document.body.innerHTML = "";
182
183
  var canvas = document.createElement("canvas");
184
  var w = canvas.width = window.innerWidth;
185
  var h = canvas.height = window.innerHeight;
186
  document.body.appendChild(canvas);
187
188
  var gl = canvas.getContext("webgl");
189
  if (!gl) { alert("i think your browser does not support webgl"); }
190
191
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
192
  gl.clear(gl.COLOR_BUFFER_BIT);
193
  
194
  var vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSrc);
195
  var fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSrc);
196
  
197
  var program = linkShaders(gl, vertexShader, fragmentShader);
198
  gl.useProgram(program);
199
  
200
  var aPosition = gl.getAttribLocation(program, 'aPosition');
201
  var uSize = gl.getUniformLocation(program, 'uSize');
202
  var iMouse = gl.getUniformLocation(program, 'iMouse');
203
  var uFragColor = gl.getUniformLocation(program, 'uFragColor');
204
  
205
  gl.vertexAttrib2f(aPosition, 0.0, 0.0);
206
  gl.uniform2f(uSize, canvas.width, canvas.height);
207
  gl.uniform3f(iMouse, 0.0, 0.0, 0.0);
208
  gl.uniform4f(uFragColor, 1.0, 0.0, 0.0, 1.0);
209
  
210
  //gl.drawArrays(gl.POINTS, 0, 1);-
211
  
212
  var positions = new Float32Array([
213
    -1.0, 1.0,
214
    -1.0, -1.0,
215
    1.0, 1.0,
216
    
217
    1.0, 1.0,
218
    -1.0, -1.0,
219
    1.0, -1.0
220
  ]);
221
  initBuffer(gl, positions, 2, aPosition);
222
  
223
  function render() {
224
   gl.drawArrays(gl.TRIANGLES, 0, 6);
225
  }
226
  
227
  document.body.addEventListener("mousemove", function(ev) {
228
    gl.uniform3f(iMouse, ev.mouseX, ev.mouseY, 0.0);
229
  });
230
  
231
  function draw() {
232
    requestAnimationFrame(draw);
233
    render();
234
  }
235
  
236
  window.onresize = function(ev) {
237
    w = canvas.width = window.innerWidth;
238
    h = canvas.height = window.innerHeight;
239
    gl.viewport(0, 0, w, h);
240
    gl.uniform2f(uSize, w, h);
241
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
242
    gl.clear(gl.COLOR_BUFFER_BIT);
243
    render();
244
  };
245
  
246
  render();
247
} catch (e) {
248
  //alert(e);
249
  var msg = document.createElement("pre");
250
  msg.style = "color: red; position: absolute; right: 0; bottom: 0";
251
  msg.textContent = e;
252
  document.body.appendChild(msg);
253
}