欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

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

step one 初始化一個111 的立方體

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

const geometry = new THREE.BoxGeometry();

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

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

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

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

底部:

側(cè)邊:

頂部:

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

import  * as THREE from 'three';
// 導(dǎo)入靜態(tài)的圖片資源,位置注意是自己項目中存放靜態(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)建一個 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)建立方體并渲染

這一步我們需要進行一些封裝,目的是將職責進行隔離。將創(chuàng)建立方體的代碼放到 generateFrag.ts 中;我們將 scene 的初始化抽離到一個固定的類 Core 中進行封裝,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 部分負責場景、相機、渲染器的初始化以及渲染草地格子。

// 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;
  // 透視相機
  public camera: THREE.PerspectiveCamera;
  // renderer 渲染器
  public renderer: THREE.WebglRenderer;
  // 地形對象
  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)聽頁面窗口大小改變,改變時需要個更新坐標系(相機位置)
   */
  #init() {
    window.addEventListener('resize', () => {
      this.camera.aspect = window.innerHeight / window.innerWidth;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    });
    // 初始化設(shè)置相機
    // 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);
    // 初始化場景scene 背景
    const backgroundColor = 0x87ceeb;
    this.scene.fog = new THREE.FogExp2(0.02);
    this.scene.background = new THREE.Color(backgroundColor);
    // 初始化場景的燈光
    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();
  }
  // 測試生成一個草地格子
  testRenderOneGrassBlock() {
    // 初始化一個 GenerateFrags 對象來創(chuàng)建一個草地格子
    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)用渲染器進行渲染
      this.renderer.render(this.scene, this.camera);
    };
    animate();
  }
}

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

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

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

解決思路

確保渲染在紋理加載之后

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

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

為場景添加合適的光源

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

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

相關(guān)文章

最新評論