最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊

 更新時(shí)間:2023年06月07日 14:20:23   作者:小烏龜快跑  
這篇文章主要為大家介紹了ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊的實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

ThreeJS 紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊

開始準(zhǔn)備使用ThreeJS寫一個(gè)類似《我的世界》場(chǎng)景的射擊類游戲,地形和我的世界很相似。場(chǎng)景中需要進(jìn)行很多的紋理貼圖,本篇文章主要以給一個(gè)立方體貼圖成草地為例子介紹 ThreeJS 中如何添加紋理?如何解決紋理貼圖后方塊不展示(紋理未生效,效果是黑色方塊)問題?

給 mesh 增加紋理,實(shí)現(xiàn)草地方塊

把大象裝進(jìn)冰箱需要三步,這里實(shí)現(xiàn)一個(gè)草地方塊也需要三步。

**step one :初始化一個(gè) geometry 立方體形狀。

step two: 初始化紋理加載器,加載紋理。

step three: 將紋理貼到立方體上,渲染出來。
**

step one 初始化一個(gè)111 的立方體

前邊兩篇文章中也有介紹,尤其是第一篇 【渲染第一個(gè)ThreeJS立方體】。不做詳細(xì)介紹呀,一行代碼

const geometry = new THREE.BoxGeometry();

Step two 初始化紋理加載器,加載紋理

開始介紹之前我們先簡(jiǎn)單減少一下 ThreeJS 支持的紋理加載器以及其加載的紋理類型,ThreeJS 提供 TextureLoader 來加載靜態(tài)圖像紋理;CubeTextureLoader 用于加載立方體貼圖紋理,它通過加載 6 個(gè)圖像來作為立方體的六個(gè)面,常用來創(chuàng)建天空盒天空球效果;CompressedTextureLoader 用于加載壓縮過后的紋理; DataTextureLoader 用于加載像素?cái)?shù)據(jù)組成的紋理,常用于動(dòng)態(tài)生成紋理或者使用特定的紋理生成算飯來創(chuàng)建紋理。還有一些其他通用的加載器用于加載文件、視頻、音頻等資源。

本文選擇使用 TextureLoader 來加載3張靜態(tài)圖片分別作為不同方向的紋理。開始前先準(zhǔn)備3 張圖片用于紋理資源分別如下。草地方塊 6 個(gè)面,頂部是草坪,側(cè)邊4個(gè)面共用一個(gè)圖,底部是一個(gè)圖。(圖片資源文末鏈接自取, 別使用一下截圖來作為圖片資源)。

準(zhǔn)備幾張靜態(tài)圖片:

底部:

側(cè)邊:

頂部:

把資源加載都放到 loader.ts 文件中處理

import  * as THREE from 'three';
// 導(dǎo)入靜態(tài)的圖片資源,位置注意是自己項(xiàng)目中存放靜態(tài)資源的地址。
import grassBlockTextureSideImg from '../../assets/textures/blocks-clipped/grassBlockSide.png';
import grassBlockTextureTopImg from '../../assets/textures/blocks-clipped/grassBlockTop.png';
import dirtTextureImg from '../../assets/textures/blocks-clipped/dirt.png';
// 創(chuàng)建一個(gè) THREE 加載器
const loader = new THREE.TextureLoader();
// 使用 loader.load 將靜態(tài)圖片加載到 ThreeJS 中
const grassBlockTextureSide = loader.load(grassBlockTextureSideImg);
const grassBlockTextureTop = loader.load(grassBlockTextureTopImg);
const dirtTexture = loader.load(dirtTextureImg);
// 定義清楚草地方塊紋理順序
export const grassBlock = {
    name: 'grassBlock',
    // 注意順序
    textureImg: [
        grassBlockTextureSide,
        grassBlockTextureSide,
        grassBlockTextureTop,
        dirtTexture,
        grassBlockTextureSide,
        grassBlockTextureSide,
      ],
      material: [],
};
// 使用 THREE.MeshStandardMaterial 將紋理創(chuàng)建成材質(zhì) 存入 grassBlock.material 上
grassBlock.material = grassBlock.textureImg.map((img, i) => {
    return new THREE.MeshStandardMaterial({
        map: img,
        // side: THREE.DoubleSide
    })
});
export default { grassBlock }

step two 完成,到目前已經(jīng)完成大部分了,接下來只要將 grassBlock.material用于新建的立方體上,然后將立方體渲染出來即可。

