【问题标题】:Is there a way to create a 3D cylinder of the canvas element in CSS?有没有办法在 CSS 中创建画布元素的 3D 圆柱体?
【发布时间】:2013-08-04 20:00:40
【问题描述】:

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

【问题讨论】:

标签: javascript html css canvas 3d


【解决方案1】:

您应该看看这个新的 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() 函数,像这样评估 p.x 和 p.y:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 谢谢,我一直在考虑 ThreeJS,但我想知道是否有办法在 CSS3 中使用 3D 变换方法来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 2015-01-06
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    相关资源
    最近更新 更多