4

我想将画布呈现为一个圆柱形圆锥体,您可以像轮子一样向两个方向旋转。这对 JS/CSS3 有可能吗?

4

2 回答 2

5

您应该看看这个新的 CSS3 功能:自定义过滤器/CSS 着色器

这里有一些非常好的演示文稿,它们比我能做的更好地描述了整个事情(如何在 Chrome 上启用它,如何开始,它是如何工作的,等等):

基本上,如果您已经熟悉着色器和 CSS3 变换,那么一切都完成了……

好处

  • 类 WebGl 的 GPU/3D 加速
  • 无 JS(GL 着色器和 CSS)
  • 可以将它与 CSS3-transitions 结合起来

不便之处

  • 新功能/仅受某些浏览器的最新版本支持(有时受标志保护)
  • 着色器的独立文件(不确定——也许可以像使用 WebGL 一样将它们内联到 html 页面中)
  • 在实现下面描述的示例时,我遇到了一个奇怪的行为:如果画布的大小(不是 CSS 大小而是“JS”大小,定义像素密度)变得太大,着色器似乎没有被应用不再,无论您是否在画布上执行操作。我很好奇为什么,所以我会尝试调查。

例子

为了满足您更精确的要求(画布作为圆柱体),我做了这个小例子:http ://aldream.net/various/css-shader-demo/cylindricalConeTransformDemo.html 。将鼠标悬停在画布上方,使其包裹成锥形。

它不会旋转,我只是应用了从上面给出的文章中的一个示例中获取的简单过渡效果,但您应该明白这一点。

使用的顶点着色器和片段着色器可以在这里找到:

简化和注释代码

  • CSS
    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
    );
}
  • HTML
<!doctype html>
<html>
<head>
    ... your meta, css, ...
<body>

    <canvas></canvas>

    <script>
        // Draw what you want in your canvas.
    </script>
</body>
</html>

编辑:我实际上不确定您要的是圆锥体还是圆柱体,但这里的差异很小。如果你想要第二个,你修改顶点着色器中的computeCylindricalConePosition()函数,像这样评估 px 和 py :

p.x = r * cos( fi ) /* * uv.y */;
p.y = r * sin( fi ) /* * uv.y */;

我希望它有所帮助。一旦我澄清了一些观点,我将尝试制定我的答案。

于 2013-05-09T16:36:34.743 回答
0

HTML-Canvas 的实际状态仅为 2D,但ThreeJS框架似乎是在 canvas-element 内进行 3d 渲染的一个很好的解决方案。

于 2013-05-08T06:26:49.603 回答