-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvr-effect.html
146 lines (127 loc) · 5.4 KB
/
vr-effect.html
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
<html>
<script type="bogus" id="vertexShader">
precision highp float;
attribute vec2 vertex;
varying vec2 oTexCoord;
void main() {
oTexCoord = 0.5 + vec2(0.5, -0.5) * vertex;
gl_Position = vec4(vertex, 0.0, 1.0);
}
</script>
<script id="fragmentShader" type="whatevs">
precision highp float;
varying vec2 oTexCoord;
// Values that were scattered throughout the Oculus world demo
const vec4 HmdWarpParam = vec4(1.0, 0.22, 0.24, 0.0); // For the 7-inch device
const vec4 ChromAbParam = vec4(0.996, -0.004, 1.014, 0.0);
const float HMD_HResolution = 1280.0;
const float HMD_VResolution = 800.0;
const float HMD_HScreenSize = 0.14976;
const float HMD_VScreenSize = HMD_HScreenSize / (HMD_HResolution / HMD_VResolution);
const float HMD_InterpupillaryDistance = 0.064;
const float HMD_LensSeparationDistance = 0.0635;
const float HMD_EyeToScreenDistance = 0.041;
const float lensOffset = HMD_LensSeparationDistance * 0.5;
const float lensShift = HMD_HScreenSize * 0.25 - lensOffset;
const float Distortion_XCenterOffset = 4.0 * lensShift / HMD_HScreenSize;
const float DistortionFitX = -1.0;
const float DistortionFitY = 0.0;
const float stereoAspect = 0.5 * HMD_HResolution / HMD_VResolution;
const float dx = DistortionFitX - Distortion_XCenterOffset;
const float dy = DistortionFitY / stereoAspect;
const float fitRadiusSquared = dx * dx + dy * dy;
const float Distortion_Scale =
HmdWarpParam.x +
HmdWarpParam.y * fitRadiusSquared +
HmdWarpParam.z * fitRadiusSquared * fitRadiusSquared +
HmdWarpParam.w * fitRadiusSquared * fitRadiusSquared * fitRadiusSquared;
// This samples from a single unwarped [0,0]x[1,1] box containing two views
// side-by-side that have been rendered using normal perspective projection.
// The left eye takes up [0,0]x[0.5,1] and the right eye takes up [0.5,0]x[1,1].
vec4 sample(vec2 point, vec2 ScreenCenter) {
if (clamp(point, ScreenCenter - vec2(0.25, 0.5), ScreenCenter + vec2(0.25, 0.5)) != point) return vec4(0.0);
vec2 checkerboard = fract(point * vec2(4.0, 2.0)) - 0.5;
return vec4(checkerboard.x * checkerboard.y < 0.0 ? 0.25 : 1.0);
}
void main() {
// Compute the viewport size
bool isRight = oTexCoord.x > 0.5;
float x = isRight ? 0.5 : 0.0;
float y = 0.0;
float w = 0.5;
float h = 1.0;
// Set up values for the shader
float XCenterOffset = isRight ? -Distortion_XCenterOffset : Distortion_XCenterOffset;
vec2 LensCenter = vec2(x + (w + XCenterOffset * 0.5) * 0.5, y + h * 0.5);
vec2 ScreenCenter = vec2(x + w * 0.5, y + h * 0.5);
float scaleFactor = 1.0 / Distortion_Scale;
vec2 Scale = vec2(w * 0.5 * scaleFactor, h * 0.5 * scaleFactor * stereoAspect);
vec2 ScaleIn = vec2(2.0 / w, 2.0 / h / stereoAspect);
// Compute the warp
vec2 theta = (oTexCoord - LensCenter) * ScaleIn; // Scales to [-1, 1]
float rSq = theta.x * theta.x + theta.y * theta.y;
vec2 theta1 = theta * (
HmdWarpParam.x +
HmdWarpParam.y * rSq +
HmdWarpParam.z * rSq * rSq +
HmdWarpParam.w * rSq * rSq * rSq);
// Compute chromatic aberration
vec2 thetaRed = theta1 * (ChromAbParam.x + ChromAbParam.y * rSq);
vec2 thetaBlue = theta1 * (ChromAbParam.z + ChromAbParam.w * rSq);
vec2 tcRed = LensCenter + Scale * thetaRed;
vec2 tcGreen = LensCenter + Scale * theta1;
vec2 tcBlue = LensCenter + Scale * thetaBlue;
// Apply chromatic aberration
gl_FragColor = vec4(
sample(tcRed, ScreenCenter).r,
sample(tcGreen, ScreenCenter).g,
sample(tcBlue, ScreenCenter).b,
1.0);
// Visualize the unwarped data
// gl_FragColor = sample(oTexCoord, ScreenCenter);
}
</script>
<body style="position:fixed;left:0;top:0;right:0;bottom:0;overflow;hidden;margin:0;">
<canvas id="canvas"></canvas>
</body>
<script>
var gl = canvas.getContext('experimental-webgl', { 'alpha': false });
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
function createShader(vertexSource, fragmentSource) {
function compileShader(type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var info = gl.getShaderInfoLog(shader);
if (info) throw new Error(info);
gl.attachShader(program, shader);
}
var program = gl.createProgram();
compileShader(gl.VERTEX_SHADER, vertexSource);
compileShader(gl.FRAGMENT_SHADER, fragmentSource);
gl.linkProgram(program);
return program;
}
function render() {
gl.useProgram(shader);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function resize() {
var dpr = window.devicePixelRatio || 1; // Support for retina displays
gl.canvas.width = innerWidth * dpr;
gl.canvas.height = innerHeight * dpr;
gl.canvas.style.width = innerWidth + 'px';
gl.canvas.style.height = innerHeight + 'px';
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
render();
}
var shader = createShader(vertexShader.textContent, fragmentShader.textContent);
window.onresize = resize;
resize();
render();
</script>
</html>