This commit is contained in:
严争鸣 2024-12-09 14:57:06 +08:00
commit 36b5eb0abb
21 changed files with 2864 additions and 0 deletions

93
README.md Normal file
View File

@ -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.

Binary file not shown.

After

(image error) Size: 667 KiB

Binary file not shown.

After

(image error) Size: 128 KiB

Binary file not shown.

After

(image error) Size: 122 KiB

Binary file not shown.

After

(image error) Size: 333 KiB

Binary file not shown.

After

(image error) Size: 1.2 MiB

Binary file not shown.

After

(image error) Size: 81 KiB

Binary file not shown.

After

(image error) Size: 202 KiB

Binary file not shown.

After

(image error) Size: 950 KiB

Binary file not shown.

After

(image error) Size: 733 KiB

Binary file not shown.

After

(image error) Size: 472 KiB

Binary file not shown.

After

(image error) Size: 552 KiB

Binary file not shown.

After

(image error) Size: 498 KiB

Binary file not shown.

After

(image error) Size: 620 KiB

Binary file not shown.

After

(image error) Size: 5.7 MiB

Binary file not shown.

After

(image error) Size: 179 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,663 @@
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-704d5b9767.css">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
**一、简介**
[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、其次是iResolutioniResolution代表的是当前画布的宽高即绘图区域的尺寸所以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、最后我们按照上面说的替换掉fragCoordfragCoord、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中如何使用参考上面体积云的示例步骤相同。
<link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-f23dff6052.css" rel="stylesheet">
<link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-e504d6a974.css" rel="stylesheet">

190
shadertoy移植/cloud.js Normal file
View File

@ -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); }`,
}),
})
)

110
shadertoy移植/rain.js Normal file
View File

@ -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);
}
`,
}),
})
)

87
shadertoy移植/test.js Normal file
View File

@ -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;