Step three 使用紋理材質(zhì)創(chuàng)建立方體并渲染

這一步我們需要進(jìn)行一些封裝,目的是將職責(zé)進(jìn)行隔離。將創(chuàng)建立方體的代碼放到 generateFrag.ts 中;我們將 scene 的初始化抽離到一個(gè)固定的類 Core 中進(jìn)行封裝,Core 類主要處理幾件事情:初始化 scene、初始化 camera、初始化渲染器 renderer。

// generateFrag.ts
import Terrain from '.';
import * as THREE from 'three';
// 導(dǎo)入草地格子的配置數(shù)據(jù)
import { grassBlock } from '../controller/loader';
export default class GenerateFrags {
  private terrain: Terrain;
  constructor(terrain: Terrain) {
    this.terrain = terrain;
  }
  generateAll() {}
  // 主要關(guān)注這里
  generateOneFrag() {
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    // 使用紋理創(chuàng)建的材質(zhì)來作為 mesh 的材質(zhì)
    const material = grassBlock.material;
    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(0, 0, 1);
    return mesh;
  }
}

core.ts 部分負(fù)責(zé)場(chǎng)景、相機(jī)、渲染器的初始化以及渲染草地格子。

// core.ts
import * as THREE from 'three';
import Terrain from '../terrain';
import GenerateFrags from '../terrain/generateFrag';
export default class Core {
  // scene
  public scene: THREE.Scene;
  // 透視相機(jī)
  public camera: THREE.PerspectiveCamera;
  // renderer 渲染器
  public renderer: THREE.WebglRenderer;
  // 地形對(duì)象
  public terrain: Terrain;
  constructor() {
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000,
    );
    this.renderer = new THREE.WebGLRenderer();
    // 地形
    this.terrain = new Terrain(this);
    // 其他初始化操作一并處理
    this.#init();
  }
  /**
   * 1, 監(jiān)聽頁面窗口大小改變,改變時(shí)需要個(gè)更新坐標(biāo)系(相機(jī)位置)
   */
  #init() {
    window.addEventListener('resize', () => {
      this.camera.aspect = window.innerHeight / window.innerWidth;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    });
    // 初始化設(shè)置相機(jī)
    // this.camera.fov = 80;
    // this.camera.aspect = window.innerWidth / window.innerWidth;
    // this.camera.far = 500;
    // this.camera.updateProjectionMatrix();
    this.camera.position.set(0, 0, 10);
    // 初始化場(chǎng)景scene 背景
    const backgroundColor = 0x87ceeb;
    this.scene.fog = new THREE.FogExp2(0.02);
    this.scene.background = new THREE.Color(backgroundColor);
    // 初始化場(chǎng)景的燈光
    const sunLight = new THREE.PointLight(0xffffff, 0.5);
    sunLight.position.set(500, 500, 500);
    this.scene.add(sunLight);
    const sunLight2 = new THREE.PointLight(0xffffff, 0.2);
    sunLight2.position.set(-500, 500, -500);
    this.scene.add(sunLight2);
    const reflectionLight = new THREE.AmbientLight(0x404040);
    this.scene.add(reflectionLight);
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    document
      .getElementById('game-container')
      .appendChild(this.renderer.domElement);
    // 這里是調(diào)用入口
    this.testRenderOneGrassBlock();
  }
  // 測(cè)試生成一個(gè)草地格子
  testRenderOneGrassBlock() {
    // 初始化一個(gè) GenerateFrags 對(duì)象來創(chuàng)建一個(gè)草地格子
    const generateOneFrag = new GenerateFrags(this.terrain);
    const cube = generateOneFrag.generateOneFrag();
    // 將草地格子加到 scene 中
    this.scene.add(cube);
    const animate = () => {
      requestAnimationFrame(animate);
      // 使用 mesh 的 rotation 來讓草地格子旋轉(zhuǎn)起來
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
      // 調(diào)用渲染器進(jìn)行渲染
      this.renderer.render(this.scene, this.camera);
    };
    animate();
  }
}

至此一個(gè)旋轉(zhuǎn)的草地格子生成出來了,效果如下:

添加紋理不生效的原因分析

