commit 36b5eb0abb31f0b4e794533e4197ae41c04e1e8f Author: 严争鸣 Date: Mon Dec 9 14:57:06 2024 +0800 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..69c2c62 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# shader + + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin http://yhm.ink/cesium/shader.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +- [ ] [Set up project integrations](http://yhm.ink/cesium/shader/-/settings/integrations) + +## Collaborate with your team + +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README + +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/shadertoy移植/20241203_143947.assets/09702a92331f297b923498f195ad37f6.gif b/shadertoy移植/20241203_143947.assets/09702a92331f297b923498f195ad37f6.gif new file mode 100644 index 0000000..337d764 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/09702a92331f297b923498f195ad37f6.gif differ diff --git a/shadertoy移植/20241203_143947.assets/211bf10bbb9465b33d1ec278ab9184e3.png b/shadertoy移植/20241203_143947.assets/211bf10bbb9465b33d1ec278ab9184e3.png new file mode 100644 index 0000000..d6d39f3 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/211bf10bbb9465b33d1ec278ab9184e3.png differ diff --git a/shadertoy移植/20241203_143947.assets/2b47675426e7e025aa72c770126b795d.png b/shadertoy移植/20241203_143947.assets/2b47675426e7e025aa72c770126b795d.png new file mode 100644 index 0000000..5daf407 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/2b47675426e7e025aa72c770126b795d.png differ diff --git a/shadertoy移植/20241203_143947.assets/3b3a587355ac37226ff923d00a3b3501.png b/shadertoy移植/20241203_143947.assets/3b3a587355ac37226ff923d00a3b3501.png new file mode 100644 index 0000000..391fb97 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/3b3a587355ac37226ff923d00a3b3501.png differ diff --git a/shadertoy移植/20241203_143947.assets/63bdf501ba818cb309751c33730c63ac.gif b/shadertoy移植/20241203_143947.assets/63bdf501ba818cb309751c33730c63ac.gif new file mode 100644 index 0000000..b277e57 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/63bdf501ba818cb309751c33730c63ac.gif differ diff --git a/shadertoy移植/20241203_143947.assets/6bab4d5963817d72a2e0418a5841e815.png b/shadertoy移植/20241203_143947.assets/6bab4d5963817d72a2e0418a5841e815.png new file mode 100644 index 0000000..a5c89f9 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/6bab4d5963817d72a2e0418a5841e815.png differ diff --git a/shadertoy移植/20241203_143947.assets/71d7b7a8f35a02471424f5185d0ecbdb.png b/shadertoy移植/20241203_143947.assets/71d7b7a8f35a02471424f5185d0ecbdb.png new file mode 100644 index 0000000..f1a890c Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/71d7b7a8f35a02471424f5185d0ecbdb.png differ diff --git a/shadertoy移植/20241203_143947.assets/8103ee5541c006dfb125fbe2e78ed87d.png b/shadertoy移植/20241203_143947.assets/8103ee5541c006dfb125fbe2e78ed87d.png new file mode 100644 index 0000000..f0a73c2 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/8103ee5541c006dfb125fbe2e78ed87d.png differ diff --git a/shadertoy移植/20241203_143947.assets/aa4fd912f61efc677780ff1378cd3d11.png b/shadertoy移植/20241203_143947.assets/aa4fd912f61efc677780ff1378cd3d11.png new file mode 100644 index 0000000..f2dc644 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/aa4fd912f61efc677780ff1378cd3d11.png differ diff --git a/shadertoy移植/20241203_143947.assets/b71065d007c4923af46f2406af5cca5b.gif b/shadertoy移植/20241203_143947.assets/b71065d007c4923af46f2406af5cca5b.gif new file mode 100644 index 0000000..ba7d898 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/b71065d007c4923af46f2406af5cca5b.gif differ diff --git a/shadertoy移植/20241203_143947.assets/b75429109a7c276754ffb523df9e9d48.png b/shadertoy移植/20241203_143947.assets/b75429109a7c276754ffb523df9e9d48.png new file mode 100644 index 0000000..f0c693c Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/b75429109a7c276754ffb523df9e9d48.png differ diff --git a/shadertoy移植/20241203_143947.assets/c1eeb7716326293e03113f99c49eda30.png b/shadertoy移植/20241203_143947.assets/c1eeb7716326293e03113f99c49eda30.png new file mode 100644 index 0000000..7ade64b Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/c1eeb7716326293e03113f99c49eda30.png differ diff --git a/shadertoy移植/20241203_143947.assets/c7673cdb75556dab2dbdff9497328541.gif b/shadertoy移植/20241203_143947.assets/c7673cdb75556dab2dbdff9497328541.gif new file mode 100644 index 0000000..cdd353e Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/c7673cdb75556dab2dbdff9497328541.gif differ diff --git a/shadertoy移植/20241203_143947.assets/e7a0064f7be091b39669a0d187bd687d.gif b/shadertoy移植/20241203_143947.assets/e7a0064f7be091b39669a0d187bd687d.gif new file mode 100644 index 0000000..562a154 Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/e7a0064f7be091b39669a0d187bd687d.gif differ diff --git a/shadertoy移植/20241203_143947.assets/e9ff0716de4a7c4710989de8b24d3998.gif b/shadertoy移植/20241203_143947.assets/e9ff0716de4a7c4710989de8b24d3998.gif new file mode 100644 index 0000000..7d79dff Binary files /dev/null and b/shadertoy移植/20241203_143947.assets/e9ff0716de4a7c4710989de8b24d3998.gif differ diff --git a/shadertoy移植/20241203_143947.html b/shadertoy移植/20241203_143947.html new file mode 100644 index 0000000..3ceeab5 --- /dev/null +++ b/shadertoy移植/20241203_143947.html @@ -0,0 +1,1721 @@ + + + + + + + + + + + + + + + + + Cesium进阶学习四、shadertoy(着色器)_cesium 着色器-CSDN博客 + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+
+ +
+ +
+
+
+
+

Cesium进阶学习四、shadertoy(着色器)

+
+ +
+ +
+
+
+
+ + + +
+ + + +

一、简介
shadertoy是一个基于webgl的分享Shader的开放平台,用户可以在上面根据既定规则分享自己编写的shader。在Cesium中要想实现一些酷炫的效果,唯一的一条路就是写shader,而shader的编写应该算是图形学中的难度天花板了。好在有很多shader大佬分享了自己编写的glsl效果,比如shadertoy网站上就是这些大牛们的作品,我们可以借鉴。
在这里插入图片描述

+

二、shadertoy着色器基本结构

+

shadertoy上的shader是纯2d绘图,没有几何顶点这些概念,它的绘图方式和canvas绘图方式很像,它将整个canvas作为绘图的画布,所以输入参数fragCoord的x值范围是(0,画布的宽度),fragCoord的y值范围是(0,画布的高度),画布的宽高在定义的输入参数中是iResolution,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。
在这里插入图片描述

+

如图所示,shadertoy上的shader示例最基本的着色器结构主要包括两个部分:
a、输入参数的定义
b、着色器的入口函数

+

1、输入参数,通过uniform来定义外部的输入值。

+
uniform vec3      iResolution;           // 视口分辨率,即画布的宽高
+uniform float     iTime;                 // shader 的运行时间 秒
+uniform float     iTimeDelta;            // 渲染时间 秒
+uniform float     iFrameRate;            // shader 帧率
+uniform int       iFrame;                // shader 帧率
+uniform float     iChannelTime[4];       // 频道运行时间 不管
+uniform vec3      iChannelResolution[4]; // 频道分辨率 不管
+uniform vec4      iMouse;                // 鼠标坐标
+uniform samplerXX iChannel0..3;          // 输入的纹理 比如我们从一张图片上采用颜色
+uniform vec4      iDate;                 // 日期 年月日 不管
+uniform float     iSampleRate;           // 声音采样 不管
+
+

2、入口函数mainImage

+
void mainImage(out vec4 fragColor, in vec2 fragCoord )
+{
+    fragColor = vec4(1.);
+}
+
+

方法的第一个参数fragColor,是一个vec4类型的变量,表示最后输出的颜色值。
方法的第二个参数fragCoord,是一个vec2类型的变量,表示输入的像素坐标。

+

三、在cesium中如何使用

+

shadertoy上的着色器是在一个canvas画布上进行工作的,要移植到Cesium中,我们需要找一个载体来替代canvas。我们知道,Cesium绘制几何图形可以通过Entity和Primitive两种方式,那么只有Primitive+Appearance比较合适了,关于Primitive的使用及介绍,可以观看前面的章节。要将着色器移植到Cesium中,我们先来重点看看shadertoy上的shader着色器需要用到的参数。以下面这个例子讲解https://www.shadertoy.com/view/XdlSDs
在这里插入图片描述

+

glsl代码:

