使用 Three.js 在 WebGL 中的环形几何体上进行非径向纹理映射

问题描述 投票:0回答:2

我正在尝试使用 ThreeJS 库使用 2D 几何结构上的纹理来模拟图像变形效果。我想在空心圆(基本上是由 THREE.RingGeometry 函数构建的环)上应用纹理图像并获得此图像中显示的结果:

Texture image and desired results

下面我展示了我在场景中获得的实心环及其线框版本的结果:

Texture applied over the ring and its corresponding wireframed version

问题在于,正如您所看到的,纹理是从环的中心到外部以放射状方式应用的。然而,我真正需要的是以同心圆的方式应用纹理图像,如本问题的第一张图片所示。

这个想法是在环形上生成原始纹理的变形版本。我想知道如何通过 Three.js 以编程方式实现这种效果,使得目标形状可以是任意 2D 几何图形。

下面是我用来绘制场景的相关代码:

var texture = THREE.ImageUtils.loadTexture('./images/texture.png');

var wireRing = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture, wireframe: true}));
wireRing.position.set(-25, 50, 0);
scene.add(wireRing);

var ring = new THREE.Mesh(new THREE.RingGeometry(10, 20, 50, 5, 0, Math.PI * 2), new THREE.MeshBasicMaterial({map: texture}));
ring.position.set(25, 50, 0);
scene.add(ring);
opengl-es three.js mapping textures
2个回答
3
投票

您只需更改

RingGeometry
中的 UV 映射,如下所示:

uvs.push( new THREE.Vector2( o / thetaSegments, i / phiSegments ) );

此外,如果您想围绕环旋转纹理,可以通过改变

RingGeometry
参数来实例化
thetaStart

var geometry = new THREE.RingGeometry( 10, 20, 50, 5, thetaStart, Math.PI * 2 );

三.js r.67


0
投票

对于使用更新版本 Three.js 的任何人,我都能够创建一个正确更新 uv 的 TypeScript 类。标准

RingGeomtry
的主要变化是从
uv
更新
const
定义,然后利用自之前提供正确答案以来已更改的
uv = new THREE.Vector2(j / phiSegments, i / thetaSegments);

行星环几何.ts

import * as THREE from 'three';

export class PlanetRingGeomtry extends THREE.BufferGeometry {
  parameters: {
    innerRadius: number;
    outerRadius: number;
    thetaSegments: number;
    phiSegments: number;
    thetaStart: number;
    thetaLength: number;
  };

  constructor(
    innerRadius = 0.5,
    outerRadius = 1,
    thetaSegments = 32,
    phiSegments = 1,
    thetaStart = 0,
    thetaLength = Math.PI * 2
  ) {
    super();

    this.parameters = {
      innerRadius: innerRadius,
      outerRadius: outerRadius,
      thetaSegments: thetaSegments,
      phiSegments: phiSegments,
      thetaStart: thetaStart,
      thetaLength: thetaLength,
    };

    thetaSegments = Math.max(3, thetaSegments);
    phiSegments = Math.max(1, phiSegments);

    // buffers

    const indices = [];
    const vertices = [];
    const normals = [];
    const uvs = [];

    // some helper variables

    let radius = innerRadius;
    const radiusStep = (outerRadius - innerRadius) / phiSegments;
    const vertex = new THREE.Vector3();
    let uv = new THREE.Vector2();

    // generate vertices, normals and uvs

    for (let j = 0; j <= phiSegments; j++) {
      for (let i = 0; i <= thetaSegments; i++) {
        // values are generate from the inside of the ring to the outside

        const segment = thetaStart + (i / thetaSegments) * thetaLength;

        // vertex

        vertex.x = radius * Math.cos(segment);
        vertex.y = radius * Math.sin(segment);

        vertices.push(vertex.x, vertex.y, vertex.z);

        // normal

        normals.push(0, 0, 1);

        // uv
        uv = new THREE.Vector2(j / phiSegments, i / thetaSegments);

        uvs.push(uv.x, uv.y);
      }

      // increase the radius for next row of vertices

      radius += radiusStep;
    }

    // indices

    for (let j = 0; j < phiSegments; j++) {
      const thetaSegmentLevel = j * (thetaSegments + 1);

      for (let i = 0; i < thetaSegments; i++) {
        const segment = i + thetaSegmentLevel;

        const a = segment;
        const b = segment + thetaSegments + 1;
        const c = segment + thetaSegments + 2;
        const d = segment + 1;

        // faces

        indices.push(a, b, d);
        indices.push(b, c, d);
      }
    }

    // build geometry

    this.setIndex(indices);
    this.setAttribute(
      'position',
      new THREE.Float32BufferAttribute(vertices, 3)
    );
    this.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
    this.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
  }
}

RingGeomtry r67的先前版本定义:https://github.com/mrdoob/ Three.js/blob/fa4e4ae77fe5a1f9506a91160cc7a9f4e61518fc/src/extras/geometries/RingGeometry.js

基于RingGeomtryr166更新:https://github.com/mrdoob/ Three.js/blob/1845f6cd0525b5c73b9da33c40e198c360af29f1/src/geometries/RingGeometry.js

土星环纹理应用的视觉示例:

地图 color map texture data

alpha地图 alphaMap texture data

相关代码

    var thetaSegments = 42;

    var geometry = new PlanetRingGeomtry(
      innerRadius,
      outerRadius,
      thetaSegments
    );
    geometry.rotateX(Math.PI / 2);

    var mapTexture = this.textureLoader.load(map);
    mapTexture.minFilter = THREE.NearestFilter;

    var colorMapTexture = this.textureLoader.load(colorMap);
    colorMapTexture.minFilter = THREE.NearestFilter;

    var material = new THREE.MeshLambertMaterial({
      map: colorMapTexture,
      alphaMap: mapTexture,
      transparent: true,
      opacity: 0.98,
      side: THREE.DoubleSide,
    });

    var ring = new THREE.Mesh(geometry, material);
    ring.position.set(0, 0, 0);

结果 rendered planet with rings

© www.soinside.com 2019 - 2024. All rights reserved.