對(duì)一個(gè)立方體添加紋理最后可能渲染成這個(gè)樣子,在保證圖片正常創(chuàng)建格子的方式也是正確的情況下,可能有兩個(gè)原因。會(huì)導(dǎo)致渲染出黑色的格子來,第一:紋理是異步加載渲染之前紋理還未加載好,第二:沒有光源。

解決思路

確保渲染在紋理加載之后

如果只渲染一次,那么需要保證渲染時(shí)紋理已經(jīng)加載完成,最好的方式就是使用 Promise 來處理一個(gè)盒子需要多張圖片來作為材質(zhì)時(shí) Promise.all 會(huì)很好用。如果是單張圖片可直接監(jiān)聽onload 事件 loader.load(imgpath, onload)

我們?cè)?core.js 中使用 requestAnimationFrame 來重復(fù)渲染草地格子第二次渲染開始紋理已經(jīng)加載完成了由此避開了紋理未加載就渲染導(dǎo)致形狀黑色問題。后續(xù)游戲中使用的紋理大部分都集中加載,因此可以檢測(cè)每個(gè)材質(zhì)回來后就進(jìn)行新的渲染觸發(fā)。

為場(chǎng)景添加合適的光源

想象一下在漆黑的屋子里面有一個(gè)彩色的球,一點(diǎn)光都沒有啥都看不見。另外就是逆光時(shí)我們看不見光源背后的東西。因此我們需要將光源設(shè)置到相機(jī)的順方向(或者多設(shè)置幾組光源),保證相機(jī)與物體的連線上能存在光的分量。

以上就是ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊的詳細(xì)內(nèi)容,更多關(guān)于ThreeJS 紋理貼圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解

    TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解

    這篇文章主要為大家介紹了TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • TypeScript?泛型接口具體使用實(shí)戰(zhàn)

    TypeScript?泛型接口具體使用實(shí)戰(zhàn)

    這篇文章主要為大家介紹了TypeScript?泛型接口具體使用實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解

    TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解

    這篇文章主要為大家介紹了TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • TypeScript Module Resolution解析過程

    TypeScript Module Resolution解析過程

    這篇文章主要為大家介紹了TypeScript Module Resolution解析過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • TypeScript保姆級(jí)基礎(chǔ)教程

    TypeScript保姆級(jí)基礎(chǔ)教程

    這篇文章主要為大家介紹了TypeScript保姆級(jí)基礎(chǔ)教程示例詳解,主要為大家介紹了typescript的類型,函數(shù),對(duì)象,接口等基礎(chǔ)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-07-07
  • 開發(fā)typescript項(xiàng)目tsconfig.json配置及選項(xiàng)使用解析

    開發(fā)typescript項(xiàng)目tsconfig.json配置及選項(xiàng)使用解析

    這篇文章主要為大家介紹了tsconfig.json配置及選項(xiàng)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • TypeScript中的函數(shù)重載示例分析

    TypeScript中的函數(shù)重載示例分析

    這篇文章主要為大家介紹了TypeScript中的函數(shù)重載示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • typescript在vue中的入門案例代碼demo

    typescript在vue中的入門案例代碼demo

    這篇文章主要介紹了typescript在vue中的入門案例代碼demo,使用技術(shù)棧vue2+typescript+scss入門練手項(xiàng)目,天氣預(yù)報(bào)demo,需要的朋友可以參考下。
    2022-12-12
  • TypeScript防抖節(jié)流函數(shù)示例詳解

    TypeScript防抖節(jié)流函數(shù)示例詳解

    這篇文章主要為大家介紹了TypeScript防抖節(jié)流函數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • TypeScript中的聯(lián)合類型使用示例詳解

    TypeScript中的聯(lián)合類型使用示例詳解

    這篇文章主要為大家介紹了TypeScript中的聯(lián)合類型使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論

宁国市| 保亭| 防城港市| 玛纳斯县| 呼玛县| 云龙县| 峨山| 柯坪县| 昭苏县| 临潭县| 长葛市| 连平县| 齐河县| 额尔古纳市| 景泰县| 承德市| 万山特区| 宝鸡市| 沾化县| 明水县| 墨玉县| 定陶县| 商都县| 普宁市| 乌兰察布市| 台北市| 邓州市| 托克逊县| 江都市| 本溪市| 鹤峰县| 延安市| 方山县| 平江县| 三原县| 漳州市| 巧家县| 乌鲁木齐市| 黄浦区| 上蔡县| 海南省|