+
void mainImage(out vec4 fragColor, in vec2 fragCoord )
+{
+    vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
+    float tau = 3.1415926535*2.0;
+    float a = atan(p.x,p.y);
+    float r = length(p)*0.75;
+    vec2 uv = vec2(a/tau,r);
+
+    //get the color
+    float xCol = (uv.x - (iTime / 3.0)) * 3.0;
+    xCol = mod(xCol, 3.0);
+    vec3 horColour = vec3(0.25, 0.25, 0.25);
+
+    if (xCol < 1.0) {
+
+        horColour.r += 1.0 - xCol;
+        horColour.g += xCol;
+    }
+    else if (xCol < 2.0) {
+
+        xCol -= 1.0;
+        horColour.g += 1.0 - xCol;
+        horColour.b += xCol;
+    }
+    else {
+
+        xCol -= 2.0;
+        horColour.b += 1.0 - xCol;
+        horColour.r += xCol;
+    }
+
+    // draw color beam
+    uv = (2.0 * uv) - 1.0;
+    float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));
+    vec3 horBeam = vec3(beamWidth);
+    fragColor = vec4((( horBeam) * horColour), 1.0);
+}
+
+

a、首先是fragCoord,前面介绍过,fragCoord表示当前处理的像素坐标,是一个vec2类型,fragCoord.x范围为(0,画布宽度),fragCoord.y范围为(0,画布高度)。
b、其次是iResolution,iResolution代表的是当前画布的宽高,即绘图区域的尺寸,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。
c、然后我们还在代码中看到有个iTime,该参数代表当前运行的时间,一般用来实现动画,因为您会发现大多数shader的效果都是动态的。
d、最后是输出结果fragColor,代表最后计算的颜色输出值,在Cesium中为out_FragColor。

+

接下来介绍在Cesium如何获取对应的参数:

+

a、fragCoord在Cesium有个gl_FragCoord与之对应,这是一个WebGL内置的变量。
b、iResolution在Cesium有个czm_viewport与之对应,不过使用时采用zw分量即 czm_viewport.zw
c、iTime在Cesium中没有对应的变量,我们可以通过变量的方式传递一个参数,然后在渲染时不断修改该值,不过这种方式略显麻烦,在Cesium中我们可以用float iTime=czm_frameNumber/100.来模拟,czm_frameNumber代表当前帧,是一个自增长的数值,所以可以用来模拟时间不断地增长。

+

接下来我们实操一下,在Cesium中实现该shader的效果:

+

1、首先我们创建一个Primitive并添加到sene中

+
let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521;
+let rect = new Cesium.Rectangle(Cesium.Math.toRadians(xMin), Cesium.Math.toRadians(yMin), Cesium.Math.toRadians(xMax), Cesium.Math.toRadians(yMax));
+const rectangle = new Cesium.RectangleGeometry({
+    rectangle: rect,
+    height: 10000.0,
+});
+const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
+viewer.scene.primitives.add(new Cesium.Primitive({
+    geometryInstances: new Cesium.GeometryInstance({
+        geometry: geometry
+    }), 
+}));
+
+

2、此时会发现什么也看不见,这是因为没有设置外观,我们创建一个默认的外观

+
let appearance = new Cesium.MaterialAppearance({
+     material: new Cesium.Material({
+         fabric: {
+             type: "Color",
+             uniforms: {
+                 color: Cesium.Color.RED
+             }
+         }
+     }), 
+ })
+ primitive.appearance = appearance;
+
+

在这里插入图片描述

+

3、接下来我们为外观添加片元着色器,并将shadertoy上的shader赋值给外观的片元着色器属性。

+

shadertoy上glsl代码:

+
 fragmentShaderSource: `  
+  void mainImage( out vec4 fragColor, in vec2 fragCoord )
+  {
+       vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
+      float tau = 3.1415926535*2.0;
+      float a = atan(p.x,p.y);
+      float r = length(p)*0.75;
+      vec2 uv = vec2(a/tau,r);
+
+      //get the color
+      float xCol = (uv.x - (iTime / 3.0)) * 3.0;
+      xCol = mod(xCol, 3.0);
+      vec3 horColour = vec3(0.25, 0.25, 0.25);
+
+      if (xCol < 1.0) {
+
+          horColour.r += 1.0 - xCol;
+          horColour.g += xCol;
+      }
+      else if (xCol < 2.0) {
+
+          xCol -= 1.0;
+          horColour.g += 1.0 - xCol;
+          horColour.b += xCol;
+      }
+      else {
+
+          xCol -= 2.0;
+          horColour.b += 1.0 - xCol;
+          horColour.r += xCol;
+      }
+
+      // draw color beam
+      uv = (2.0 * uv) - 1.0;
+      float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));
+      vec3 horBeam = vec3(beamWidth);
+      fragColor = vec4((( horBeam) * horColour), 1.0);
+  }
+   `
+
+

操作步骤:
a、首先我们需要修改着色器入口函数,即将mainImage修改为main,因为Appearance片元着色器的入口函数是main。
b、然后将输出结果的fragColor修改为out_FragColor。
c、最后我们按照上面说的替换掉fragCoord,fragCoord、iTime

+

我们需要的代码:

+
fragmentShaderSource: ` 
+   void main()
+   {
+       float iTime=czm_frameNumber/100.;
+       vec2 p = (2.0 * gl_FragCoord.xy-czm_viewport.zw)/czm_viewport.w;
+
+       float tau = 3.1415926535*2.0;
+       float a = atan(p.x,p.y);
+       float r = length(p)*0.75;
+       vec2 uv = vec2(a/tau,r);
+
+       //get the color
+       float xCol = (uv.x - (iTime / 3.0)) * 3.0;
+       xCol = mod(xCol, 3.0);
+       vec3 horColour = vec3(0.25, 0.25, 0.25);
+
+       if (xCol < 1.0) {
+
+           horColour.r += 1.0 - xCol;
+           horColour.g += xCol;
+       }
+       else if (xCol < 2.0) {
+
+           xCol -= 1.0;
+           horColour.g += 1.0 - xCol;
+           horColour.b += xCol;
+       }
+       else {
+
+           xCol -= 2.0;
+           horColour.b += 1.0 - xCol;
+           horColour.r += xCol;
+       }
+
+       // draw color beam
+       uv = (2.0 * uv) - 1.0;
+       float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));
+       vec3 horBeam = vec3(beamWidth);
+       out_FragColor = vec4((( horBeam) * horColour), 1.0);
+   }
+    `
+
+

在这里插入图片描述

+

但是移动地球我们会发现绘制的结果始终是在屏幕中心,这其实是一个正确的结果,因为这个示例在shadertoy上也是始终绘制在屏幕中心。现在我们需要将Primitive的几何体作为绘制的画布,上面我们是使用gl_FragCoord坐标来获取当前应该处理的像素,我们现在需要改变为Appearance的纹理坐标,通过Appearence的纹理坐标,计算当前Appearence上需要处理的像素。

+
vec2 p = (2.0 * gl_FragCoord.xy-czm_viewport.zw)/czm_viewport.w;
+
+

该行代码的意思是将绘图区的宽高转换到[-1,1]的一个区间中。而在Appearance的片元着色器中,相对于该Primitive对应的Geometry而言,绘图区的宽高已经被限制在了[0,1]的区间了,这可以由片元着色器的st推断,因为片元着色器的st一般就是[0,1]。现在我们改造一下代码,将绘图区限定到Appearance的纹理区间中

+
 vec2 p = 2.0 * v_st - 1.;//(2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
+
+

因为v_st区间是[0,1],所以我们的变换一下到[-1,1],运行结果如下
在这里插入图片描述

+

到这里我们已经成功将shadertoy上这个示例的shader移植到Cesium上的Primitve中

+

四、着色器使用技巧

+

上面示例的shader成功移植到Cesium中的Primitive上。分享2个在使用shadertoy上的shader时的技巧:

+

1、在Cesium中如何选择对应的载体作为画布
因为shadertoy上的shader类型canvas的绘制原理,是将canvas作为一个画布,在Cesium中我们可以选择Entity或Primtive来作为载体。又因为要方便操作片元着色器,所以我们选择了Primitive,但是Primitive中又有很多Geometry类型,那具体使用哪种Geometry呢?根据经验,最好选择像RectangleGeometry、PlaneGeomery这种比较规则的几何类型,因为shader绘图其实是根据纹理坐标来实现的,而这种规则的几何往往 它的纹理坐标也比较规则。

+

2、如何去除黑色背景
虽然我们已经成功将shader移植到Cesium中,但是黑色的背景着实有点丑,我们使用shader的初衷是为了好看、酷炫,这效果好像有点违背了我们的初衷。那我们该如何去除这个黑色的背景呢?我们可以分析一下这个黑色,其实黑色的值就是vec3(0,0,0),rgb三个分量越接近于0,就越黑,当然,这也代表着r+g+b约接近0,所以我们可以这样去消除黑色背景。

+
out_FragColor = vec4(color,color.r+color.g+color.g);
+
+

在这里插入图片描述

+

这样就可以了。

+

五、难度加深,带有输入纹理数据的着色器示例(应用)

+

实现一个shader上带有输入纹理数据的例子
在这里插入图片描述

+

按照 “在Cesium中如何使用” 一节的思路,我们先创建好Primitive、Appearance,然后将着色器代码拷贝进来并修改相关参数。

