You should take a look at this new CSS3 feature: Custom CSS Filters / Shaders .
Here are some really nice presentations that describe it all better than I could (how to enable it in Chrome, how to get started, how it works, etc.):
Basically, if you are already familiar with CSS3 shaders and transforms, all this is done ...
Benefits
- GPU / 3D acceleration with WebGl
- JS-free (GL-shaders and CSS only)
- Ability to combine it with CSS3 transitions
Inconvenients
- The new function / is only supported by the latest versions of some browsers (sometimes protected by a flag)
- Independent files for shaders (uncertainty about this - it is possible, somehow it is possible to embed them in an html page, for example, using WebGL)
- When implementing the example described below, I came across a strange behavior: if the canvas size (not the CSS size, but the "JS" that defines the pixel density) becomes too large, the shaders do not seem to be applied, regardless of the operations you perform or not on your canvas. I am very curious why, so I will try to investigate this.
Example
To answer your more exact requirements (canvas as a cylindrical cone), I made this small example: http://aldream.net/various/css-shader-demo/cylindricalConeTransformDemo.html . Hover over the canvas to wrap it in a cone.
It doesnβt spin, I just applied a simple transition effect, which I took from one example in the above articles, but you should get this idea.
The vertex shader and fragment shader used can be found here:
Simplified and commented code
canvas { width: 640px; height: 560px; -webkit-filter: custom(url(cylindricalConeTransform.vs) mix(url(cylindricalConeTransform.fs) normal source-atop ), 36 2 , amount 0, cylinderRadius 0.35, cylinderLength 250, transform rotateY(0deg) rotateX(0deg)); -webkit-transition: -webkit-filter linear 1s; } canvas:hover { filter: custom(url(cylindricalConeTransform.vs) mix(url(cylindricalConeTransform.fs) normal source-atop), 36 2, amount 1, cylinderRadius 0.35, cylinderLength 250, transform rotateY(60deg) rotateX(60deg)); }
precision mediump float; // Built-in attributes attribute vec4 a_position; attribute vec2 a_texCoord; // Built-in uniforms uniform mat4 u_projectionMatrix; // Uniforms passed in from CSS uniform float amount; uniform float cylinderRadius; uniform float cylinderLength; uniform mat4 transform; // Constants const float PI = 3.1415; // Cone function vec3 computeCylindricalConePosition( vec2 uv, float r, float l ) { vec3 p; float fi = uv.x * PI * 2.0; px = r * cos( fi ) * uv.y; py = r * sin( fi ) * uv.y; pz = (uv.y - 0.5) * l; return p; } // Main void main() { vec4 position = a_position; // Map plane to cone using UV coordinates vec3 cone = computeCylindricalConePosition( a_texCoord, cylinderRadius, cylinderLength ); // Blend plane and cone position.xyz = mix( position.xyz, cone, amount ); // Set vertex position gl_Position = u_projectionMatrix * transform * position; }
precision mediump float; void main() { css_ColorMatrix = mat4( 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); }
<!doctype html> <html> <head> ... your meta, css, ... <body> <canvas></canvas> <script> </script> </body> </html>
EDIT: I'm really not sure if you are asking for a cone or cylinder, but the difference here is small. If you want the second, you change the computeCylindricalConePosition () function in the vertex shader, evaluating px and py like this:
px = r * cos( fi ) ; py = r * sin( fi ) ;
Hope this helps. I will try to develop my answer as soon as I clarify some points.