Reputation: 1326
I'd like to present the canvas as a cylindrical cone, which you can spin like a wheel in both directions. Is this at all possible with JS/CSS3?
Upvotes: 4
Views: 4974
Reputation: 15129
You should take a look at this new CSS3 feature: the Custom filters / CSS shaders.
Here are some really nice presentations made which describe the whole thing better than I could do (how to enable it on Chrome, how to start, how it works, etc):
Basically, if you're already familiar with shaders and CSS3 transforms, it's all done...
To answer your more-precise requirements (canvas as a cylindrical cone), I made this small example: http://aldream.net/various/css-shader-demo/cylindricalConeTransformDemo.html. Hover above the canvas to make it wrap into a cone.
It doesn't spin, I just applied a simple transition effect I took from one example in the articles given above, but you should get the idea.
The vertex shader and fragment shader used can be found here:
canvas {
/* ... Prettify it as you wish */
width: 640px;
height: 560px;
-webkit-filter: custom(url(cylindricalConeTransform.vs) /* Vertex-shader */
mix(url(cylindricalConeTransform.fs) normal source-atop /* Fragment-shader and color-mixing properties */),
36 2 /* Numbers of vertices */,
/* Passing the values to the shaders uniforms: */
amount 0,
cylinderRadius 0.35,
cylinderLength 250,
transform rotateY(0deg) rotateX(0deg));
-webkit-transition: -webkit-filter linear 1s; /* Transition on the filter for animation. */
}
canvas:hover {
/* Same as above, but with different values for some uniforms. With the CSS-transition, those values will be tweened. */
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;
p.x = r * cos( fi ) * uv.y;
p.y = r * sin( fi ) * uv.y;
p.z = (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;
}
/** spec: css */
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>
// Draw what you want in your canvas.
</script>
</body>
</html>
EDIT : I'm actually not sure if you're asking for a cone or a cylinder, but the difference is small here. If you want the 2nd, you modify the computeCylindricalConePosition() function in the vertex-shader, evaluating p.x and p.y like this instead:
p.x = r * cos( fi ) /* * uv.y */;
p.y = r * sin( fi ) /* * uv.y */;
I hope it helps. I will try to develop my answer once I clarify some points.
Upvotes: 5