+
let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521;
+const rectangle = new Cesium.RectangleGeometry({
+    rectangle: rect,
+    height: 10000.0,
+});
+const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
+viewer.scene.primitives.add(new Cesium.Primitive({
+    geometryInstances: new Cesium.GeometryInstance({
+        geometry: geometry
+    }),
+    appearance: new Cesium.MaterialAppearance({
+       material:new Cesium.Material({
+        fabric: { 
+                uniforms: {
+                    image:"./texture.png"
+                }
+            }
+       })
+        ,
+        fragmentShaderSource: ` 
+        in vec3 v_positionEC; 
+        in vec3 v_normalEC; 
+        in vec2 v_st;
+
+        // Maximum number of cells a ripple can cross.
+        #define MAX_RADIUS 2
+
+        // Set to 1 to hash twice. Slower, but less patterns.
+        #define DOUBLE_HASH 0
+
+        // Hash functions shamefully stolen from:
+        // https://www.shadertoy.com/view/4djSRW
+        #define HASHSCALE1 .1031
+        #define HASHSCALE3 vec3(.1031, .1030, .0973)
+
+        float hash12(vec2 p)
+        {
+            vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1);
+            p3 += dot(p3, p3.yzx + 19.19);
+            return fract((p3.x + p3.y) * p3.z);
+        }
+
+        vec2 hash22(vec2 p)
+        {
+            vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3);
+            p3 += dot(p3, p3.yzx+19.19);
+            return fract((p3.xx+p3.yz)*p3.zy);
+
+        }
+
+        void main(  )
+        {
+
+            //float resolution = 10. * exp2(-3.*iMouse.x/iResolution.x);
+           // vec2 uv = fragCoord.xy / iResolution.y * resolution;
+            float resolution =20.;
+            vec2 uv = v_st * resolution;
+            vec2 p0 = floor(uv);
+
+            float iTime=czm_frameNumber/100.;
+
+            vec2 circles = vec2(0.);
+            for (int j = -MAX_RADIUS; j <= MAX_RADIUS; ++j)
+            {
+                for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i)
+                {
+                    vec2 pi = p0 + vec2(i, j);
+                    #if DOUBLE_HASH
+                    vec2 hsh = hash22(pi);
+                    #else
+                    vec2 hsh = pi;
+                    #endif
+                    vec2 p = pi + hash22(hsh);
+
+                    float t = fract(0.3*iTime + hash12(hsh));
+                    vec2 v = p - uv;
+                    float d = length(v) - (float(MAX_RADIUS) + 1.)*t;
+
+                    float h = 1e-3;
+                    float d1 = d - h;
+                    float d2 = d + h;
+                    float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1);
+                    float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2);
+                    circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t));
+                }
+            }
+            circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1));
+
+            float intensity = mix(0.01, 0.15, smoothstep(0.1, 0.6, abs(fract(0.05*iTime + 0.5)*2.-1.)));
+            vec3 n = vec3(circles, sqrt(1. - dot(circles, circles)));
+            vec3 color = texture(image_0, uv/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n, normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.);
+            out_FragColor = vec4(color, 1.0);
+        }
+    `
+    })
+}));
+
+

分析代码:

+
float resolution = 10. * exp2(-3.*iMouse.x/iResolution.x);
+vec2 uv = fragCoord.xy / iResolution.y * resolution;
+
+

意思是将uv转换到[0,x]的区间,在Cesium中应该这样写,我们先固定一个值

+
float resolution =20.;
+vec2 uv = v_st * resolution;
+
+

本节的重点是

+
vec3 color = texture(iChannel0, uv/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n,normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.);
+texture(iChannel0, uv/resolution - intensity*n.xy).rgb
+
+

从纹理中采样颜色值,这个iChannel0是sampler2D,在Cesium对应Cesium.Texture,不过我们可以直接传一张图片,Cesium会自动为我们封装成Cesium.Texture。将图片传递到着色器,这里我们采用Materail的属性uniforms,需要注意的是如果您在Appearance的片元着色器中使用Material中的uniforms参数值时,你必须在参数名的后面加上一个序号,比如你的第一个参数为在Material的uniforms中为image,那在Appearance的片元着色器中必须使用image_0,如下:

+
texture(image_0, uv/resolution - intensity*n.xy).rgb
+
+

在这里插入图片描述

+

六、Perlin-Worley噪声实现云图

+

shadertoy示例地址:https://www.shadertoy.com/view/3dVXDc

+

在这里插入图片描述

+

该示例使用了Perlin+Worley(柏林+沃利)噪声来实现云的效果,并且是先将结果绘制到一张Texture中,然后在主函数中根据纹理坐标读取纹理中的值。
1、首先是噪声函数,定义在Common中
在这里插入图片描述

+

2、然后是绘制到Texture中,过程在BufferA中
在这里插入图片描述

+

3、最后在主函数中调用
在这里插入图片描述

+

4、主函数中为了显示了各个噪声的结果,将画布拆分为了5份,我们可以注释掉一些不需要的结果显示,比如修改代码如下:

+
void mainImage( out vec4 fragColor, in vec2 fragCoord )
+{
+    vec2 st = fragCoord / iResolution.xy;
+    vec2 uv = fragCoord / iResolution.y;
+    st.x *= 5.; // 5 columns for different noises
+    uv -= .02 * iTime;
+
+    vec3 col = vec3(0.);
+
+    float perlinWorley = textureLod(iChannel0, uv * .5, 0.).x;
+
+    // worley fbms with different frequencies
+    vec3 worley = textureLod(iChannel0, uv, 0.).yzw;
+    float wfbm = worley.x * .625 +
+                 worley.y * .125 +
+                 worley.z * .25; 
+
+    // cloud shape modeled after the GPU Pro 7 chapter
+    float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.);
+    cloud = remap(cloud, .85, 1., 0., 1.); // fake cloud coverage
+
+    // if (st.x < 1.)
+    //     col += perlinWorley;
+    // else if(st.x < 2.)
+    //     col += worley.x;
+    // else if(st.x < 3.)
+    //    col += worley.y;
+    // else if(st.x < 4.)
+    //     col += worley.z;
+    // else if(st.x < 5.)
+        col += cloud;
+
+    // column dividers
+    // float div = smoothstep(.01, 0., abs(st.x - 1.));
+    // div += smoothstep(.01, 0., abs(st.x - 2.));
+    // div += smoothstep(.01, 0., abs(st.x - 3.));
+    // div += smoothstep(.01, 0., abs(st.x - 4.));
+
+    // col = mix(col, vec3(0., 0., .866), div);
+
+    fragColor = vec4(col,1.0);
+}
+
+	因为我们不需要绘制到Texture的步骤,所以需要合并BufferA和主函数的代码
+  uv -= .02 * iTime;
+    vec2 m = vec2(0.5);
+
+    vec4 col = vec4(0.);
+
+    float slices = 128.; // number of layers of the 3d texture
+    float freq = 4.;
+
+    float pfbm= mix(1., perlinfbm(vec3(uv, floor(m.y*slices)/slices), 4., 7), .5);
+    pfbm = abs(pfbm * 2. - 1.); // billowy perlin noise
+
+    col.g += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq);
+    col.b += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*2.);
+    col.a += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*4.);
+    col.r += remap(pfbm, 0., 1., col.g, 1.); // perlin-worley 
+
+
+    float perlinWorley =  col.r;
+
+    // worley fbms with different frequencies
+    vec3 worley = col.yzw;
+    float wfbm = worley.x * .625 +
+                 worley.y * .125 +
+                 worley.z * .25; 
+
+    // cloud shape modeled after the GPU Pro 7 chapter
+    float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.);
+    cloud = remap(cloud, .65, 1., 0., 1.); // fake cloud coverage
+
+    vec3 col_ = vec3(0.); 
+    col_ += cloud;
+
+

5、在cesium中如何实现:我们先创建好Primitive、Appearance,然后将着色器代码拷贝进来并修改相关参数

