OLD | NEW |
(Empty) | |
| 1 <!-- @@REWRITE(insert html-copyright) --> |
| 2 <!-- |
| 3 O3D Siteswap animator |
| 4 @@REWRITE(delete-start) |
| 5 Author: Eric Uhrhane (ericu@google.com) |
| 6 @@REWRITE(delete-end) |
| 7 --> |
| 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
| 9 "http://www.w3.org/TR/html4/loose.dtd"> |
| 10 <html> |
| 11 <head> |
| 12 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> |
| 13 <title> |
| 14 Site Swap Simulator |
| 15 </title> |
| 16 <style type="text/css"> |
| 17 html, body { |
| 18 height: 100%; |
| 19 margin: 0; |
| 20 padding: 0; |
| 21 border: none; |
| 22 } |
| 23 </style> |
| 24 <!-- Our javascript code --> |
| 25 <script type="text/javascript" src="../o3djs/base.js"></script> |
| 26 <script type="text/javascript" src="siteswap.js"></script> |
| 27 <script type="text/javascript" src="math.js"></script> |
| 28 <script type="text/javascript" src="animation.js"></script> |
| 29 <script type="text/javascript"> |
| 30 |
| 31 o3djs.require('o3djs.util'); |
| 32 |
| 33 // Set up the client area. |
| 34 function init() { |
| 35 o3djs.util.setMainEngine(o3djs.util.Engine.V8); |
| 36 o3djs.util.addScriptUri(''); // Allow V8 to load scripts in the cwd. |
| 37 o3djs.util.makeClients(initStep2); |
| 38 setUpSelection(); |
| 39 } |
| 40 |
| 41 // Select the entire input pattern, so that the user can just type. |
| 42 function setUpSelection() { |
| 43 var input_pattern = document.getElementById('input_pattern'); |
| 44 input_pattern.focus(); |
| 45 input_pattern.selectionStart = 0; |
| 46 input_pattern.selectionEnd = input_pattern.value.length; |
| 47 } |
| 48 |
| 49 /* |
| 50 * Wrappers to enable button presses to call through to the embedded V8 engine. |
| 51 */ |
| 52 |
| 53 // Update whether we're animating or frozen based on the value of the checkbox. |
| 54 function updateAnimatingWrapper() { |
| 55 g.o3dElement.eval('updateAnimating()'); |
| 56 } |
| 57 |
| 58 // Compute a new pattern. |
| 59 function onComputePatternWrapper() { |
| 60 g.o3dElement.eval('onComputePattern()'); |
| 61 } |
| 62 |
| 63 // Adjust the view matrix to the new proportions of the plugin window. |
| 64 // TODO: Switch to using the resize event once that's checked in. |
| 65 function onResizeWrapper() { |
| 66 g.o3dElement.eval('onResize()'); |
| 67 } |
| 68 window.onresize = onResizeWrapper; |
| 69 |
| 70 // Clean up all our callbacks, etc. |
| 71 function cleanupWrapper() { |
| 72 if (g && g.o3dElement) { |
| 73 g.o3dElement.eval('cleanup()'); |
| 74 } |
| 75 } |
| 76 |
| 77 // The point of this function is to suppress form submit; we want to use the |
| 78 // pattern entered when the user hits return, not submit the page to the |
| 79 // webserver. |
| 80 function suppressSubmit(event) { |
| 81 onComputePatternWrapper(); // TODO: This suppresses form autocomplete storage. |
| 82 return false; |
| 83 } |
| 84 |
| 85 </script> |
| 86 </head> |
| 87 <body onload="init()" onunload="cleanupWrapper()"> |
| 88 <table width="100%" style="height:100%;"> |
| 89 <tr> |
| 90 <td> |
| 91 <h1>Juggler</h1> |
| 92 This sample displays a site-swap juggling pattern with animation done by |
| 93 a vertex shader. |
| 94 <form name="the_form" onsubmit="return suppressSubmit(event)"> |
| 95 <table> |
| 96 <tr> |
| 97 <td> |
| 98 <table> |
| 99 <tr> |
| 100 <td> |
| 101 <input |
| 102 type="radio" |
| 103 name="radio_group_hands" |
| 104 value="1" |
| 105 onclick=onComputePatternWrapper()> |
| 106 1 Hand<br> |
| 107 <input |
| 108 type="radio" |
| 109 name="radio_group_hands" |
| 110 value="2" |
| 111 onclick=onComputePatternWrapper() |
| 112 checked> |
| 113 2 Hands<br> |
| 114 <input |
| 115 type="radio" |
| 116 name="radio_group_hands" |
| 117 value="3" |
| 118 onclick=onComputePatternWrapper()> |
| 119 3 Hands<br> |
| 120 <input |
| 121 type="radio" |
| 122 name="radio_group_hands" |
| 123 value="4" |
| 124 onclick=onComputePatternWrapper()> |
| 125 4 Hands<br> |
| 126 </td> |
| 127 <td> |
| 128 <input type="text" name="input_pattern" id="input_pattern" |
| 129 value="3 4 5"> |
| 130 </td> |
| 131 <td> |
| 132 <input type="checkbox" name="check_box" checked |
| 133 onclick=updateAnimatingWrapper()>Animate |
| 134 <input |
| 135 type="checkbox" |
| 136 name="pair_hands" |
| 137 onclick=onComputePatternWrapper(); |
| 138 >Pair Hands |
| 139 </td> |
| 140 <td> |
| 141 <input type="button" name="computePattern" |
| 142 value="Compute Pattern" |
| 143 onclick=onComputePatternWrapper()> |
| 144 </td> |
| 145 </tr> |
| 146 </table> |
| 147 </td> |
| 148 <td> |
| 149 </td> |
| 150 </tr> |
| 151 </table> |
| 152 </form> |
| 153 <table id="container" width="90%" style="height:70%;"> |
| 154 <tr> |
| 155 <td height="100%"> |
| 156 <!-- Start of g.o3d plugin --> |
| 157 <div id="o3d" style="width: 100%; height: 100%;"></div> |
| 158 <!-- End of g.o3d plugin --> |
| 159 </td> |
| 160 </tr> |
| 161 </table> |
| 162 <!-- a simple way to get a multiline string --> |
| 163 <textarea id="shader" name="shader" cols="80" rows="20" |
| 164 style="display: none;"> |
| 165 // the 4x4 world view projection matrix |
| 166 float4x4 worldViewProjection : WorldViewProjection; |
| 167 |
| 168 // positions of the light and camera |
| 169 float3 light_pos; |
| 170 float3 camera_pos; |
| 171 |
| 172 // phong lighting properties of the material |
| 173 float4 light_ambient; |
| 174 float4 light_diffuse; |
| 175 float4 light_specular; |
| 176 |
| 177 // shininess of the material (for specular lighting) |
| 178 float shininess; |
| 179 |
| 180 // time for animation |
| 181 float time; |
| 182 |
| 183 // coefficients for a t^2 + b t + c for each of x, y, z |
| 184 float3 coeff_a; |
| 185 float3 coeff_b; |
| 186 float3 coeff_c; |
| 187 |
| 188 // flag and coefficient for optional LERP with rate t * coeff_lerp; |
| 189 float coeff_lerp; |
| 190 |
| 191 // coefficients for a t^2 + b t + c for each of x, y, z, for optional LERP |
| 192 float3 coeff_l_a; |
| 193 float3 coeff_l_b; |
| 194 float3 coeff_l_c; |
| 195 |
| 196 // coefficients for d sin(f t) + e cos(e t) for each of x, y, z |
| 197 float3 coeff_d; |
| 198 float3 coeff_e; |
| 199 float3 coeff_f; |
| 200 |
| 201 // to be subtracted from time to get the t for the above equation |
| 202 float time_base; |
| 203 |
| 204 // input parameters for our vertex shader |
| 205 struct VertexShaderInput { |
| 206 float4 position : POSITION; |
| 207 float3 normal : NORMAL; |
| 208 float4 color : COLOR; |
| 209 }; |
| 210 |
| 211 // input parameters for our pixel shader |
| 212 // also the output parameters for our vertex shader |
| 213 struct PixelShaderInput { |
| 214 float4 position : POSITION; |
| 215 float3 lightVector : TEXCOORD0; |
| 216 float3 normal : TEXCOORD1; |
| 217 float3 viewPosition : TEXCOORD2; |
| 218 float4 color : COLOR; |
| 219 }; |
| 220 |
| 221 /** |
| 222 * Vertex Shader - vertex shader for phong illumination |
| 223 */ |
| 224 PixelShaderInput vertexShaderFunction(VertexShaderInput input) { |
| 225 /** |
| 226 * We use the standard phong illumination equation here. |
| 227 * We restrict (clamp) the dot products so that we |
| 228 * don't get any negative values. |
| 229 * All vectors are normalized for proper calculations. |
| 230 * |
| 231 * The output color is the summation of the |
| 232 * ambient, diffuse, and specular contributions. |
| 233 * |
| 234 * Note that we have to transform each vertex and normal |
| 235 * by the world view projection matrix first. |
| 236 */ |
| 237 PixelShaderInput output; |
| 238 |
| 239 float t = time - time_base; |
| 240 float3 offset = float3(0, 0, 0); |
| 241 offset += t * t * coeff_a + t * coeff_b + coeff_c; |
| 242 offset += coeff_d * sin(t * coeff_f); |
| 243 offset += coeff_e * cos(t * coeff_f); |
| 244 |
| 245 float3 lerpOffset = t * t * coeff_l_a + t * coeff_l_b + coeff_l_c; |
| 246 if (coeff_lerp > 0) { |
| 247 float rate = min(coeff_lerp * t, 1); |
| 248 float3 lerpVector = float3(rate, rate, rate); |
| 249 offset = lerp(offset, lerpOffset, lerpVector); |
| 250 } else if (coeff_lerp < 0) { |
| 251 float rate = min(-coeff_lerp * t, 1); |
| 252 float3 lerpVector = float3(rate, rate, rate); |
| 253 offset = lerp(lerpOffset, offset, lerpVector); |
| 254 } |
| 255 |
| 256 input.position = input.position + float4(offset.xyz, 0); |
| 257 |
| 258 output.position = mul(input.position, worldViewProjection); |
| 259 |
| 260 /** |
| 261 * lightVector - light vector |
| 262 * normal - normal vector |
| 263 * viewPosition - view vector (from camera) |
| 264 */ |
| 265 |
| 266 // NOTE: In this case we do not need to multiply by any matrices since the |
| 267 // WORLD transformation matrix is the identity. If you were moving the |
| 268 // object such that the WORLD transform matrix was not the identity, you |
| 269 // would need to multiply the normal by the WORLDINVERSETTRANSFORM matrix |
| 270 // since the normal is in object space. Other values (light_pos, camera_pos) |
| 271 // are already in world space. |
| 272 float3 lightVector = light_pos - input.position.xyz; |
| 273 float3 normal = input.normal; |
| 274 float3 viewPosition = camera_pos - input.position.xyz; |
| 275 |
| 276 output.lightVector = lightVector; |
| 277 output.normal = normal; |
| 278 output.viewPosition = viewPosition; |
| 279 output.color = input.color; |
| 280 return output; |
| 281 } |
| 282 |
| 283 /** |
| 284 * Pixel Shader |
| 285 */ |
| 286 float4 pixelShaderFunction(PixelShaderInput input): COLOR { |
| 287 float3 lightVector = normalize(input.lightVector); |
| 288 float3 normal = normalize(input.normal); |
| 289 float3 viewPosition = normalize(input.viewPosition); |
| 290 float3 halfVector = normalize(lightVector + viewPosition); |
| 291 |
| 292 // use lit function to calculate phong shading |
| 293 // x component contains the ambient coefficient |
| 294 // y component contains the diffuse coefficient: |
| 295 // max(dot(normal, lightVector),0) |
| 296 // z component contains the specular coefficient: |
| 297 // dot(normal, lightVector) < 0 || dot(normal, halfVector) < 0 ? |
| 298 // 0 : pow(dot(normal, halfVector), shininess) |
| 299 // NOTE: This is actually Blinn-Phong shading, not Phong shading |
| 300 // which would use the reflection vector instead of the half vector |
| 301 |
| 302 float4 phong_coeff = lit(dot(normal, lightVector), |
| 303 dot(normal, halfVector), shininess); |
| 304 |
| 305 float4 ambient = light_ambient * phong_coeff.x * input.color; |
| 306 float4 diffuse = light_diffuse * phong_coeff.y * input.color; |
| 307 float4 specular = light_specular * phong_coeff.z * input.color; |
| 308 |
| 309 return ambient + diffuse + specular; |
| 310 } |
| 311 |
| 312 // Here we tell our effect file *which* functions are |
| 313 // our vertex and pixel shaders. |
| 314 |
| 315 // #o3d VertexShaderEntryPoint vertexShaderFunction |
| 316 // #o3d PixelShaderEntryPoint pixelShaderFunction |
| 317 // #o3d MatrixLoadOrder RowMajor |
| 318 </textarea> |
| 319 </td> |
| 320 </tr> |
| 321 </table> |
| 322 </body> |
| 323 </html> |
OLD | NEW |