ThreeJS-经纬线映射贴图(十六)

Posted 不穿铠甲的穿山甲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreeJS-经纬线映射贴图(十六)相关的知识,希望对你有一定的参考价值。

hdr资源:

链接: https://pan.baidu.com/s/1mCdjpV7jKWHTXmExMa0T8A

提取码: 7ydx

复制这段内容后打开百度网盘手机App,操作更方便哦

增加新引入:

import RGBELoader from "three/examples/jsm/loaders/RGBELoader"

 关键代码:

    rgbeLoader.loadAsync('three/marble13-flat.hdr').then( texture =>

      //添加球形反射映射

      texture.mapping = THREE.EquirectangularReflectionMapping;

      //设置场景背景

      scene.background = texture;

    )

完整的代码:

<template>

  <div id="three_div"></div>

</template>

  <script>

import * as THREE from "three";

import OrbitControls from "three/examples/jsm/controls/OrbitControls";

import RGBELoader from "three/examples/jsm/loaders/RGBELoader"

export default

  name: "HOME",

  components:

    // vueQr,

    // glHome,

  ,

  data()

    return ;

  ,

  mounted()

    //使用控制器控制3D拖动旋转OrbitControls

    //控制3D物体移动

    //1.创建场景

    const scene = new THREE.Scene();

    console.log(scene);

    //2.创建相机

    const camera = new THREE.PerspectiveCamera(

      75,

      window.innerWidth / window.innerHeight,

      0.1,

      1000

    );

    //设置相机位置

    camera.position.set(0, 0, 10);

    //将相机添加到场景

    scene.add(camera);

    //添加物体

    //创建一个半径为1,经纬度分段数位20的球

    const cubeGeometry = new THREE.SphereBufferGeometry(2,100,100);

    //纹理加载器

    let cubeTextureLoader = new THREE.CubeTextureLoader();

    cubeTextureLoader =  cubeTextureLoader.setPath('three/').load([

      'sphere.webp',

      'sphere.webp',

      'sphere.webp',

      'sphere.webp',

      'sphere.webp',

      'sphere.webp'

    ]);

    let rgbeLoader = new RGBELoader();

    rgbeLoader.loadAsync('three/marble13-flat.hdr').then( texture =>

      //添加球形反射映射

      texture.mapping = THREE.EquirectangularReflectionMapping;

      //设置场景背景

      scene.background = texture;

    )

    //纹理加载器加载图片

    const cubeMaterial = new THREE.MeshStandardMaterial(

      metalness: 1,

      roughness: 0.1,

     // envMap: cubeTextureLoader//添加环境贴图

    );

    //根据几何体和材质创建物体

    const mesh = new THREE.Mesh(cubeGeometry, cubeMaterial);

    //将物体加入到场景

    scene.add(mesh);

    //给场景添加贴图纹理

    //scene.background = cubeTextureLoader;

    //给场景所有的物体添加默认的环境贴图

    scene.environment = cubeTextureLoader;

    //添加坐标轴辅助器

    const axesHepler = new THREE.AxesHelper(5);

    scene.add(axesHepler);

    //标准材质需要借助灯光

    //添加周围环境灯光(由物体发出的灯光)参数(灯色,强度0-1)

    const light = new THREE.AmbientLight(0xFFFFFF, 1);

    scene.add(light);

    //直线光(由光源发出的灯光)

    // const directionalLight = new THREE.DirectionalLight(0xffff00, 1);

    // //设置灯光位置

    // directionalLight.position.set(10, 10, 10);

    // scene.add(directionalLight);

   

    //添加平面

    // const planeGeometry = new THREE.PlaneBufferGeometry(1, 1);

    // const mesh2 = new THREE.Mesh(planeGeometry, cubeMaterial);

    // mesh2.position.set(0, 0, 3);

    // scene.add(mesh2);

    //初始化渲染器

    const render = new THREE.WebGLRenderer();

    //设置渲染器的尺寸

    render.setSize(window.innerWidth, window.innerHeight);

    //使用渲染器,通过相机将场景渲染进来

    //创建轨道控制器,可以拖动,控制的是摄像头

    const controls = new OrbitControls(camera, render.domElement);

    //设置控制阻尼,让控制器有更真实的效果

    controls.enableDamping = true;

    //将webgl渲染的canvas内容添加到body上

    document.getElementById("three_div").appendChild(render.domElement);

    //渲染下一帧的时候就会调用回调函数

    let renderFun = () =>

      //更新阻尼数据

      controls.update();

      //需要重新绘制canvas画布

      render.render(scene, camera);

      //监听屏幕刷新(60HZ,120HZ),每次刷新触发一次requestAnimationFrame回调函数

      //但是requestAnimationFrame的回调函数注册生命只有一次,因此需要循环注册,才能达到一直调用的效果

      window.requestAnimationFrame(renderFun);

    ;

    // window.requestAnimationFrame(renderFun);

    renderFun();

    //画布全屏

    window.addEventListener("dblclick", () =>

      if (document.fullscreenElement)

        document.exitFullscreen();

      else

        //document.documentElement.requestFullscreen();

        render.domElement.requestFullscreen();

     

    );

    //监听画面变化,更新渲染画面,(自适应的大小)

    window.addEventListener("resize", () =>

      //更新摄像机的宽高比

      camera.aspect = window.innerWidth / window.innerHeight;

      //更新摄像机的投影矩阵

      camera.updateProjectionMatrix();

      //更新渲染器宽度和高度

      render.setSize(window.innerWidth, window.innerHeight);

      //设置渲染器的像素比

      render.setPixelRatio(window.devicePixelRatio);

      console.log("画面变化了");

    );

  ,

  methods:

    paush(animate)

      animate.pause();

    ,

  ,