+
let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521;
+const rectangle = new Cesium.RectangleGeometry({
+    rectangle: rect,
+    height: 10000.0,
+});
+const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
+viewer.scene.primitives.add(new Cesium.Primitive({
+    geometryInstances: new Cesium.GeometryInstance({
+        geometry: geometry
+    }),
+    appearance: new Cesium.MaterialAppearance({
+       material:new Cesium.Material({
+        fabric: { 
+                uniforms: {
+                    image:"./texture.png"
+                }
+            }
+       })
+        ,
+           fragmentShaderSource: ` 
+            in vec3 v_positionEC;//顶点 相机(眼睛)坐标系 
+            in vec3 v_normalEC;//顶点法线 相机(眼睛)坐标系 
+            in vec2 v_st;//纹理坐标 uv
+            /**
+            This tab contains all the necessary noise functions required to model a cloud shape.
+            */
+
+            // Hash by David_Hoskins
+            #define UI0 1597334673U
+            #define UI1 3812015801U
+            #define UI2 uvec2(UI0, UI1)
+            #define UI3 uvec3(UI0, UI1, 2798796415U)
+            #define UIF (1.0 / float(0xffffffffU))
+
+            vec3 hash33(vec3 p)
+            {
+                uvec3 q = uvec3(ivec3(p)) * UI3;
+                q = (q.x ^ q.y ^ q.z)*UI3;
+                return -1. + 2. * vec3(q) * UIF;
+            }
+
+            float remap(float x, float a, float b, float c, float d)
+            {
+                return (((x - a) / (b - a)) * (d - c)) + c;
+            }
+
+            // Gradient noise by iq (modified to be tileable)
+            float gradientNoise(vec3 x, float freq)
+            {
+                // grid
+                vec3 p = floor(x);
+                vec3 w = fract(x);
+
+                // quintic interpolant
+                vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.);
+
+
+                // gradients
+                vec3 ga = hash33(mod(p + vec3(0., 0., 0.), freq));
+                vec3 gb = hash33(mod(p + vec3(1., 0., 0.), freq));
+                vec3 gc = hash33(mod(p + vec3(0., 1., 0.), freq));
+                vec3 gd = hash33(mod(p + vec3(1., 1., 0.), freq));
+                vec3 ge = hash33(mod(p + vec3(0., 0., 1.), freq));
+                vec3 gf = hash33(mod(p + vec3(1., 0., 1.), freq));
+                vec3 gg = hash33(mod(p + vec3(0., 1., 1.), freq));
+                vec3 gh = hash33(mod(p + vec3(1., 1., 1.), freq));
+
+                // projections
+                float va = dot(ga, w - vec3(0., 0., 0.));
+                float vb = dot(gb, w - vec3(1., 0., 0.));
+                float vc = dot(gc, w - vec3(0., 1., 0.));
+                float vd = dot(gd, w - vec3(1., 1., 0.));
+                float ve = dot(ge, w - vec3(0., 0., 1.));
+                float vf = dot(gf, w - vec3(1., 0., 1.));
+                float vg = dot(gg, w - vec3(0., 1., 1.));
+                float vh = dot(gh, w - vec3(1., 1., 1.));
+
+                // interpolation
+                return va + 
+                       u.x * (vb - va) + 
+                       u.y * (vc - va) + 
+                       u.z * (ve - va) + 
+                       u.x * u.y * (va - vb - vc + vd) + 
+                       u.y * u.z * (va - vc - ve + vg) + 
+                       u.z * u.x * (va - vb - ve + vf) + 
+                       u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh);
+            }
+
+            // Tileable 3D worley noise
+            float worleyNoise(vec3 uv, float freq)
+            {    
+                vec3 id = floor(uv);
+                vec3 p = fract(uv);
+
+                float minDist = 10000.;
+                for (float x = -1.; x <= 1.; ++x)
+                {
+                    for(float y = -1.; y <= 1.; ++y)
+                    {
+                        for(float z = -1.; z <= 1.; ++z)
+                        {
+                            vec3 offset = vec3(x, y, z);
+                            vec3 h = hash33(mod(id + offset, vec3(freq))) * .5 + .5;
+                            h += offset;
+                            vec3 d = p - h;
+                               minDist = min(minDist, dot(d, d));
+                        }
+                    }
+                }
+
+                // inverted worley noise
+                return 1. - minDist;
+            }
+
+            // Fbm for Perlin noise based on iq's blog
+            float perlinfbm(vec3 p, float freq, int octaves)
+            {
+                float G = exp2(-.85);
+                float amp = 1.;
+                float noise = 0.;
+                for (int i = 0; i < octaves; ++i)
+                {
+                    noise += amp * gradientNoise(p * freq, freq);
+                    freq *= 2.;
+                    amp *= G;
+                }
+
+                return noise;
+            }
+
+            // Tileable Worley fbm inspired by Andrew Schneider's Real-Time Volumetric Cloudscapes
+            // chapter in GPU Pro 7.
+            float worleyFbm(vec3 p, float freq)
+            {
+                return worleyNoise(p*freq, freq) * .625 +
+                         worleyNoise(p*freq*2., freq*2.) * .25 +
+                         worleyNoise(p*freq*4., freq*4.) * .125;
+            }
+
+
+            void main(  )
+            {
+                vec2 uv =  v_st;
+                float iTime=czm_frameNumber/100.;
+                uv -= .02 * iTime;
+                vec2 m = vec2(0.5);
+
+                vec4 col = vec4(0.);
+
+                float slices = 128.; // number of layers of the 3d texture
+                float freq = 4.;
+
+                float pfbm= mix(1., perlinfbm(vec3(uv, floor(m.y*slices)/slices), 4., 7), .5);
+                pfbm = abs(pfbm * 2. - 1.); // billowy perlin noise
+
+                col.g += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq);
+                col.b += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*2.);
+                col.a += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*4.);
+                col.r += remap(pfbm, 0., 1., col.g, 1.); // perlin-worley 
+
+
+                float perlinWorley =  col.r;
+
+                // worley fbms with different frequencies
+                vec3 worley = col.yzw;
+                float wfbm = worley.x * .625 +
+                             worley.y * .125 +
+                             worley.z * .25; 
+
+                // cloud shape modeled after the GPU Pro 7 chapter
+                float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.);
+                cloud = remap(cloud, .65, 1., 0., 1.); // fake cloud coverage
+
+                vec3 col_ = vec3(0.); 
+                col_ += cloud;  
+
+                out_FragColor = vec4(col_,col.r); `
+    })
+}));
+
+

这样就实现了体积云类似效果
在这里插入图片描述

+

七、流体水面
示例地址:https://www.shadertoy.com/view/4dd3Rl
在这里插入图片描述

+

取到代码在cesium中如何使用参考上面体积云的示例,步骤相同。

+
+ + +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ + + + +
+
+
+
+ +
+ +
+ 02-20 + + 8045 + +
+
+
+ +
+
+
+ + + + + +
+ + + +
+
+ +
+ +
+ +
+ +
+
+
+
+
+
+
+ 评论 +
+
+
+
+ + + +
+
+ +
+ +
+
+ 成就一亿技术人! +
+
+ 拼手气红包6.0元 +
+
+
+
+
+ 还能输入1000个字符 +
+
+   +
+
+
+ 红包 + 添加红包 +
+
+ 表情包 + 插入表情 +
+
+
+
+
+ 表情包 + 代码片 +
+ +
+
+
+ + + + + + + +
+
+
+
+
+
+
+
+
+  条评论被折叠 查看 +
+
+ +
+
+
+
+
被折叠的  条评论 + 为什么被折叠? + + 到【灌水乐园】发言 +
+
+ +
+
+
+
+
+ 添加红包 + +
+
+
+ +
+ + +
+

请填写红包祝福语或标题

+
+
+ +
+ + +
+

红包个数最小为10个

+
+
+ +
+ + +
+

红包金额最低5元

+
+
+ +
+ 当前余额3.43元 + 前往充值 > +
+
+
+
+ 需支付:10.00元 +
+ + +
+
+
+
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+
+
+
+ +
成就一亿技术人!
+
+
+
+
+
+
+ 领取后你会自动成为博主和红包主的粉丝 + 规则 +
+
+
+
+
+
+ + + +
+
hope_wisdom
发出的红包 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

打赏作者

+
+
+ + + +
+
+

Cesium进阶学习

+

你的鼓励将是我创作的最大动力

+
+
+
+
+
+
+ ¥1 + ¥2 + ¥4 + ¥6 + ¥10 + ¥20 +
+
+
+
+
+ 扫码支付:¥1 +
+
+
+ + 获取中 +
+
+
+ + + 扫码支付 +
+
+
+
+

您的余额不足,请更换扫码支付或充值

+

打赏作者

+
+
+
+ +
+
实付
+ +
+
+
+ + 点击重新获取 +
+
+
扫码支付
+
+
+ + + + + + +
+
+ + 钱包余额 + 0 +
+ +
+
+

抵扣说明:

+

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

