GLSL着色器可提供纹理“烟熏"效果 [英] GLSL shader for texture 'smoke' effect

查看:353
本文介绍了GLSL着色器可提供纹理“烟熏"效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我环顾四周,没有发现任何相关内容.我打算创建一个着色器,以提供如下所示的纹理烟雾效果动画:

I've looked around and haven't found anything relevant. I'm tyring to create a shader to give a texture smoke effect animation like here:

不要求一个完整/完整的解决方案(尽管那将是很棒的),但是任何指向我可以在哪里开始实现这种效果的指标.我需要绘制图形的顶点吗?如果我只有纹理,可以这样做吗?

Not asking for a complete/full solution (although that would be awesome) but any pointers towards where I can get started to achieve this effect. Would i need to have the vertices for the drawing or is this possible if I have the texture only?

推荐答案

在所示的示例中,看起来好像它们具有顶点.可能记录了花朵形状的绘画",然后连续播放.然后,效果会根据绘制时的时间偏移量命中顶点.那里的效果似乎主要是运动模糊.

In the example pictured it appears as if they have the vertices. Possibly the "drawing" of the flower shape was recorded and then played back continuously. Then the effect hits the vertices based on a time offset from when they were drawn. The effect there appears to mostly be a motion blur.

因此,要复制此效果,您将需要顶点.看到花朵的顶部如何开始在底部之前消失?如果仔细观察,您会发现模糊效果的计时实际上是沿着花朵的逆时针方向移动的.即使在gif的第一帧,您也可以看到花朵形状的末端比开始处的黄色亮.

So to replicate this effect you would need the vertices. See how the top of the flower starts to disappear before the bottom? If you look closely you'll see that actually the blur effect timing follows the path of the flower around counter clockwise. Even on the first frame of your gif you can see that the end of the flower shape is a brighter yellow than the beginning.

运动模糊的角度似乎也随着时间的变化而变化,从向左偏向向上.

The angle of the motion blur also appears to change over time from being more left oriented to being more up oriented.

该段的亮度也随时间而变化,从淡黄色开始到黑色或透明结束.

And the brightness of the segment is also changing over time starting with the yellowish color and ending either black or transparent.

我不能确定的是效果是否是可加的,这意味着他们是将效果应用到整个帧,然后将效果应用到每个帧,或者是否要在每个帧中重新创建效果.如果重新创建每一帧,您将可以反向执行效果并显示图像.

What I can't tell from this is if the effect is additive, meaning that they're applying the effect to the whole frame and then to the results of that effect each frame, or if it's being recreated each frame. If recreated each frame you'd be able to do the effect in reverse and have the image appear.

如果您希望对位图纹理而不是同样可行的线对象产生这种效果,尽管方法会有所不同.

If you are wanting this effect on a bitmapped texture instead of a line object that's also doable, although the approach would be different.

让我们从线对象开始,并假设您具有顶点.我要采用的方法是,将一定百分比的衰减作为属性添加到顶点数据中.然后,您渲染的每个帧都将首先基于该顶点的时间来更新衰减百分比.稍微交错一下.

Let's start with the line object and assume you have the vertices. The way I would approach it is that I would add a percentage of decay as an attribute to the vertex data. Then each frame that you render you'd first update the decay percentage based on the time for that vertex. Stagger them slightly.

然后,着色器将使用运动模糊着色器绘制线段,其中运动模糊量,模糊角度和线段颜色由衰减属性分配的可变变量控制.我尚未测试此着色器.像伪代码一样对待它.但是我会这样处理...顶点着色器:

Then the shader would draw the line segment using a motion blur shader where the amount of motion blur, the angle of the blur, and the color of the segment are controlled by a varying variable that is assigned by the decay attribute. I haven't tested this shader. Treat it like pseudocode. But I'd approach it this way... Vertex Shader:

 uniform mat4 u_modelViewProjectionMatrix;
 uniform float maxBlurSizeConstant;  // experiment with value and it will be based on the scale of the render

 attribute vec3 a_vertexPosition;
 attribute vec2 a_vertexTexCoord0;
 attribute float a_decay;

 varying float v_decay;
 varying vec2 v_fragmentTexCoord0;
 varying vec2 v_texCoord1;
 varying vec2 v_texCoord2;
 varying vec2 v_texCoord3;
 varying vec2 v_texCoord4;
 varying vec2 v_texCoordM1;
 varying vec2 v_texCoordM2;
 varying vec2 v_texCoordM3;
 varying vec2 v_texCoordM4;

 void main()
 {
    gl_Position = u_modelViewProjectionMatrix * vec4(a_vertexPosition,1.0);

    v_decay = a_decay;

    float angle = 2.8 - a_decay * 0.8;  // just an example of angles

    vec2 tOffset = vec2(cos(angle),sin(angle)) * maxBlurSizeConstant * a_decay;

    v_fragmentTexCoord0 = a_vertexTexCoord0;

    v_texCoordM1 = a_vertexTexCoord0 - tOffset;
    v_texCoordM2 = a_vertexTexCoord0 - 2.0 * tOffset;
    v_texCoordM3 = a_vertexTexCoord0 - 3.0 * tOffset;
    v_texCoordM4 = a_vertexTexCoord0 - 4.0 * tOffset;
    v_texCoord1 = a_vertexTexCoord0 + tOffset;
    v_texCoord2 = a_vertexTexCoord0 + 2.0 * tOffset;
    v_texCoord3 = a_vertexTexCoord0 + 3.0 * tOffset;
    v_texCoord4 = a_vertexTexCoord0 + 4.0 * tOffset;
 }

