使用 WebGL 为 HTML5 游戏创建逼真的地形

这篇具有很好参考价值的文章主要介绍了使用 WebGL 为 HTML5 游戏创建逼真的地形。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

推荐:使用 NSDT场景编辑器快速搭建3D应用场景

建 模 和 3D 地形

大多数 3D 对象是 使用建模工具创建,这是有充分理由的。创建复杂对象 (如飞机甚至建筑物)很难在代码中完成。建模工具 几乎总是有意义的,但也有例外!其中之一可能是案例 就像飞行拱廊岛连绵起伏的丘陵一样。我们最终使用了 我们发现更简单,甚至可能更直观的技术:一个 高度图。

高度图是一种 使用常规二维图像来描述 像岛屿或其他地形一样的表面。这是一种非常常见的使用方式 高程数据,不仅在游戏中,而且在地理信息系统中 制图师和地质学家使用的 (GIS)。

帮助您获得想法 有关其工作原理,请查看此交互式演示中的高度图。尝试绘图 ,然后检出生成的地形。

使用 WebGL 为 HTML5 游戏创建逼真的地形,webgl,html5,游戏

高度图背后的概念 很简单。在上图所示的图像中,纯黑色是 “地板”和纯白色是最高峰。介于两者之间的灰度颜色 表示相应的高程。这为我们提供了 256 个海拔高度,这 是我们游戏的大量细节。实际应用程序可能会使用完整的 色谱可存储更多层次的细节(2564 = 4,294,967,296 级 详细信息(如果包含 Alpha 通道)。

高度图有几个 与传统多边形网格相比的优势:

一、高度图很多 更紧凑。仅存储最重要的数据(高程)。它 需要以编程方式转换为 3D 对象,但这是 经典交易:您现在节省空间,稍后通过计算付款。通过存储 数据即图像,您将获得另一个空间优势:您可以利用标准 图像压缩技术并使数据变小(相比之下)!

其次,高度图是一个 生成、可视化和编辑地形的便捷方式。非常直观 当你看到一个。感觉有点像看地图。这被证明是 对飞行街机特别有用。我们设计和编辑了我们的岛屿 在 Photoshop 中!这使得根据需要进行小调整变得非常简单。 例如,当我们想确保跑道完全平坦时, 我们只是确保以单一颜色在该区域上绘画。

您可以看到高度图 下面的飞行拱廊。看看你是否能发现我们为 跑道和村庄。

使用 WebGL 为 HTML5 游戏创建逼真的地形,webgl,html5,游戏

飞行街机岛的高度图。它是在Photoshop中创建的,它基于着名的太平洋岛链中的“大岛”。有什么猜测吗?

使用 WebGL 为 HTML5 游戏创建逼真的地形,webgl,html5,游戏

在解码高度贴图后映射到生成的 3D 网格上的纹理。更多内容见下文。

解码高度图

我们用Babylon.js建造了飞行拱廊,Babylon给了我们一个漂亮的 从高度图到 3D 的简单路径。Babylon提供了一个 API 来生成 来自高度图图像的网格几何体:

1
var ground = BABYLON.Mesh.CreateGroundFromHeightMap(
2
 
3
    'your-mesh-name',
4
 
5
    '/path/to/heightmap.png',
6
 
7
    100, // width of the ground mesh (x axis) 
8
 
9
    100, // depth of the ground mesh (z axis) 
10
 
11
    40,  // number of subdivisions 
12
 
13
    0,   // min height 
14
 
15
    50,  // max height 
16
 
17
    scene,
18
 
19
    false, // updateable? 
20
 
21
    null // callback when mesh is ready 
22
 
23
);

细节量是 由该细分的财产决定。需要注意的是, 参数是指高度图两侧的细分数量 图像,而不是单元格总数。所以稍微增加这个数字可以 对网格中的顶点总数有很大影响。

  • 20 个细分 = 400 细胞
  • 50 个细分 = 2,500 细胞
  • 100 个细分 = 10,000 细胞
  • 500 个细分 = 250,000 细胞
  • 1,000 个细分 = 1,000,000 细胞

在下一节中,我们将 了解如何为地面设置纹理,但在尝试使用高度贴图时 创建时,查看线框很有用。这是应用简单代码 线框纹理,因此很容易看到高度图数据是如何转换为的 网格的顶点:

1
// simple wireframe material 
2
 
3
var material = new BABYLON.StandardMaterial('ground-material', scene);
4
 
5
material.wireframe = true;
6
 
7
ground.material = material;

创建纹理细节

一旦我们有一个模型,映射一个 质地相对简单。对于飞行街机,我们简单地创建了一个 非常大的图像,与我们的高度图中的岛屿相匹配。图像得到 延伸到地形的轮廓上,所以纹理和高度图 保持相关性。这真的很容易想象,再一次,所有 制作工作是在Photoshop中完成的。

原始纹理图像是 创建于 4096x4096。那可是挺大的!(我们最终将尺寸减小了 为了保持下载合理,级别到2048x2048,但所有 使用全尺寸图像进行开发。这是来自 原始纹理。

使用 WebGL 为 HTML5 游戏创建逼真的地形,webgl,html5,游戏

这些矩形表示 岛上城镇的建筑。我们很快注意到 我们可以在地形和 其他 3D 模型。即使使用我们巨大的岛屿纹理,区别在于 令人分心的明显!

为了解决这个问题,我们“混合” 以随机噪声的形式进入地形纹理的附加细节。您可以 请参阅下面的之前和之后。注意额外的噪点如何增强外观 地形细节。

使用 WebGL 为 HTML5 游戏创建逼真的地形,webgl,html5,游戏

我们创建了一个自定义着色器 添加噪音。着色器为您提供了对 WebGL 3D 场景的渲染,这是着色器如何 有用。

WebGL着色器由两个组成 主要部分:顶点和片段着色器。顶点的主要目标 着色器是将顶点映射到渲染帧中的某个位置。片段(或 像素)着色器控制像素的结果颜色。

着色器是用 称为GLSL(图形库着色器语言)的高级语言,它 类似于C。此代码在 GPU 上执行。深入了解如何 着色器工作,请参阅此处 有关如何为 Babylon.js 创建自己的自定义着色器的教程,或参阅此图形着色器编码初学者指南。

顶点着色器

我们不会改变我们的 纹理映射到地面网格体,因此我们的顶点着色器非常简单。 它只是计算标准映射并分配目标位置。

1
precision mediump float;
2
 
3
 
4
 
5
// Attributes 
6
 
7
attribute vec3 position;
8
 
9
attribute vec3 normal;
10
 
11
attribute vec2 uv;
12
 
13
 
14
 
15
// Uniforms 
16
 
17
uniform mat4 worldViewProjection;
18
 
19
 
20
 
21
// Varying 
22
 
23
varying vec4 vPosition;
24
 
25
varying vec3 vNormal;
26
 
27
varying vec2 vUV;
28
 
29
 
30
 
31
void main() {
32
 
33
 
34
 
35
    vec4 p = vec4( position, 1.0 );
36
 
37
    vPosition = p;
38
 
39
    vNormal = normal;
40
 
41
    vUV = uv;
42
 
43
    gl_Position = worldViewProjection * p;
44
 
45
}

碎片着色器

我们的片段着色器有点 更复杂。它结合了两个不同的图像:基础图像和混合图像。 基础图像映射到整个地面网格。在飞行街机中,这个 是岛屿的彩色图像。混合图像是使用的小噪点图像 在近距离为地面提供一些纹理和细节。着色器 组合每个图像中的值以创建跨 岛。

飞行的最后一课 街机发生在有雾的日子,所以我们的像素着色器的另一个任务是 调整颜色以模拟雾。调整基于顶点的距离 来自相机,远处像素被“遮挡”得更厉害 在雾中。您将在函数中看到此距离计算 在主着色器代码上方。calcFogFactor

1
#ifdef GL_ES 
2
 
3
precision highp float;
4
 
5
#endif 
6
 
7
 
8
 
9
uniform mat4 worldView;
10
 
11
varying vec4 vPosition;
12
 
13
varying vec3 vNormal;
14
 
15
varying vec2 vUV;
16
 
17
 
18
 
19
// Refs 
20
 
21
uniform sampler2D baseSampler;
22
 
23
uniform sampler2D blendSampler;
24
 
25
uniform float blendScaleU;
26
 
27
uniform float blendScaleV;
28
 
29
 
30
 
31
#define FOGMODE_NONE 0. 
32
 
33
#define FOGMODE_EXP 1. 
34
 
35
#define FOGMODE_EXP2 2. 
36
 
37
#define FOGMODE_LINEAR 3. 
38
 
39
#define E 2.71828 
40
 
41
 
42
 
43
uniform vec4 vFogInfos;
44
 
45
uniform vec3 vFogColor;
46
 
47
 
48
 
49
float calcFogFactor() {
50
 
51
 
52
 
53
    // gets distance from camera to vertex 
54
 
55
    float fogDistance = gl_FragCoord.z / gl_FragCoord.w;
56
 
57
 
58
 
59
    float fogCoeff = 1.0;
60
 
61
    float fogStart = vFogInfos.y;
62
 
63
    float fogEnd = vFogInfos.z;
64
 
65
    float fogDensity = vFogInfos.w;
66
 
67
 
68
 
69
    if (FOGMODE_LINEAR == vFogInfos.x) {
70
 
71
        fogCoeff = (fogEnd - fogDistance) / (fogEnd - fogStart);
72
 
73
    }
74
 
75
    else if (FOGMODE_EXP == vFogInfos.x) {
76
 
77
        fogCoeff = 1.0 / pow(E, fogDistance * fogDensity);
78
 
79
    }
80
 
81
    else if (FOGMODE_EXP2 == vFogInfos.x) {
82
 
83
        fogCoeff = 1.0 / pow(E, fogDistance * fogDistance * fogDensity * fogDensity);
84
 
85
    }
86
 
87
 
88
 
89
    return clamp(fogCoeff, 0.0, 1.0);
90
 
91
}
92
 
93
 
94
 
95
void main(void) {
96
 
97
 
98
 
99
    vec4 baseColor = texture2D(baseSampler, vUV);
100
 
101
 
102
 
103
    vec2 blendUV = vec2(vUV.x * blendScaleU, vUV.y * blendScaleV);
104
 
105
    vec4 blendColor = texture2D(blendSampler, blendUV);
106
 
107
 
108
 
109
    // multiply type blending mode 
110
 
111
    vec4 color = baseColor * blendColor;
112
 
113
 
114
 
115
    // factor in fog color 
116
 
117
    float fog = calcFogFactor();
118
 
119
    color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
120
 
121
 
122
 
123
    gl_FragColor = color;
124
 
125
}

我们定制的最后一件作品 Blend shader 是 Babylon 使用的 JavaScript 代码。主要目的 此代码用于准备传递给顶点和像素着色器的参数。

1
function BlendMaterial(name, scene, options) {
2
 
3
    this.name = name;
4
 
5
    this.id = name;
6
 
7
 
8
 
9
    this.options = options;
10
 
11
    this.blendScaleU = options.blendScaleU || 1;
12
 
13
    this.blendScaleV = options.blendScaleV || 1;
14
 
15
 
16
 
17
    this._scene = scene;
18
 
19
    scene.materials.push(this);
20
 
21
 
22
 
23
    var assets = options.assetManager;
24
 
25
    var textureTask = assets.addTextureTask('blend-material-base-task', options.baseImage);
26
 
27
    textureTask.onSuccess = _.bind(function(task) {
28
 
29
 
30
 
31
        this.baseTexture = task.texture;
32
 
33
        this.baseTexture.uScale = 1;
34
 
35
        this.baseTexture.vScale = 1;
36
 
37
 
38
 
39
        if (options.baseHasAlpha) {
40
 
41
            this.baseTexture.hasAlpha = true;
42
 
43
        }
44
 
45
 
46
 
47
    }, this);
48
 
49
 
50
 
51
    textureTask = assets.addTextureTask('blend-material-blend-task', options.blendImage);
52
 
53
    textureTask.onSuccess = _.bind(function(task) {
54
 
55
        this.blendTexture = task.texture;
56
 
57
        this.blendTexture.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE;
58
 
59
        this.blendTexture.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE;
60
 
61
    }, this);
62
 
63
 
64
 
65
}
66
 
67
 
68
 
69
BlendMaterial.prototype = Object.create(BABYLON.Material.prototype);
70
 
71
 
72
 
73
BlendMaterial.prototype.needAlphaBlending = function () {
74
 
75
    return (this.options.baseHasAlpha === true);
76
 
77
};
78
 
79
 
80
 
81
BlendMaterial.prototype.needAlphaTesting = function () {
82
 
83
    return false;
84
 
85
};
86
 
87
 
88
 
89
BlendMaterial.prototype.isReady = function (mesh) {
90
 
91
    var engine = this._scene.getEngine();
92
 
93
 
94
 
95
    // make sure textures are ready 
96
 
97
    if (!this.baseTexture || !this.blendTexture) {
98
 
99
        return false;
100
 
101
    }
102
 
103
 
104
 
105
    if (!this._effect) {
106
 
107
        this._effect = engine.createEffect(
108
 
109
 
110
 
111
            // shader name 
112
 
113
            "blend",
114
 
115
 
116
 
117
            // attributes describing topology of vertices 
118
 
119
            [ "position", "normal", "uv" ],
120
 
121
 
122
 
123
            // uniforms (external variables) defined by the shaders 
124
 
125
            [ "worldViewProjection", "world", "blendScaleU", "blendScaleV", "vFogInfos", "vFogColor" ],
126
 
127
 
128
 
129
            // samplers (objects used to read textures) 
130
 
131
            [ "baseSampler", "blendSampler" ],
132
 
133
 
134
 
135
            // optional define string 
136
 
137
            "");
138
 
139
    }
140
 
141
 
142
 
143
    if (!this._effect.isReady()) {
144
 
145
        return false;
146
 
147
    }
148
 
149
 
150
 
151
    return true;
152
 
153
};
154
 
155
 
156
 
157
BlendMaterial.prototype.bind = function (world, mesh) {
158
 
159
 
160
 
161
    var scene = this._scene;
162
 
163
    this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
164
 
165
    this._effect.setColor3("vFogColor", scene.fogColor);
166
 
167
 
168
 
169
    this._effect.setMatrix("world", world);
170
 
171
    this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
172
 
173
 
174
 
175
    // Textures 
176
 
177
    this._effect.setTexture("baseSampler", this.baseTexture);
178
 
179
    this._effect.setTexture("blendSampler", this.blendTexture);
180
 
181
 
182
 
183
    this._effect.setFloat("blendScaleU", this.blendScaleU);
184
 
185
    this._effect.setFloat("blendScaleV", this.blendScaleV);
186
 
187
};
188
 
189
 
190
 
191
BlendMaterial.prototype.dispose = function () {
192
 
193
 
194
 
195
    if (this.baseTexture) {
196
 
197
        this.baseTexture.dispose();
198
 
199
    }
200
 
201
 
202
 
203
    if (this.blendTexture) {
204
 
205
        this.blendTexture.dispose();
206
 
207
    }
208
 
209
 
210
 
211
    this.baseDispose();
212
 
213
};

Babylon.js使它变得容易 创建基于着色器的自定义材质。我们的混合材料相对简单, 但它确实对岛屿的外观产生了很大的影响,当 飞机低空飞到地面。着色器将 GPU 的强大功能带到 浏览器,扩展可应用于 3D 的创意效果类型 场景。在我们的案例中,这是画龙点名!

原文链接:使用 WebGL 为 HTML5 游戏创建逼真的地形 (mvrlink.com)文章来源地址https://www.toymoban.com/news/detail-697625.html

到了这里,关于使用 WebGL 为 HTML5 游戏创建逼真的地形的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Three.js创建令人惊叹的WebGL 3D可视化

    WebGL 可视化 3D 绘图是一项新兴技术,具有广阔的应用前景。它允许开发人员在 Web 浏览器中创建和渲染 3D 图形,而无需安装额外的插件或软件。 本博客将介绍 Three.js,Three.js 是一个功能强大的 WebGL 框架,提供了丰富的 API 用于创建和渲染 3D 图形,接下来让我们通

    2024年01月19日
    浏览(66)
  • unity发布WebGl在手机上的横屏适配,webgl横版游戏在手机上直接转横屏

    unity版本2020.1 问题:webgl的横版游戏 1920*1080,在手机上适配的不好,还是竖屏显示, 使用官方的说明,说是只在全屏模式下能旋转,也不好用,可能直接旋转也不会达到理想的效果 解决方案: 1.我这边使用的方案是UI的适配,UGUI,采用的是两套UI,根据不同平台加载不同的资源

    2024年02月02日
    浏览(47)
  • 【Unity】3D贪吃蛇游戏制作/WebGL本地测试及项目部署

    本文是Unity3D贪吃蛇游戏从制作到部署的相关细节 项目开源代码:https://github.com/zstar1003/3D_Snake 试玩链接:http://xdxsb.top/Snake_Game_3D 效果预览: 试玩链接中的内容会和该效果图略有不同,后面会详细说明。 经典贪吃蛇游戏:蛇身随着吃食物的增加不断变长,通过A/D或方向键←→

    2024年02月07日
    浏览(53)
  • Unity打包浏览器端网页HTML(WebGL)以及部署到Tomcat浏览器访问报错问题解决

    Unity 默认打包是 PC 端客户端程序,想要打包浏览器可以访问的 WebGL 网页,需要修改一些配置。 我使用的 Unity 版本是 2021.3.24f1 。 1.1 点击 File —— Build Settings... 1.2 点击 Add Open Scenes .把全部场景加入 Scene In Build 列表中 网上说不全部加进去会找不到需要跳转的场景,我还没涉

    2024年02月16日
    浏览(57)
  • 快速上手WebGL,代码+图解手把手教你使用WebGL一步步实现热力图

    大家好,我是南木元元,热衷分享有趣实用的文章。 项目中需要绘制热力图,热力图其实就是数值大小用颜色来进行区分,每个点的数值需根据颜色映射表(调色板)映射为指定颜色。需要3个数值字段,可绘制在平行坐标系中(2个数值字段分别确定x、y轴,1个数值字段确定

    2024年01月18日
    浏览(56)
  • WebGL简介以及使用

    WebGL(Web图形库) 是一种在没有使用插件的情况下在网页浏览器中渲染2D图形和3D图形的技术。它基于OpenGL ES,一个在嵌入式系统中广泛使用的图形API。WebGL通过HTML5的 canvas 元素直接在网页上实现图形渲染,使得开发者能够创建复杂的视觉效果和动态图形,而不会牺牲网页的性

    2024年02月01日
    浏览(28)
  • WebGL 同时使用多幅纹理

    目录 前言 ​编辑 示例代码 颜色矢量的分量乘法来计算两个纹素最终的片元颜色

    2024年02月09日
    浏览(36)
  • Openlayers使用WebGL加载多种自定义图标矢量点

    使用OpenLayers的 WebGLPointsLayer 加载海量矢量点(100W),并使用 多种自定义图标样式 。 你需要满足以下环境要求: 支持WebGL 的浏览器(Chrome、Firefox、Safari和Edge等)。 计算机具有一定的图形处理能力( 显卡 )。 一定的计算机 内存和网络带宽 。 一点耐心 1.创建一个 包含所有

    2024年04月11日
    浏览(43)
  • Html5钢琴块游戏制作(音乐游戏)

    当年一款手机节奏音游,相信不少人都玩过或见过。最近也是将其做了出来分享给大家。 游戏的基本玩法:点击下落的黑色方块,弹奏音乐。(下落的速度会越来越快)  可以进行试玩,手机玩起来效果会更好些。 点击试玩 游戏使用了一首儿歌乐谱,听出来是啥了吗^ ^ --

    2023年04月16日
    浏览(42)
  • HTML5-创建HTML文档

    HTML5中的一个主要变化是: 将元素的语义与元素对其内容呈现结果的影响分开。 从原理上讲这合乎情理。HTML元素负责文档内容的结构和含义,内容的呈现则由应用于元素上的CSS样式控制。下面介绍最基础的HTML元素:文档元素和元数据元素。 一、构建基本的文档结构 文档元

    2024年02月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包