threejs深入纹理,立体场景cubeResolution(四)
在这个课程里主要完成讲解两个demo:
一个是电视墙:用视频做纹理
一,用视频做纹理
首先我们用video标签把视频源引入:
1 2 3 4 5 | < video id="video" autoplay loop style="display:none"> < source src="http://10.1.26.29:84/assets/video/sintel_trailer-480p.ogv" type="video/ogg"> < source src="http://10.1.26.29:84/assets/video/sintel_trailer-480p.mp4" type="video/mp4"> < source src="http://10.1.26.29:84/assets/video/sintel_trailer-480p.webm" type="video/webm"> </ video > |
设置视频纹理
在这里引入一个概念mipmap:一个mipmap是一组纹理图片,每个图片的尺寸都是前一张图片的一半。这些图片实在加载纹理时创建的,可以生成较平滑的过滤效果。
注意:
1.由于我们的视频不是正方形,所以要保证材质不会生成mipmap。
2.由于材质变化得很频繁,所以我们需要设置简单高效的过滤器。LinearFilter 线性过滤
1 2 3 4 5 6 7 8 9 10 11 | var video = document.getElementById( 'video' ); //获取页面dom元素 videoTexture = new THREE.Texture(video); //minFilter属性:指定纹理如何缩小。默认值:THREE.LinearMipMapLinearFilter videoTexture.minFilter = THREE.LinearFilter; //magFilter属性:指定纹理如何放大。默认值:THREE.LinearFilter videoTexture.magFilter = THREE.LinearFilter; videoTexture.format = THREE.RGBFormat; videoTexture.generateMipmaps = false ; |
THREE.Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )
Image:这是一个图片类型,基本上它有ImageUtils来加载,如下代码
var image = THREE.ImageUtils.loadTexture(url); // url 是一个http://xxxx/aaa.jpg 的类似地址,javascript没有从本地加载数据的能力,所以没有办法从您电脑的C盘加载数据。
Mapping:是一个THREE.UVMapping()类型,它表示的是纹理坐标。下一节,我们将说说纹理坐标。
wrapS:表示x轴的纹理的回环方式,就是当纹理的宽度小于需要贴图的平面的宽度的时候,平面剩下的部分应该p以何种方式贴图的问题。
wrapT:表示y轴的纹理回环方式。
magFilter和minFilter表示过滤的方式,这是OpenGL的基本概念。当您不设置的时候,它会取默认值。
format:表示加载的图片的格式,这个参数可以取值THREE.RGBAFormat,RGBFormat等。THREE.RGBAFormat表示每个像素点要使用四个分量表示,分别是红、绿、蓝、透明来表示。RGBFormat则不使用透明,也就是说纹理不会有透明的效果。
type:表示存储纹理的内存的每一个字节的格式,是有符号,还是没有符号,是整形,还是浮点型。不过这里默认是无符号型(THREE.UnsignedByteType)。暂时就解释到这里,有需要时,我们在仔细分析,或者给作者留言询问。
anisotropy:各向异性过滤。使用各向异性过滤能够使纹理的效果更好,但是会消耗更多的内存、CPU、GPU时间。
添加一个长方体作为电视墙,设置纹理时,我们采用两种纹理,有四面是纯色的,有两面是视频纹理,我们这里用数组materials存放六个面的纹理,然后通过THREE.MeshFaceMaterial()设置每个面的纹理,你也可以自己设置,六个面都是视频纹理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var cubeGeometry = new THREE.BoxGeometry(1, 10, 20); var cubeMaterial = new THREE.MeshBasicMaterial({map: videoTexture}); var materials = []; materials.push(cubeMaterial); materials.push(cubeMaterial); for ( var i = 1; i < 5; i++) { materials.push( new THREE.MeshLambertMaterial({color: 0xff0000})); } //MeshFaceMaterial这是一种容器,可以在该容器中为物体的各个表面上设置不同的颜色 var cube = new THREE.Mesh(cubeGeometry, new THREE.MeshFaceMaterial(materials)); cube.position.set(-10.05,0,0); cube.rotation.x = -0.3; cube.rotation.y = 23.5; cube.name = 'cube' ; scene.add(cube); |
MeshFaceMaterial方法根据参数materials创建mesh(网格)的复合材质类型,参数material是一个Material类型的数组对象,网格中的三角面属性materialindex定义了该三角面使用的参数material中材质对象的索引号.
添加控制器:
我们之前已经使用过一个可以缩放的控制器,这里我们使用一个可以旋转的控制器
用script标签引入一个库文件 OrbitControls.js
创建一个实例对象,就可以使用了。
1 | orbit = new THREE.OrbitControls(camera); |
完整代码下载:github(threejs-five) 如果你觉得我写的对你有帮助的话,请给个star,谢谢
二,玻璃质感反射一个空间环境
首先我们从原理上进行分析,这种可以表现立体空间环境的实现,实际上是构造了一个大的正方体,(skybox)正方体的六个面的背景是符合实际场景的六张图片,在这个demo里,就是汽车内部的前后左右上下,然后我们在正方体的内部进行观看,从而达到立体环绕的效果;
使用ShaderMaterial(共享材质)实现漫光反射,根据参数parameters创建为自定义着色器创建材质类型,这样的材质对象让用户扩充材质类型,有了无限的可能.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 参数的格式: parameters = { defines: { "label" : "value" }, uniforms: { "parameter1" : { type: "f" , value: 1.0 }, "parameter2" : { type: "i" value2: 2 } }, fragmentShader: <string>, vertexShader: <string>, shading: THREE.SmoothShading, blending: THREE.NormalBlending, depthTest: <bool>, depthWrite: <bool>, wireframe: <boolean>, wireframeLinewidth: <float>, lights: <bool>, vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, skinning: <bool>, morphTargets: <bool>, morphNormals: <bool>, fog: <bool> } |
接下来我们从代码进行分析:
首先我们先引入正方体六个面的图片,依然是异步引入
1 2 3 4 5 6 7 8 | var urls = [ 'http://10.1.26.29:84/assets/cubemap/car/right.png' , 'http://10.1.26.29:84/assets/cubemap/car/left.png' , 'http://10.1.26.29:84/assets/cubemap/car/top.png' , 'http://10.1.26.29:84/assets/cubemap/car/bottom.png' , 'http://10.1.26.29:84/assets/cubemap/car/front.png' , 'http://10.1.26.29:84/assets/cubemap/car/back.png' ]; |
用THREE.ImageUtils.loadTextureCube()方法载入纹理
定义一个着色器,基于THREE.ShaderLib来创建自定义的ShaderMaterial材质
1 2 3 4 5 6 7 8 9 10 11 12 13 | var cubemap = THREE.ImageUtils.loadTextureCube(urls); cubemap.format = THREE.RGBFormat; //一个特别的着色器(Three.ShaderLib[“cube”]),结合THREE.ShaderMaterial类,我们可以基于CubeMap对象创建一个环境 var shader = THREE.ShaderLib[ "cube" ]; shader.uniforms[ "tCube" ].value = cubemap;<br> //ShaderMaterial创建自己的着色器,要使用ShaderMaterial,必须传入两个着色器:fragmentShader,vertexShader var material = new THREE.ShaderMaterial({ fragmentShader: shader.fragmentShader, //定义每个传入的像素的颜色 vertexShader: shader.vertexShader, //允许你修改每一个传入的顶点的位置 uniforms: shader.uniforms, //该属性可以向你的着色器发送消息,将同样的消息发送到每个顶点和片段 depthWrite: false , side: THREE.DoubleSide //实现一个立体双面的效果 }); |
接下来,我们就可以创建天空盒子
1 2 | var skybox = new THREE.Mesh( new THREE.BoxGeometry(10000, 10000, 10000), material); scene.add(skybox); |
CubeCamera方法根据 near, far ,cubeResolution 生成立方体相机.CubeCamera对象的功能函数采用 定义构造的函数原型对象来实现. CubeCamera经常用来创建天空盒子.由六张图片拼接成一个场景.
near 指明相对于深度剪切面的近的距离,必须为正数,可选参数,如果未指定,初始化为0.1
far 指明相对于深度剪切面的远的距离,必须为正数,可选参数,如果未指定,初始化为2000
cubeResolution 设置立方体的宽度
Matrix4 返回PerspectiveCamera,透视投影相机
1 2 3 | cubeCamera = new THREE.CubeCamera(0.1, 20000, 256); cubeCamera.renderTarget.minFilter = THREE.LinearMipMapLinearFilter; scene.add(cubeCamera); |
接下来,我们可以创建镜面反射的立体图形
先以球体为例,
我们用立体相机的渲染目标,cubeCamera.renderTarget,也就是整个环境
1 2 3 4 5 | var sphereGeometry = new THREE.SphereGeometry(4, 15, 15);<br> ////envMap 设置环境贴图,默认是null var dynamicEnvMaterial = new THREE.MeshBasicMaterial({envMap: cubeCamera.renderTarget, side: THREE.DoubleSide}); sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMaterial); sphere.name = 'sphere' ; scene.add(sphere); |
再添加一个旋转立方体,可以显示变化的环境
用 cubemap作为纹理贴图,就是上面加载的六张图片
1 2 3 4 5 6 | var cubeGeometry = new THREE.BoxGeometry(5, 5, 5); var envMaterial = new THREE.MeshBasicMaterial({envMap: cubemap, side: THREE.DoubleSide}); var cube = new THREE.Mesh(cubeGeometry, envMaterial); cube.name = 'cube' ; scene.add(cube); cube.position.set(-10, 0, 0); |
最后,同样使用上面提到的控制器:OrbitControls
1 | orbit = new THREE.OrbitControls(camera); |
完整代码下载: github(threejs-six) 如果你觉得我写的对你有帮助的话,请给我个star,
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 上周热点回顾(1.20-1.26)