片段着色器:

 uniform sampler2D u_textureSampler;

 varying float v_decay;
 varying vec2 v_fragmentTexCoord0;
 varying vec2 v_texCoord1;
 varying vec2 v_texCoord2;
 varying vec2 v_texCoord3;
 varying vec2 v_texCoord4;
 varying vec2 v_texCoordM1;
 varying vec2 v_texCoordM2;
 varying vec2 v_texCoordM3;
 varying vec2 v_texCoordM4;

 void main()
 {
     lowp vec4 fragmentColor = texture2D(u_textureSampler, v_fragmentTexCoord0) * 0.18;

     fragmentColor += texture2D(u_textureSampler, v_texCoordM1) * 0.15;
     fragmentColor += texture2D(u_textureSampler, v_texCoordM2) * 0.12;
     fragmentColor += texture2D(u_textureSampler, v_texCoordM3) * 0.09;
     fragmentColor += texture2D(u_textureSampler, v_texCoordM4) * 0.05;
     fragmentColor += texture2D(u_textureSampler, v_texCoord1) * 0.15;
     fragmentColor += texture2D(u_textureSampler, v_texCoord2) * 0.12;
     fragmentColor += texture2D(u_textureSampler, v_texCoord3) * 0.09;
     fragmentColor += texture2D(u_textureSampler, v_texCoord4) * 0.05;

     gl_FragColor = vec4(fragmentColor.rgb, fragmentColor.a * v_decay);
 }

当然,诀窍在于根据时间的微小偏移量来改变每个顶点的衰减量.

Of course the trick is in varying the decay amount per vertex based on a slight offset in time.

如果要对精灵执行相同的操作,则将执行非常相似的操作,只是每个顶点的衰减之间的差异必须正确处理,因为只有4个顶点.

If you want to do the same with a sprite you're going to do something very similar except that the difference between the decay per vertex would have to be played with to get right as there are only 4 vertices.

抱歉-编辑

对不起...上面的着色器模糊了传入的纹理.它不一定会模糊所绘制线条的颜色.这可能是您想要做的,也可能不是.但是,又一次又不知道您实际上试图完成什么,很难给您一个完美的答案.我觉得您还是宁愿在精灵上执行此操作,也不愿基于线顶点的对象执行此操作.因此,不能,您不能按原样复制此着色器并将其粘贴到您的代码中.但这显示了您将如何做自己想做的事情的概念.尤其是如果要在纹理上而不是在基于顶点的线上进行

Sorry... The above shader blurs the incoming texture. It doesn't necessarily blur the color of the line being drawn. This might or might not be what you want to do. But again without knowing more of what you are actually trying to accomplish it's difficult to give you a perfect answer. I get the feeling you'd rather do this on a sprite anyway than a line vertex based object. So no you can't copy and paste this shader in to your code as is. But it shows the concept of how you'd do what you're looking to do. Especially if you're doing it on a texture instead of on a vertex based line.

上面的着色器也不完整.例如,它不会扩展以允许模糊超出纹理范围.它从子画面中子画面所在区域的外部获取纹理信息.要解决此问题,您必须从大于精灵的边界框开始,然后将顶点中的精灵缩小为正确的大小.而且,您不必从Sprite表格中获取超出Sprite边界的文本框.有一些方法可以做到,而不必在Sprite工作表中的Sprite周围包含一堆空白.

Also the above shader isn't complete. For example it doesn't expand to allow the blur to get beyond the bounds of the texture. And it gets texture info from outside the area where the sprite is in the sprite sheet. To fix this you'd have to start with a bounding box larger than the sprite and shrink the sprite in the vertex to be the right size. And you'd have to not grab textels from the spite sheet beyond the bounds of the sprite. There are ways of doing this without having to include a bunch of white space around the sprite in the sprite sheet.

更新

乍一看,它可能是基于粒子的.如果是的话,它们再次具有所有顶点,但作为粒子位置.我比较喜欢线段,因为我看不到任何间隙.因此,如果是颗粒,则存在很多并且它们被紧紧地放置.粒子仍在从顶部花瓣到最后一个花瓣的级联衰减.即使是线段,您也可以将顶点视为施加风和重力的粒子.

On second look it might be particle based. If it is they again have all the vertices but as particle locations. I sort of prefer the idea that it's line segments because I don't see any gaps. So if it is particles there are a lot and they're tightly placed. The particles are still decaying cascading from the top petal around to the last. Even if it's line segments you could treat the vertices as particles to apply the wind and gravity.

有关烟雾效果的工作方式,请按71平方查看此帮助应用程序: https://71squared.com/particledesigner

As for how the smoke effect works check out this helper app by 71 squared: https://71squared.com/particledesigner

其工作方式是购买Mac应用程序以用于设计和保存粒子.然后,转到他们的github并获取iOS代码.但是这个特定的代码创建了一个粒子发射器.用粒子做形状将是不同的代码.但是粒子的演化是相同的.

The way it works is that you buy the Mac app to use to design and save your particle. Then you go to their github and get the iOS code. But this particular code creates a particle emitter. Doing a shape out of particles would be different code. But the evolution of the particles is the same.

这篇关于GLSL着色器可提供纹理“烟熏"效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