;

</script>

<style scoped lang="scss">

</style>

效果图:

 

THREE JS 贴图之UV纹理映射

介绍

     Threejs贴图即将图片或canvas作为贴图贴到物体表面,让模型图片表现物体的纹理。通过贴图来使不同的模型展示不同的样式,不仅仅可以实现‘换装’,也可以做一些炫酷的效果。本文主要通过设置geometry的uv坐标来实现道路流光效果。

#简单实现

     思路:抛开真实道路情况的弯曲、倾斜的效果,首先创建个长方形的mesh,给mesh添加纹理,再通过animation方法每帧设置纹理的offset属性移动 -0.036。想法很好,说干就干。效果如图所示:




#查看mesh

     实现直线道路的过程很轻松,以为很快就结束了,只要在场景中选取几个点位,通过Catmull-Rom算法将点解析成平滑的曲线,再生成面,其余的步骤就轻车熟路了。万万没想到出现的不是流光效果,而是闪烁效果!!!



THREE JS 贴图之UV纹理映射


     苦思冥想N天后发现是贴图的问题,泪奔了,原因是通过顶点创建的面在geometry的faceVertexUvs属性中为空的,如图。(具体发生的原因还没有仔细研究,既然知道走到这了,手动映射一下UV就可以了吧)。



THREE JS 贴图之UV纹理映射




UV映射

     材质贴图又称纹理贴图,是将图片包裹到物体的表面,可以理解为给书包书皮,这样可以减少计算机的计算量。UV映射是将2D图形投影到3D模型表面,U、V表示纹理贴图的坐标,范围在0~1之间(即图1的坐标范围为(0,0)~(1,1))。如下图所示图1中0~7表示我们要添加的坐标点,根据这7个点来生成平面,THREE JS中进行UV映射时应按照逆时针构建三角网,正确的顺序应为(0,1,3)、(0,3,2)……一共要构建6个三角网,当然如果要按照顺时针构建的话显示图像就会在背面,也可以设置显示方式为THREE.DOUBLE,可以正反面都显示。假设图二表示我们要映射的图片,图片的左下角对应0坐标,右下角对应1坐标,2坐标对应图片的1/3位置。以此类推即可。

UV映射理解通了很简单,如果做复杂模型的话多一些工作量,大体思路是这样的。




模拟弯曲道路流光效果-完结撒花



    有了以上的知识基础,再实现流光道路就轻车熟路了。

 /** * 弯曲道路 流光效果 */ function initBlendRoad() { //texture var textureLoader = new THREE.TextureLoader(); texture = textureLoader.load("../../static/img/road/newRoad.png"); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.magFilter = THREE.LinearFilter; texture.offset.z = 0.5; texture.repeat.x = 2; texture.repeat.y = 3;
//vertices var points1 = [ new THREE.Vector3(50,-100,0), new THREE.Vector3(43,0,3), new THREE.Vector3(-20,50,0), ]; var vertices1 = new THREE.CatmullRomCurve3(points1); var points2 = [ new THREE.Vector3(60,-100,0), new THREE.Vector3(50,0,5), new THREE.Vector3(-19.5,59.4,0), ]; var vertices2 = new THREE.CatmullRomCurve3(points2);
//mesh var initgeometry = new THREE.INITGEOMETRY(vertices1.getPoints(99), vertices2.getPoints(99)); this.initFaceVertexUvs(initgeometry); var initMaterial = new THREE.INITMATERIAL({texture:texture}); var mesh = new THREE.Mesh(initgeometry, initMaterial); // console.log('curve road',mesh); scene.add(mesh); } /** * 传入geometry,根据 faces属性生成 faceVertexUvs * 默认逆时针加载,从(0,0)点开始 */ function initFaceVertexUvs(geometry){ let len = geometry.faces.length+2; let part = Math.floor((1/(len/2 -1)) * 100) /100; for (let i = 2; i < len; i++) { if (i % 2 == 0){ // 偶数 geometry.faceVertexUvs[0].push( [ new THREE.Vector2(0,((i/2)-1) * part), new THREE.Vector2(1,((i/2)-1) * part), new THREE.Vector2(0,(i/2)* part), ] ); }else if (i%2 == 1){ // 奇数 geometry.faceVertexUvs[0].push( [ new THREE.Vector2(1,(((i-1)/2)-1) * part), new THREE.Vector2(1,((i-1)/2) * part), new THREE.Vector2(0,((i-1)/2) * part), ] ); }
} }





    想要什么类型的效果可以自己用PS制作个图片或从网上下载一个即可,下面附上最终效果图:







以上是关于ThreeJS-经纬线映射贴图(十六)的主要内容,如果未能解决你的问题,请参考以下文章

threejs里怎么解决网格贴图闪烁

ThreeJS——创建纹理贴图

ThreeJS法线贴图normalMap

ThreeJS文字作为纹理贴图

threejs透明贴图如何不影响内部材质

threejs立方体贴图产生边缘锯齿问题