+
+
+
+
+ 余额充值 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shadertoy移植/20241203_143947.md b/shadertoy移植/20241203_143947.md new file mode 100644 index 0000000..adb4547 --- /dev/null +++ b/shadertoy移植/20241203_143947.md @@ -0,0 +1,663 @@ + + + + + + +**一、简介** + [shadertoy](https://www.shadertoy.com/)是一个基于webgl的分享Shader的开放平台,用户可以在上面根据既定规则分享自己编写的shader。在Cesium中要想实现一些酷炫的效果,唯一的一条路就是写shader,而shader的编写应该算是图形学中的难度天花板了。好在有很多shader大佬分享了自己编写的glsl效果,比如shadertoy网站上就是这些大牛们的作品,我们可以借鉴。 + ![在这里插入图片描述](20241203_143947.assets/c1eeb7716326293e03113f99c49eda30.png) + +**二、shadertoy着色器基本结构** + +shadertoy上的shader是纯2d绘图,没有几何顶点这些概念,它的绘图方式和canvas绘图方式很像,它将整个canvas作为绘图的画布,所以输入参数fragCoord的x值范围是(0,画布的宽度),fragCoord的y值范围是(0,画布的高度),画布的宽高在定义的输入参数中是iResolution,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。 + ![在这里插入图片描述](20241203_143947.assets/8103ee5541c006dfb125fbe2e78ed87d.png) + +如图所示,shadertoy上的shader示例最基本的着色器结构主要包括两个部分: + a、输入参数的定义 + b、着色器的入口函数 + +1、输入参数,通过uniform来定义外部的输入值。 + + uniform vec3 iResolution; // 视口分辨率,即画布的宽高 + uniform float iTime; // shader 的运行时间 秒 + uniform float iTimeDelta; // 渲染时间 秒 + uniform float iFrameRate; // shader 帧率 + uniform int iFrame; // shader 帧率 + uniform float iChannelTime[4]; // 频道运行时间 不管 + uniform vec3 iChannelResolution[4]; // 频道分辨率 不管 + uniform vec4 iMouse; // 鼠标坐标 + uniform samplerXX iChannel0..3; // 输入的纹理 比如我们从一张图片上采用颜色 + uniform vec4 iDate; // 日期 年月日 不管 + uniform float iSampleRate; // 声音采样 不管 + +2、入口函数mainImage + + void mainImage(out vec4 fragColor, in vec2 fragCoord ) + { + fragColor = vec4(1.); + } + +方法的第一个参数fragColor,是一个vec4类型的变量,表示最后输出的颜色值。 + 方法的第二个参数fragCoord,是一个vec2类型的变量,表示输入的像素坐标。 + +**三、在cesium中如何使用** + +shadertoy上的着色器是在一个canvas画布上进行工作的,要移植到Cesium中,我们需要找一个载体来替代canvas。我们知道,Cesium绘制几何图形可以通过Entity和Primitive两种方式,那么只有Primitive+Appearance比较合适了,关于Primitive的使用及介绍,可以观看前面的章节。要将着色器移植到Cesium中,我们先来重点看看shadertoy上的shader着色器需要用到的参数。以下面这个例子讲解https://www.shadertoy.com/view/XdlSDs + ![在这里插入图片描述](20241203_143947.assets/71d7b7a8f35a02471424f5185d0ecbdb.png) + +glsl代码: + + void mainImage(out vec4 fragColor, in vec2 fragCoord ) + { + vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y; + float tau = 3.1415926535*2.0; + float a = atan(p.x,p.y); + float r = length(p)*0.75; + vec2 uv = vec2(a/tau,r); + + //get the color + float xCol = (uv.x - (iTime / 3.0)) * 3.0; + xCol = mod(xCol, 3.0); + vec3 horColour = vec3(0.25, 0.25, 0.25); + + if (xCol < 1.0) { + + horColour.r += 1.0 - xCol; + horColour.g += xCol; + } + else if (xCol < 2.0) { + + xCol -= 1.0; + horColour.g += 1.0 - xCol; + horColour.b += xCol; + } + else { + + xCol -= 2.0; + horColour.b += 1.0 - xCol; + horColour.r += xCol; + } + + // draw color beam + uv = (2.0 * uv) - 1.0; + float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y)); + vec3 horBeam = vec3(beamWidth); + fragColor = vec4((( horBeam) * horColour), 1.0); + } + +a、首先是fragCoord,前面介绍过,fragCoord表示当前处理的像素坐标,是一个vec2类型,fragCoord.x范围为(0,画布宽度),fragCoord.y范围为(0,画布高度)。 + b、其次是iResolution,iResolution代表的是当前画布的宽高,即绘图区域的尺寸,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。 + c、然后我们还在代码中看到有个iTime,该参数代表当前运行的时间,一般用来实现动画,因为您会发现大多数shader的效果都是动态的。 + d、最后是输出结果fragColor,代表最后计算的颜色输出值,在Cesium中为out\_FragColor。 + +接下来介绍在Cesium如何获取对应的参数: + +a、fragCoord在Cesium有个gl\_FragCoord与之对应,这是一个WebGL内置的变量。 + b、iResolution在Cesium有个czm\_viewport与之对应,不过使用时采用zw分量即 czm\_viewport.zw + c、iTime在Cesium中没有对应的变量,我们可以通过变量的方式传递一个参数,然后在渲染时不断修改该值,不过这种方式略显麻烦,在Cesium中我们可以用float iTime=czm\_frameNumber/100.来模拟,czm\_frameNumber代表当前帧,是一个自增长的数值,所以可以用来模拟时间不断地增长。 + +接下来我们实操一下,在Cesium中实现该shader的效果: + +1、首先我们创建一个Primitive并添加到sene中 + + let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521; + let rect = new Cesium.Rectangle(Cesium.Math.toRadians(xMin), Cesium.Math.toRadians(yMin), Cesium.Math.toRadians(xMax), Cesium.Math.toRadians(yMax)); + const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10000.0, + }); + const geometry = Cesium.RectangleGeometry.createGeometry(rectangle); + viewer.scene.primitives.add(new Cesium.Primitive({ + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry + }), + })); + +2、此时会发现什么也看不见,这是因为没有设置外观,我们创建一个默认的外观 + + let appearance = new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + type: "Color", + uniforms: { + color: Cesium.Color.RED + } + } + }), + }) + primitive.appearance = appearance; + +![在这里插入图片描述](20241203_143947.assets/aa4fd912f61efc677780ff1378cd3d11.png) + +3、接下来我们为外观添加片元着色器,并将shadertoy上的shader赋值给外观的片元着色器属性。 + +shadertoy上glsl代码: + + fragmentShaderSource: ` + void mainImage( out vec4 fragColor, in vec2 fragCoord ) + { + vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y; + float tau = 3.1415926535*2.0; + float a = atan(p.x,p.y); + float r = length(p)*0.75; + vec2 uv = vec2(a/tau,r); + + //get the color + float xCol = (uv.x - (iTime / 3.0)) * 3.0; + xCol = mod(xCol, 3.0); + vec3 horColour = vec3(0.25, 0.25, 0.25); + + if (xCol < 1.0) { + + horColour.r += 1.0 - xCol; + horColour.g += xCol; + } + else if (xCol < 2.0) { + + xCol -= 1.0; + horColour.g += 1.0 - xCol; + horColour.b += xCol; + } + else { + + xCol -= 2.0; + horColour.b += 1.0 - xCol; + horColour.r += xCol; + } + + // draw color beam + uv = (2.0 * uv) - 1.0; + float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y)); + vec3 horBeam = vec3(beamWidth); + fragColor = vec4((( horBeam) * horColour), 1.0); + } + ` + +操作步骤: + a、首先我们需要修改着色器入口函数,即将mainImage修改为main,因为Appearance片元着色器的入口函数是main。 + b、然后将输出结果的fragColor修改为out\_FragColor。 + c、最后我们按照上面说的替换掉fragCoord,fragCoord、iTime + +我们需要的代码: + + fragmentShaderSource: ` + void main() + { + float iTime=czm_frameNumber/100.; + vec2 p = (2.0 * gl_FragCoord.xy-czm_viewport.zw)/czm_viewport.w; + + float tau = 3.1415926535*2.0; + float a = atan(p.x,p.y); + float r = length(p)*0.75; + vec2 uv = vec2(a/tau,r); + + //get the color + float xCol = (uv.x - (iTime / 3.0)) * 3.0; + xCol = mod(xCol, 3.0); + vec3 horColour = vec3(0.25, 0.25, 0.25); + + if (xCol < 1.0) { + + horColour.r += 1.0 - xCol; + horColour.g += xCol; + } + else if (xCol < 2.0) { + + xCol -= 1.0; + horColour.g += 1.0 - xCol; + horColour.b += xCol; + } + else { + + xCol -= 2.0; + horColour.b += 1.0 - xCol; + horColour.r += xCol; + } + + // draw color beam + uv = (2.0 * uv) - 1.0; + float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y)); + vec3 horBeam = vec3(beamWidth); + out_FragColor = vec4((( horBeam) * horColour), 1.0); + } + ` + +![在这里插入图片描述](20241203_143947.assets/b71065d007c4923af46f2406af5cca5b.gif) + +但是移动地球我们会发现绘制的结果始终是在屏幕中心,这其实是一个正确的结果,因为这个示例在shadertoy上也是始终绘制在屏幕中心。现在我们需要将Primitive的几何体作为绘制的画布,上面我们是使用gl\_FragCoord坐标来获取当前应该处理的像素,我们现在需要改变为Appearance的纹理坐标,通过Appearence的纹理坐标,计算当前Appearence上需要处理的像素。 + + vec2 p = (2.0 * gl_FragCoord.xy-czm_viewport.zw)/czm_viewport.w; + +该行代码的意思是将绘图区的宽高转换到[-1,1]的一个区间中。而在Appearance的片元着色器中,相对于该Primitive对应的Geometry而言,绘图区的宽高已经被限制在了[0,1]的区间了,这可以由片元着色器的st推断,因为片元着色器的st一般就是[0,1]。现在我们改造一下代码,将绘图区限定到Appearance的纹理区间中 + + vec2 p = 2.0 * v_st - 1.;//(2.0*fragCoord.xy-iResolution.xy)/iResolution.y; + +因为v\_st区间是[0,1],所以我们的变换一下到[-1,1],运行结果如下 + ![在这里插入图片描述](20241203_143947.assets/c7673cdb75556dab2dbdff9497328541.gif) + +到这里我们已经成功将shadertoy上这个示例的shader移植到Cesium上的Primitve中 + +**四、着色器使用技巧** + +上面示例的shader成功移植到Cesium中的Primitive上。分享2个在使用shadertoy上的shader时的技巧: + +1、在Cesium中如何选择对应的载体作为画布 + 因为shadertoy上的shader类型canvas的绘制原理,是将canvas作为一个画布,在Cesium中我们可以选择Entity或Primtive来作为载体。又因为要方便操作片元着色器,所以我们选择了Primitive,但是Primitive中又有很多Geometry类型,那具体使用哪种Geometry呢?根据经验,最好选择像RectangleGeometry、PlaneGeomery这种比较规则的几何类型,因为shader绘图其实是根据纹理坐标来实现的,而这种规则的几何往往 它的纹理坐标也比较规则。 + +2、如何去除黑色背景 + 虽然我们已经成功将shader移植到Cesium中,但是黑色的背景着实有点丑,我们使用shader的初衷是为了好看、酷炫,这效果好像有点违背了我们的初衷。那我们该如何去除这个黑色的背景呢?我们可以分析一下这个黑色,其实黑色的值就是vec3(0,0,0),rgb三个分量越接近于0,就越黑,当然,这也代表着r+g+b约接近0,所以我们可以这样去消除黑色背景。 + + out_FragColor = vec4(color,color.r+color.g+color.g); + +![在这里插入图片描述](20241203_143947.assets/09702a92331f297b923498f195ad37f6.gif) + +这样就可以了。 + +**五、难度加深,带有输入纹理数据的着色器示例(应用)** + +实现一个[shader](https://www.shadertoy.com/view/ldfyzl)上带有输入纹理数据的例子 + ![在这里插入图片描述](20241203_143947.assets/e9ff0716de4a7c4710989de8b24d3998.gif) + +按照 “在Cesium中如何使用” 一节的思路,我们先创建好Primitive、Appearance,然后将着色器代码拷贝进来并修改相关参数。 + + let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521; + const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10000.0, + }); + const geometry = Cesium.RectangleGeometry.createGeometry(rectangle); + viewer.scene.primitives.add(new Cesium.Primitive({ + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry + }), + appearance: new Cesium.MaterialAppearance({ + material:new Cesium.Material({ + fabric: { + uniforms: { + image:"./texture.png" + } + } + }) + , + fragmentShaderSource: ` + in vec3 v_positionEC; + in vec3 v_normalEC; + in vec2 v_st; + + // Maximum number of cells a ripple can cross. + #define MAX_RADIUS 2 + + // Set to 1 to hash twice. Slower, but less patterns. + #define DOUBLE_HASH 0 + + // Hash functions shamefully stolen from: + // https://www.shadertoy.com/view/4djSRW + #define HASHSCALE1 .1031 + #define HASHSCALE3 vec3(.1031, .1030, .0973) + + float hash12(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE1); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); + } + + vec2 hash22(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3); + p3 += dot(p3, p3.yzx+19.19); + return fract((p3.xx+p3.yz)*p3.zy); + + } + + void main( ) + { + + //float resolution = 10. * exp2(-3.*iMouse.x/iResolution.x); + // vec2 uv = fragCoord.xy / iResolution.y * resolution; + float resolution =20.; + vec2 uv = v_st * resolution; + vec2 p0 = floor(uv); + + float iTime=czm_frameNumber/100.; + + vec2 circles = vec2(0.); + for (int j = -MAX_RADIUS; j <= MAX_RADIUS; ++j) + { + for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i) + { + vec2 pi = p0 + vec2(i, j); + #if DOUBLE_HASH + vec2 hsh = hash22(pi); + #else + vec2 hsh = pi; + #endif + vec2 p = pi + hash22(hsh); + + float t = fract(0.3*iTime + hash12(hsh)); + vec2 v = p - uv; + float d = length(v) - (float(MAX_RADIUS) + 1.)*t; + + float h = 1e-3; + float d1 = d - h; + float d2 = d + h; + float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); + float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); + circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t)); + } + } + circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1)); + + float intensity = mix(0.01, 0.15, smoothstep(0.1, 0.6, abs(fract(0.05*iTime + 0.5)*2.-1.))); + vec3 n = vec3(circles, sqrt(1. - dot(circles, circles))); + vec3 color = texture(image_0, uv/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n, normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.); + out_FragColor = vec4(color, 1.0); + } + ` + }) + })); + +分析代码: + + float resolution = 10. * exp2(-3.*iMouse.x/iResolution.x); + vec2 uv = fragCoord.xy / iResolution.y * resolution; + +意思是将uv转换到[0,x]的区间,在Cesium中应该这样写,我们先固定一个值 + + float resolution =20.; + vec2 uv = v_st * resolution; + +本节的重点是 + + vec3 color = texture(iChannel0, uv/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n,normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.); + texture(iChannel0, uv/resolution - intensity*n.xy).rgb + +从纹理中采样颜色值,这个iChannel0是sampler2D,在Cesium对应Cesium.Texture,不过我们可以直接传一张图片,Cesium会自动为我们封装成Cesium.Texture。将图片传递到着色器,这里我们采用Materail的属性uniforms,需要注意的是如果您在Appearance的片元着色器中使用Material中的uniforms参数值时,你必须在参数名的后面加上一个序号,比如你的第一个参数为在Material的uniforms中为image,那在Appearance的片元着色器中必须使用image\_0,如下: + + texture(image_0, uv/resolution - intensity*n.xy).rgb + +![在这里插入图片描述](20241203_143947.assets/63bdf501ba818cb309751c33730c63ac.gif) + +**六、Perlin-Worley噪声实现云图** + +shadertoy示例地址:https://www.shadertoy.com/view/3dVXDc + +![在这里插入图片描述](20241203_143947.assets/b75429109a7c276754ffb523df9e9d48.png) + +该示例使用了Perlin+Worley(柏林+沃利)噪声来实现云的效果,并且是先将结果绘制到一张Texture中,然后在主函数中根据纹理坐标读取纹理中的值。 + 1、首先是噪声函数,定义在Common中 + ![在这里插入图片描述](20241203_143947.assets/211bf10bbb9465b33d1ec278ab9184e3.png) + +2、然后是绘制到Texture中,过程在BufferA中 + ![在这里插入图片描述](20241203_143947.assets/6bab4d5963817d72a2e0418a5841e815.png) + +3、最后在主函数中调用 + ![在这里插入图片描述](20241203_143947.assets/2b47675426e7e025aa72c770126b795d.png) + +4、主函数中为了显示了各个噪声的结果,将画布拆分为了5份,我们可以注释掉一些不需要的结果显示,比如修改代码如下: + + void mainImage( out vec4 fragColor, in vec2 fragCoord ) + { + vec2 st = fragCoord / iResolution.xy; + vec2 uv = fragCoord / iResolution.y; + st.x *= 5.; // 5 columns for different noises + uv -= .02 * iTime; + + vec3 col = vec3(0.); + + float perlinWorley = textureLod(iChannel0, uv * .5, 0.).x; + + // worley fbms with different frequencies + vec3 worley = textureLod(iChannel0, uv, 0.).yzw; + float wfbm = worley.x * .625 + + worley.y * .125 + + worley.z * .25; + + // cloud shape modeled after the GPU Pro 7 chapter + float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.); + cloud = remap(cloud, .85, 1., 0., 1.); // fake cloud coverage + + // if (st.x < 1.) + // col += perlinWorley; + // else if(st.x < 2.) + // col += worley.x; + // else if(st.x < 3.) + // col += worley.y; + // else if(st.x < 4.) + // col += worley.z; + // else if(st.x < 5.) + col += cloud; + + // column dividers + // float div = smoothstep(.01, 0., abs(st.x - 1.)); + // div += smoothstep(.01, 0., abs(st.x - 2.)); + // div += smoothstep(.01, 0., abs(st.x - 3.)); + // div += smoothstep(.01, 0., abs(st.x - 4.)); + + // col = mix(col, vec3(0., 0., .866), div); + + fragColor = vec4(col,1.0); + } + 因为我们不需要绘制到Texture的步骤,所以需要合并BufferA和主函数的代码 + uv -= .02 * iTime; + vec2 m = vec2(0.5); + + vec4 col = vec4(0.); + + float slices = 128.; // number of layers of the 3d texture + float freq = 4.; + + float pfbm= mix(1., perlinfbm(vec3(uv, floor(m.y*slices)/slices), 4., 7), .5); + pfbm = abs(pfbm * 2. - 1.); // billowy perlin noise + + col.g += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq); + col.b += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*2.); + col.a += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*4.); + col.r += remap(pfbm, 0., 1., col.g, 1.); // perlin-worley + + float perlinWorley = col.r; + + // worley fbms with different frequencies + vec3 worley = col.yzw; + float wfbm = worley.x * .625 + + worley.y * .125 + + worley.z * .25; + + // cloud shape modeled after the GPU Pro 7 chapter + float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.); + cloud = remap(cloud, .65, 1., 0., 1.); // fake cloud coverage + + vec3 col_ = vec3(0.); + col_ += cloud; + +5、在cesium中如何实现:我们先创建好Primitive、Appearance,然后将着色器代码拷贝进来并修改相关参数 + + let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521; + const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10000.0, + }); + const geometry = Cesium.RectangleGeometry.createGeometry(rectangle); + viewer.scene.primitives.add(new Cesium.Primitive({ + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry + }), + appearance: new Cesium.MaterialAppearance({ + material:new Cesium.Material({ + fabric: { + uniforms: { + image:"./texture.png" + } + } + }) + , + fragmentShaderSource: ` + in vec3 v_positionEC;//顶点 相机(眼睛)坐标系 + in vec3 v_normalEC;//顶点法线 相机(眼睛)坐标系 + in vec2 v_st;//纹理坐标 uv + /** + This tab contains all the necessary noise functions required to model a cloud shape. + */ + + // Hash by David_Hoskins + #define UI0 1597334673U + #define UI1 3812015801U + #define UI2 uvec2(UI0, UI1) + #define UI3 uvec3(UI0, UI1, 2798796415U) + #define UIF (1.0 / float(0xffffffffU)) + + vec3 hash33(vec3 p) + { + uvec3 q = uvec3(ivec3(p)) * UI3; + q = (q.x ^ q.y ^ q.z)*UI3; + return -1. + 2. * vec3(q) * UIF; + } + + float remap(float x, float a, float b, float c, float d) + { + return (((x - a) / (b - a)) * (d - c)) + c; + } + + // Gradient noise by iq (modified to be tileable) + float gradientNoise(vec3 x, float freq) + { + // grid + vec3 p = floor(x); + vec3 w = fract(x); + + // quintic interpolant + vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.); + + // gradients + vec3 ga = hash33(mod(p + vec3(0., 0., 0.), freq)); + vec3 gb = hash33(mod(p + vec3(1., 0., 0.), freq)); + vec3 gc = hash33(mod(p + vec3(0., 1., 0.), freq)); + vec3 gd = hash33(mod(p + vec3(1., 1., 0.), freq)); + vec3 ge = hash33(mod(p + vec3(0., 0., 1.), freq)); + vec3 gf = hash33(mod(p + vec3(1., 0., 1.), freq)); + vec3 gg = hash33(mod(p + vec3(0., 1., 1.), freq)); + vec3 gh = hash33(mod(p + vec3(1., 1., 1.), freq)); + + // projections + float va = dot(ga, w - vec3(0., 0., 0.)); + float vb = dot(gb, w - vec3(1., 0., 0.)); + float vc = dot(gc, w - vec3(0., 1., 0.)); + float vd = dot(gd, w - vec3(1., 1., 0.)); + float ve = dot(ge, w - vec3(0., 0., 1.)); + float vf = dot(gf, w - vec3(1., 0., 1.)); + float vg = dot(gg, w - vec3(0., 1., 1.)); + float vh = dot(gh, w - vec3(1., 1., 1.)); + + // interpolation + return va + + u.x * (vb - va) + + u.y * (vc - va) + + u.z * (ve - va) + + u.x * u.y * (va - vb - vc + vd) + + u.y * u.z * (va - vc - ve + vg) + + u.z * u.x * (va - vb - ve + vf) + + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh); + } + + // Tileable 3D worley noise + float worleyNoise(vec3 uv, float freq) + { + vec3 id = floor(uv); + vec3 p = fract(uv); + + float minDist = 10000.; + for (float x = -1.; x <= 1.; ++x) + { + for(float y = -1.; y <= 1.; ++y) + { + for(float z = -1.; z <= 1.; ++z) + { + vec3 offset = vec3(x, y, z); + vec3 h = hash33(mod(id + offset, vec3(freq))) * .5 + .5; + h += offset; + vec3 d = p - h; + minDist = min(minDist, dot(d, d)); + } + } + } + + // inverted worley noise + return 1. - minDist; + } + + // Fbm for Perlin noise based on iq's blog + float perlinfbm(vec3 p, float freq, int octaves) + { + float G = exp2(-.85); + float amp = 1.; + float noise = 0.; + for (int i = 0; i < octaves; ++i) + { + noise += amp * gradientNoise(p * freq, freq); + freq *= 2.; + amp *= G; + } + + return noise; + } + + // Tileable Worley fbm inspired by Andrew Schneider's Real-Time Volumetric Cloudscapes + // chapter in GPU Pro 7. + float worleyFbm(vec3 p, float freq) + { + return worleyNoise(p*freq, freq) * .625 + + worleyNoise(p*freq*2., freq*2.) * .25 + + worleyNoise(p*freq*4., freq*4.) * .125; + } + + void main( ) + { + vec2 uv = v_st; + float iTime=czm_frameNumber/100.; + uv -= .02 * iTime; + vec2 m = vec2(0.5); + + vec4 col = vec4(0.); + + float slices = 128.; // number of layers of the 3d texture + float freq = 4.; + + float pfbm= mix(1., perlinfbm(vec3(uv, floor(m.y*slices)/slices), 4., 7), .5); + pfbm = abs(pfbm * 2. - 1.); // billowy perlin noise + + col.g += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq); + col.b += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*2.); + col.a += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*4.); + col.r += remap(pfbm, 0., 1., col.g, 1.); // perlin-worley + + float perlinWorley = col.r; + + // worley fbms with different frequencies + vec3 worley = col.yzw; + float wfbm = worley.x * .625 + + worley.y * .125 + + worley.z * .25; + + // cloud shape modeled after the GPU Pro 7 chapter + float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.); + cloud = remap(cloud, .65, 1., 0., 1.); // fake cloud coverage + + vec3 col_ = vec3(0.); + col_ += cloud; + + out_FragColor = vec4(col_,col.r); ` + }) + })); + +这样就实现了体积云类似效果 + ![在这里插入图片描述](20241203_143947.assets/e7a0064f7be091b39669a0d187bd687d.gif) + +**七、流体水面** + 示例地址:https://www.shadertoy.com/view/4dd3Rl + ![在这里插入图片描述](20241203_143947.assets/3b3a587355ac37226ff923d00a3b3501.png) + +取到代码在cesium中如何使用参考上面体积云的示例,步骤相同。 + + + \ No newline at end of file diff --git a/shadertoy移植/cloud.js b/shadertoy移植/cloud.js new file mode 100644 index 0000000..5879c3e --- /dev/null +++ b/shadertoy移植/cloud.js @@ -0,0 +1,190 @@ +const viewer = new Cesium.Viewer('cesiumContainer') + +let xMin = 115.894604, + yMin = 39.516896, + xMax = 117.431959, + yMax = 40.630521 +let rect = new Cesium.Rectangle( + Cesium.Math.toRadians(xMin), + Cesium.Math.toRadians(yMin), + Cesium.Math.toRadians(xMax), + Cesium.Math.toRadians(yMax) +) + +const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10000.0, +}) +const geometry = Cesium.RectangleGeometry.createGeometry(rectangle) +viewer.scene.primitives.add( + new Cesium.Primitive({ + asynchronous: false, + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry, + }), + appearance: new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + uniforms: { + image: './texture.png', + }, + }, + }), + fragmentShaderSource: ` + in vec3 v_positionEC;//顶点 相机(眼睛)坐标系 + in vec3 v_normalEC;//顶点法线 相机(眼睛)坐标系 + in vec2 v_st;//纹理坐标 uv + /** + This tab contains all the necessary noise functions required to model a cloud shape. + */ + + // Hash by David_Hoskins + #define UI0 1597334673U + #define UI1 3812015801U + #define UI2 uvec2(UI0, UI1) + #define UI3 uvec3(UI0, UI1, 2798796415U) + #define UIF (1.0 / float(0xffffffffU)) + + vec3 hash33(vec3 p) + { + uvec3 q = uvec3(ivec3(p)) * UI3; + q = (q.x ^ q.y ^ q.z)*UI3; + return -1. + 2. * vec3(q) * UIF; + } + + float remap(float x, float a, float b, float c, float d) + { + return (((x - a) / (b - a)) * (d - c)) + c; + } + + // Gradient noise by iq (modified to be tileable) + float gradientNoise(vec3 x, float freq) + { + // grid + vec3 p = floor(x); + vec3 w = fract(x); + + // quintic interpolant + vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.); + + // gradients + vec3 ga = hash33(mod(p + vec3(0., 0., 0.), freq)); + vec3 gb = hash33(mod(p + vec3(1., 0., 0.), freq)); + vec3 gc = hash33(mod(p + vec3(0., 1., 0.), freq)); + vec3 gd = hash33(mod(p + vec3(1., 1., 0.), freq)); + vec3 ge = hash33(mod(p + vec3(0., 0., 1.), freq)); + vec3 gf = hash33(mod(p + vec3(1., 0., 1.), freq)); + vec3 gg = hash33(mod(p + vec3(0., 1., 1.), freq)); + vec3 gh = hash33(mod(p + vec3(1., 1., 1.), freq)); + + // projections + float va = dot(ga, w - vec3(0., 0., 0.)); + float vb = dot(gb, w - vec3(1., 0., 0.)); + float vc = dot(gc, w - vec3(0., 1., 0.)); + float vd = dot(gd, w - vec3(1., 1., 0.)); + float ve = dot(ge, w - vec3(0., 0., 1.)); + float vf = dot(gf, w - vec3(1., 0., 1.)); + float vg = dot(gg, w - vec3(0., 1., 1.)); + float vh = dot(gh, w - vec3(1., 1., 1.)); + + // interpolation + return va + + u.x * (vb - va) + + u.y * (vc - va) + + u.z * (ve - va) + + u.x * u.y * (va - vb - vc + vd) + + u.y * u.z * (va - vc - ve + vg) + + u.z * u.x * (va - vb - ve + vf) + + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh); + } + + // Tileable 3D worley noise + float worleyNoise(vec3 uv, float freq) + { + vec3 id = floor(uv); + vec3 p = fract(uv); + + float minDist = 10000.; + for (float x = -1.; x <= 1.; ++x) + { + for(float y = -1.; y <= 1.; ++y) + { + for(float z = -1.; z <= 1.; ++z) + { + vec3 offset = vec3(x, y, z); + vec3 h = hash33(mod(id + offset, vec3(freq))) * .5 + .5; + h += offset; + vec3 d = p - h; + minDist = min(minDist, dot(d, d)); + } + } + } + + // inverted worley noise + return 1. - minDist; + } + + // Fbm for Perlin noise based on iq's blog + float perlinfbm(vec3 p, float freq, int octaves) + { + float G = exp2(-.85); + float amp = 1.; + float noise = 0.; + for (int i = 0; i < octaves; ++i) + { + noise += amp * gradientNoise(p * freq, freq); + freq *= 2.; + amp *= G; + } + + return noise; + } + + // Tileable Worley fbm inspired by Andrew Schneider's Real-Time Volumetric Cloudscapes + // chapter in GPU Pro 7. + float worleyFbm(vec3 p, float freq) + { + return worleyNoise(p*freq, freq) * .625 + + worleyNoise(p*freq*2., freq*2.) * .25 + + worleyNoise(p*freq*4., freq*4.) * .125; + } + + void main( ) + { + vec2 uv = v_st; + float iTime=czm_frameNumber/100.; + uv -= .02 * iTime; + vec2 m = vec2(0.5); + + vec4 col = vec4(0.); + + float slices = 128.; // number of layers of the 3d texture + float freq = 4.; + + float pfbm= mix(1., perlinfbm(vec3(uv, floor(m.y*slices)/slices), 4., 7), .5); + pfbm = abs(pfbm * 2. - 1.); // billowy perlin noise + + col.g += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq); + col.b += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*2.); + col.a += worleyFbm(vec3(uv, floor(m.y*slices)/slices), freq*4.); + col.r += remap(pfbm, 0., 1., col.g, 1.); // perlin-worley + + float perlinWorley = col.r; + + // worley fbms with different frequencies + vec3 worley = col.yzw; + float wfbm = worley.x * .625 + + worley.y * .125 + + worley.z * .25; + + // cloud shape modeled after the GPU Pro 7 chapter + float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.); + cloud = remap(cloud, .65, 1., 0., 1.); // fake cloud coverage + + vec3 col_ = vec3(0.); + col_ += cloud; + + out_FragColor = vec4(col_,col.r); }`, + }), + }) +) diff --git a/shadertoy移植/rain.js b/shadertoy移植/rain.js new file mode 100644 index 0000000..1fff3f7 --- /dev/null +++ b/shadertoy移植/rain.js @@ -0,0 +1,110 @@ +const viewer = new Cesium.Viewer('cesiumContainer') + +let xMin = 123.894604, + yMin = 34.516896, + xMax = 125.431959, + yMax = 35.630521 +let rect = new Cesium.Rectangle( + Cesium.Math.toRadians(xMin), + Cesium.Math.toRadians(yMin), + Cesium.Math.toRadians(xMax), + Cesium.Math.toRadians(yMax) +) +const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10.0, +}) +const geometry = Cesium.RectangleGeometry.createGeometry(rectangle) +viewer.scene.primitives.add( + new Cesium.Primitive({ + asynchronous: false, + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry, + }), + appearance: new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + uniforms: { + image: + 'https://png.pngtree.com/png-vector/20240611/ourmid/pngtree-decorative-dividing-horizontal-line-with-star-shape-vector-png-image_12658779.png', + }, + }, + }), + fragmentShaderSource: ` + in vec3 v_positionEC; + in vec3 v_normalEC; + in vec2 v_st; + + // Maximum number of cells a ripple can cross. + #define MAX_RADIUS 2 + + // Set to 1 to hash twice. Slower, but less patterns. + #define DOUBLE_HASH 0 + + // Hash functions shamefully stolen from: + // https://www.shadertoy.com/view/4djSRW + #define HASHSCALE1 .1031 + #define HASHSCALE3 vec3(.1031, .1030, .0973) + + float hash12(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE1); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); + } + + vec2 hash22(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3); + p3 += dot(p3, p3.yzx+19.19); + return fract((p3.xx+p3.yz)*p3.zy); + + } + + void main( ) + { + + //float resolution = 10. * exp2(-3.*iMouse.x/iResolution.x); + // vec2 uv = fragCoord.xy / iResolution.y * resolution; + float resolution =20.; + vec2 uv = v_st * resolution; + vec2 p0 = floor(uv); + + float iTime=czm_frameNumber/100.; + + vec2 circles = vec2(0.); + for (int j = -MAX_RADIUS; j <= MAX_RADIUS; ++j) + { + for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i) + { + vec2 pi = p0 + vec2(i, j); + #if DOUBLE_HASH + vec2 hsh = hash22(pi); + #else + vec2 hsh = pi; + #endif + vec2 p = pi + hash22(hsh); + + float t = fract(0.3*iTime + hash12(hsh)); + vec2 v = p - uv; + float d = length(v) - (float(MAX_RADIUS) + 1.)*t; + + float h = 1e-3; + float d1 = d - h; + float d2 = d + h; + float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); + float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); + circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t)); + } + } + circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1)); + + float intensity = mix(0.01, 0.15, smoothstep(0.1, 0.6, abs(fract(0.05*iTime + 0.5)*2.-1.))); + vec3 n = vec3(circles, sqrt(1. - dot(circles, circles))); + vec3 color = texture(image_0, uv/resolution - intensity*n.xy).rgb + 5.*pow(clamp(dot(n, normalize(vec3(1., 0.7, 0.5))), 0., 1.), 6.); + out_FragColor = vec4(color, color.r+color.g+color.b); + } + `, + }), + }) +) diff --git a/shadertoy移植/test.js b/shadertoy移植/test.js new file mode 100644 index 0000000..0aae300 --- /dev/null +++ b/shadertoy移植/test.js @@ -0,0 +1,87 @@ +const viewer = new Cesium.Viewer('cesiumContainer') + +const shader = ` +in vec2 v_st; +void main() + { + float iTime = czm_frameNumber/100.; + vec2 p = 2.0 * v_st - 1.; + // vec2 p = (2.0 * gl_FragCoord.xy-czm_viewport.zw)/czm_viewport.w; + + float tau = 3.1415926535*2.0; + float a = atan(p.x,p.y); + float r = length(p)*0.75; + vec2 uv = vec2(a/tau,r); + + //get the color + float xCol = (uv.x - (iTime / 3.0)) * 3.0; + xCol = mod(xCol, 3.0); + vec3 horColour = vec3(0.25, 0.25, 0.25); + + if (xCol < 1.0) { + + horColour.r += 1.0 - xCol; + horColour.g += xCol; + } + else if (xCol < 2.0) { + + xCol -= 1.0; + horColour.g += 1.0 - xCol; + horColour.b += xCol; + } + else { + + xCol -= 2.0; + horColour.b += 1.0 - xCol; + horColour.r += xCol; + } + + // draw color beam + uv = (2.0 * uv) - 1.0; + float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y)); + vec3 horBeam = vec3(beamWidth); + //out_FragColor = vec4((( horBeam) * horColour), 1.0); + vec3 color = (horBeam) * horColour; + out_FragColor = vec4(color,color.r+color.g+color.b); + + }` +let xMin = 115, + yMin = 39, + xMax = 117, + yMax = 41 +let rect = new Cesium.Rectangle( + Cesium.Math.toRadians(xMin), + Cesium.Math.toRadians(yMin), + Cesium.Math.toRadians(xMax), + Cesium.Math.toRadians(yMax) +) + +const rectangle = new Cesium.RectangleGeometry({ + rectangle: rect, + height: 10000.0, +}) +const geometry = Cesium.RectangleGeometry.createGeometry(rectangle) + +let appearance = new Cesium.MaterialAppearance({ + material: new Cesium.Material({ + fabric: { + type: 'Color', + uniforms: { + color: Cesium.Color.RED, + }, + }, + }), + fragmentShaderSource: shader, +}) + +const primitive = new Cesium.Primitive({ + appearance: appearance, + geometryInstances: new Cesium.GeometryInstance({ + geometry: geometry, + }), + asynchronous: false, +}) + +viewer.scene.primitives.add(primitive) + +// primitive.appearance = appearance;