1- <!DOCTYPE html> < html lang ="zh "> < head >
2- < meta charset ="utf-8 ">
3- < title > Backgrounds and Skyboxes</ title >
4- < meta name ="viewport " content ="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0 ">
5- < meta name ="twitter:card " content ="summary_large_image ">
6- < meta name ="twitter:site " content ="@threejs ">
7- < meta name ="twitter:title " content ="Three.js – Backgrounds and Skyboxes ">
8- < meta property ="og:image " content ="https://threejs.org/files/share.png ">
9- < link rel ="shortcut icon " href ="/files/favicon_white.ico " media ="(prefers-color-scheme: dark) ">
10- < link rel ="shortcut icon " href ="/files/favicon.ico " media ="(prefers-color-scheme: light) ">
11-
12- < link rel ="stylesheet " href ="/manual/resources/lesson.css ">
13- < link rel ="stylesheet " href ="/manual/resources/lang.css ">
14- <!-- Import maps polyfill -->
15- <!-- Remove this when import maps will be widely supported -->
16- < script async src ="
https://unpkg.com/[email protected] /dist/es-module-shims.js "
> </ script > 17-
18- < script type ="importmap ">
1+ <!DOCTYPE html>
2+ < html lang ="zh ">
3+
4+ < head >
5+ < meta charset ="utf-8 ">
6+ < title > 背景与天空盒</ title >
7+ < meta name ="viewport " content ="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0 ">
8+ < meta name ="twitter:card " content ="summary_large_image ">
9+ < meta name ="twitter:site " content ="@threejs ">
10+ < meta name ="twitter:title " content ="Three.js – Backgrounds and Skyboxes ">
11+ < meta property ="og:image " content ="https://threejs.org/files/share.png ">
12+ < link rel ="shortcut icon " href ="/files/favicon_white.ico " media ="(prefers-color-scheme: dark) ">
13+ < link rel ="shortcut icon " href ="/files/favicon.ico " media ="(prefers-color-scheme: light) ">
14+
15+ < link rel ="stylesheet " href ="/manual/resources/lesson.css ">
16+ < link rel ="stylesheet " href ="/manual/resources/lang.css ">
17+ <!-- Import maps polyfill -->
18+ <!-- Remove this when import maps will be widely supported -->
19+ < script async src ="
https://unpkg.com/[email protected] /dist/es-module-shims.js "
> </ script > 20+
21+ < script type ="importmap ">
1922{
2023 "imports" : {
2124 "three" : "../../build/three.module.js"
2225 }
2326}
2427</ script >
25- < link rel ="stylesheet " href ="/manual/zh/lang.css ">
26- </ head >
27- < body >
28- < div class ="container ">
29- < div class ="lesson-title ">
30- < h1 > Backgrounds and Skyboxes</ h1 >
31- </ div >
32- < div class ="lesson ">
33- < div class ="lesson-main ">
34- < p > 抱歉,还没有中文翻译哦。 < a href ="https://github.com/mrdoob/three.js "> 欢迎加入翻译</ a > ! 😄</ p >
35- < p > < a href ="/manual/en/backgrounds.html "> 英文原文链接</ a > .</ p >
28+ < link rel ="stylesheet " href ="/manual/zh/lang.css ">
29+ </ head >
30+
31+ < body >
32+ < div class ="container ">
33+ < div class ="lesson-title ">
34+ < h1 > 背景与天空盒</ h1 >
35+ </ div >
36+ < div class ="lesson ">
37+ < div class ="lesson-main ">
38+ < p > 这里大部分的文章都使用纯色作为背景。</ p >
39+ < p > 添加静态背景就像添加CSS一样简单,参考来自这篇< a href ="responsive.html "> THREE.js响应式编程</ a > 中的一个例子,我们只需要改变两个地方。
40+ </ p >
41+ < p > 我们需要在Canvas上添加一些CSS,以将其背景设置为图像。</ p >
42+ < pre class ="prettyprint showlinemods notranslate lang-html " translate ="no "> <style>
43+ body {
44+ margin: 0;
45+ }
46+ #c {
47+ width: 100%;
48+ height: 100%;
49+ display: block;
50+ + background: url(resources/images/daikanyama.jpg) no-repeat center center;
51+ + background-size: cover;
52+ }
53+ </style></ pre >
54+ < p > 然后我们需要告诉 < a href ="/docs/#api/en/renderers/WebGLRenderer "> < code class ="notranslate "
55+ translate ="no "> WebGLRenderer</ code > </ a > 去使用 < code class ="notranslate "
56+ translate ="no "> alpha</ code > ,这样我们不绘制的地方都是透明的。
57+ </ p >
58+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> function main() {
59+ const canvas = document.querySelector('#c');
60+ - const renderer = new THREE.WebGLRenderer({canvas});
61+ + const renderer = new THREE.WebGLRenderer({
62+ + canvas,
63+ + alpha: true,
64+ + });</ pre >
65+ < p > 然后背景就有了。</ p >
66+ < p > </ p >
67+ < div translate ="no " class ="threejs_example_container notranslate ">
68+ < div > < iframe class ="threejs_example notranslate " translate ="no " style =" "
69+ src ="/manual/examples/resources/editor.html?url=/manual/examples/background-css.html "> </ iframe > </ div >
70+ < a class ="threejs_center " href ="/manual/examples/background-css.html " target ="_blank "> 点击在新窗口打开</ a >
71+ </ div >
72+ < p > </ p >
73+ < p > 如果我们想让背景被 < a href ="post-processing.html "> 后处理效果</ a > 影响,我们需要用THREE.js绘制背景。</ p >
74+ < p > THREE.js 让这变得非常简单。我们可以将场景的背景设置为一种纹理。</ p >
75+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> const loader = new THREE.TextureLoader();
76+ const bgTexture = loader.load('resources/images/daikanyama.jpg');
77+ scene.background = bgTexture;</ pre >
78+ < p > 效果如下</ p >
79+ < p > </ p >
80+ < div translate ="no " class ="threejs_example_container notranslate ">
81+ < div > < iframe class ="threejs_example notranslate " translate ="no " style =" "
82+ src ="/manual/examples/resources/editor.html?url=/manual/examples/background-scene-background.html "> </ iframe >
83+ </ div >
84+ < a class ="threejs_center " href ="/manual/examples/background-scene-background.html "
85+ target ="_blank "> 点击在新窗口打开</ a >
86+ </ div >
87+ < p > </ p >
88+ < p > 这产生了一个背景图,但它被拉伸以适应屏幕。</ p >
89+ < p > 我们可以解决这个问题,通过设置纹理属性 < code class ="notranslate " translate ="no "> repeat</ code > 和 < code class ="notranslate "
90+ translate ="no "> offset</ code > 来显示图像的一部分。</ p >
91+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> function render(time) {
92+
93+ ...
3694
95+ + // 设置背景贴图的repeat和offset属性
96+ + // 来保证图片的比例是正确的
97+ + // 注意图片有可能还没加载完成
98+ + const canvasAspect = canvas.clientWidth / canvas.clientHeight;
99+ + const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
100+ + const aspect = imageAspect / canvasAspect;
101+ +
102+ + bgTexture.offset.x = aspect > 1 ? (1 - 1 / aspect) / 2 : 0;
103+ + bgTexture.repeat.x = aspect > 1 ? 1 / aspect : 1;
104+ +
105+ + bgTexture.offset.y = aspect > 1 ? 0 : (1 - aspect) / 2;
106+ + bgTexture.repeat.y = aspect > 1 ? 1 : aspect;
107+
108+ ...
109+
110+ renderer.render(scene, camera);
111+
112+ requestAnimationFrame(render);
113+ }</ pre >
114+ < p > 现在由 THREE.js 绘制背景。这个上面CSS的版本没有明显的区别,不过如果我们应用< a href ="post-processing.html "> 后处理效果</ a > ,背景也会被影响。</ p >
115+ < p > </ p >
116+ < div translate ="no " class ="threejs_example_container notranslate ">
117+ < div > < iframe class ="threejs_example notranslate " translate ="no " style =" "
118+ src ="/manual/examples/resources/editor.html?url=/manual/examples/background-scene-background-fixed-aspect.html "> </ iframe >
119+ </ div >
120+ < a class ="threejs_center " href ="/manual/examples/background-scene-background-fixed-aspect.html "
121+ target ="_blank "> 点击在新窗口打开</ a >
122+ < p > </ p >
123+ < p > 当然,静态背景通常不是我们在 3D 场景中想要的,相对的我们需要某种< em > 天空盒</ em > 效果。就如字面意思,天空盒就是绘制了一片天空在盒子上。我们把相机放在盒子里,看起来里面有天空背景。</ p >
124+ < p >
125+ 实现天空盒最常见的方法是制作一个立方体,应用纹理,绘制在它的内部。在立方体的每一面绘制一个纹理(使用纹理坐标),看起来像地平线的一些图像。通常使用带有纹理的天空球体或天空穹顶。你也许自己能想象得出来。只用一个立方体或球体,
126+ < a href ="textures.html "> 应用纹理</ a > , 标记它是 < code class ="notranslate " translate ="no "> THREE.BackSide</ code >
127+ ,这样我们渲染内部面而不是外部面,然后也把它直接放到场景里。或者使用两个场景,一个特殊的场景用于绘制天空盒/球体/圆顶,另一个画正常的一切。你可以用你正常的 < a
128+ href ="/docs/#api/en/cameras/PerspectiveCamera "> < code class ="notranslate "
129+ translate ="no "> PerspectiveCamera</ code > </ a > 去绘制,不需要< a
130+ href ="/docs/#api/en/cameras/OrthographicCamera "> < code class ="notranslate "
131+ translate ="no "> OrthographicCamera</ code > </ a > 。
132+ </ p >
133+ < p > 另一个方法是使用< em > 立方体贴图(Cubemap)</ em > . 立方体贴图是一种特殊的纹理,它有6个立方体面,它不使用标准的纹理坐标,使用从中心指向外部的方向来决定绘制的颜色。</ p >
134+ < p > 这是来自加利福利亚,山景城的计算机历史博物馆的6张立方体图像。</ p >
135+ < div class ="threejs_center ">
136+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/pos-x.jpg " style ="width: 200px "
137+ class ="border ">
138+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/neg-x.jpg " style ="width: 200px "
139+ class ="border ">
140+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/pos-y.jpg " style ="width: 200px "
141+ class ="border ">
142+ </ div >
143+ < div class ="threejs_center ">
144+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/neg-y.jpg " style ="width: 200px "
145+ class ="border ">
146+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/pos-z.jpg " style ="width: 200px "
147+ class ="border ">
148+ < img src ="../examples/resources/images/cubemaps/computer-history-museum/neg-z.jpg " style ="width: 200px "
149+ class ="border ">
150+ </ div >
151+ < p > 为了使用它们,我们使用< a href ="/docs/#api/en/loaders/CubeTextureLoader "> < code class ="notranslate "
152+ translate ="no "> CubeTextureLoader</ code > </ a > 加载它们,然后将其用作场景的背景。</ p >
153+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> {
154+ const loader = new THREE.CubeTextureLoader();
155+ const texture = loader.load([
156+ 'resources/images/cubemaps/computer-history-museum/pos-x.jpg',
157+ 'resources/images/cubemaps/computer-history-museum/neg-x.jpg',
158+ 'resources/images/cubemaps/computer-history-museum/pos-y.jpg',
159+ 'resources/images/cubemaps/computer-history-museum/neg-y.jpg',
160+ 'resources/images/cubemaps/computer-history-museum/pos-z.jpg',
161+ 'resources/images/cubemaps/computer-history-museum/neg-z.jpg',
162+ ]);
163+ scene.background = texture;
164+ }</ pre >
165+ < p > 在渲染时,我们不需要像上面那样调整纹理:</ p >
166+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> function render(time) {
167+
168+ ...
169+
170+ - // 设置背景贴图的repeat和offset属性
171+ - // 来保证图片的比例是正确的
172+ - // 注意图片有可能还没加载完成
173+ - const canvasAspect = canvas.clientWidth / canvas.clientHeight;
174+ - const imageAspect = bgTexture.image ? bgTexture.image.width / bgTexture.image.height : 1;
175+ - const aspect = imageAspect / canvasAspect;
176+ -
177+ - bgTexture.offset.x = aspect > 1 ? (1 - 1 / aspect) / 2 : 0;
178+ - bgTexture.repeat.x = aspect > 1 ? 1 / aspect : 1;
179+ -
180+ - bgTexture.offset.y = aspect > 1 ? 0 : (1 - aspect) / 2;
181+ - bgTexture.repeat.y = aspect > 1 ? 1 : aspect;
182+
183+ ...
184+
185+ renderer.render(scene, camera);
186+
187+ requestAnimationFrame(render);
188+ }</ pre >
189+ < p > 让我们添加一些控件,以便我们可以旋转相机。</ p >
190+ < pre class ="prettyprint showlinemods notranslate lang-js "
191+ translate ="no "> import {OrbitControls} from '/examples/jsm/controls/OrbitControls.js';</ pre >
192+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> const fov = 75;
193+ const aspect = 2; // Canvas默认值
194+ const near = 0.1;
195+ -const far = 5;
196+ +const far = 100;
197+ const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
198+ -camera.position.z = 2;
199+ +camera.position.z = 3;
200+
201+ +const controls = new OrbitControls(camera, canvas);
202+ +controls.target.set(0, 0, 0);
203+ +controls.update();</ pre >
204+ < p > 来尝试下,拖动以旋转示例里的相机,观察围绕着我们的立方体贴图。</ p >
205+ < p > </ p >
206+ < div translate ="no " class ="threejs_example_container notranslate ">
207+ < div > < iframe class ="threejs_example notranslate " translate ="no " style =" "
208+ src ="/manual/examples/resources/editor.html?url=/manual/examples/background-cubemap.html "> </ iframe >
209+ </ div >
210+ < a class ="threejs_center " href ="/manual/examples/background-cubemap.html " target ="_blank "> 点击在新窗口打开</ a >
211+ </ div >
212+ < p > </ p >
213+ < p > 另一种选择是使用等距矩形贴图(Equirectangular map), 这是被
214+ < a href ="https://google.com/search?q=360+camera "> 360 全景相机</ a > 拍摄的一种特殊类型的图片。
215+ </ p >
216+ < p > < a href ="https://hdrihaven.com/hdri/?h=tears_of_steel_bridge "> 这是一张图片</ a > ,我从
217+ < a href ="https://hdrihaven.com "> 这个网站</ a > 找到的。
218+ </ p >
219+ < div class ="threejs_center "> < img
220+ src ="../examples/resources/images/equirectangularmaps/tears_of_steel_bridge_2k.jpg " style ="width: 600px ">
221+ </ div >
222+ < p > 这并不难,首先,我们将等距矩形图片加载为纹理, 我们可以调用 < a
223+ href ="/docs/#api/en/renderers/WebGLCubeRenderTarget.fromEquirectangularTexture "> < code class ="notranslate "
224+ translate ="no "> WebGLCubeRenderTarget.fromEquirectangularTexture</ code > </ a >
225+ 这将为我们从等距矩形纹理中生成一个立方体贴图,我们传入预期的立方体贴图的大小给 < a href ="/docs/#api/en/renderers/WebGLCubeRenderTarget "> < code
226+ class ="notranslate " translate ="no "> WebGLCubeRenderTarget</ code > </ a > ,
227+ 使用等距矩形图片的高度似乎是一个不错的假设。</ p >
228+ < pre class ="prettyprint showlinemods notranslate lang-js " translate ="no "> {
229+ - const loader = new THREE.CubeTextureLoader();
230+ - const texture = loader.load([
231+ - 'resources/images/cubemaps/computer-history-museum/pos-x.jpg',
232+ - 'resources/images/cubemaps/computer-history-museum/neg-x.jpg',
233+ - 'resources/images/cubemaps/computer-history-museum/pos-y.jpg',
234+ - 'resources/images/cubemaps/computer-history-museum/neg-y.jpg',
235+ - 'resources/images/cubemaps/computer-history-museum/pos-z.jpg',
236+ - 'resources/images/cubemaps/computer-history-museum/neg-z.jpg',
237+ - ]);
238+ - scene.background = texture;
239+ + const loader = new THREE.TextureLoader();
240+ + const texture = loader.load(
241+ + 'resources/images/equirectangularmaps/tears_of_steel_bridge_2k.jpg',
242+ + () => {
243+ + const rt = new THREE.WebGLCubeRenderTarget(texture.image.height);
244+ + rt.fromEquirectangularTexture(renderer, texture);
245+ + scene.background = rt.texture;
246+ + });
247+ }</ pre >
248+ < p > 这就是全部要做的事。</ p >
249+ < p > </ p >
250+ < div translate ="no " class ="threejs_example_container notranslate ">
251+ < div > < iframe class ="threejs_example notranslate " translate ="no " style =" "
252+ src ="/manual/examples/resources/editor.html?url=/manual/examples/background-equirectangularmap.html "> </ iframe >
253+ </ div >
254+ < a class ="threejs_center " href ="/manual/examples/background-equirectangularmap.html "
255+ target ="_blank "> 点击在新窗口打开</ a >
256+ </ div >
257+ < p > </ p >
258+ < p > 除了在加载时执行此操作,你还可以提前转换等距矩形到立方体贴图。< a href ="https://matheowis.github.io/HDRI-to-CubeMap/ "> 这是一个可以为你做这件事的网站</ a > 。
259+ </ p >
37260 </ div >
38261 </ div >
39262 </ div >
40-
263+ </ div >
264+
41265 < script src ="/manual/resources/prettify.js "> </ script >
42266 < script src ="/manual/resources/lesson.js "> </ script >
43267
44268
45269
46270
47- </ body > </ html >
271+ </ body >
272+
273+ </ html >
0 commit comments