日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【threejs开发随笔】利用shaderMaterial制作草地

發(fā)布時間:2024/8/1 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【threejs开发随笔】利用shaderMaterial制作草地 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【threejs開發(fā)隨筆】利用shaderMaterial制作草地

0.前言

最近的一個threejs項目需要草地的效果,遂參考各路大神的方法制作了一個
1.al-ro
2.spacejack

大體的思路是用shaderMaterial實現(xiàn)頂點動畫,模擬草葉隨風(fēng)搖擺的樣子,利用InstancedMesh來大規(guī)模產(chǎn)生草葉。利用math庫里的MeshSurfaceSampler對象來吧草鋪到指定mesh上去。
點擊查看演示示例
點擊下載示例文件

1.先說用法

用法很簡單,引入makeGrass對象,然后new一個,傳入場景、需要生成草的mesh以及生成草的數(shù)量:

const grasses = new makeGrass(this.scene, // 場景model.scene.getObjectByName('平面') as Mesh, // 需要生草的mesh,類型需為Mesh250000 // 生草數(shù)量)

然后在渲染循環(huán)中執(zhí)行makeGrass實例的公共方法update()

...this.renderer.setAnimationLoop(() => { this.renderLoop() }) 執(zhí)行渲染循環(huán)方法。...// 渲染循環(huán)private renderLoop () {this.renderer.render(this.scene, this.camera)this.grasses?.update()this.controls?.update()}

2. 再說實現(xiàn)

首先我們新建一個makeGrass.ts文件,導(dǎo)入所需依賴

import { Clock, DoubleSide, InstancedMesh, Mesh, Object3D, PlaneGeometry, Scene, ShaderMaterial, Vector3 } from "three" import { MeshSurfaceSampler } from "three/examples/jsm/math/MeshSurfaceSampler"

新建一個makeGrass類

export default class makeGrass {private scene:Sceneprivate mesh:Meshprivate leavesMaterial: ShaderMaterialprivate clock = new Clockprivate sampler!:MeshSurfaceSamplerprivate grassesAmount!:numberconstructor(scene:Scene,mesh:Mesh,grassesAmount:number,) {this.scene = scenethis.mesh = mesh} }

寫一個方法用來初始化草葉的shader材質(zhì)并返回

private initleavesMaterial() {const vertexShader = `varying vec2 vUv;uniform float time;// 噪波float N (vec2 st) {return fract( sin( dot( st.xy, vec2(12.9898,78.233 ) ) ) * 43758.5453123);}float smoothNoise( vec2 ip ){vec2 lv = fract( ip );vec2 id = floor( ip );lv = lv * lv * ( 3. - 2. * lv );float bl = N( id );float br = N( id + vec2( 1, 0 ));float b = mix( bl, br, lv.x );float tl = N( id + vec2( 0, 1 ));float tr = N( id + vec2( 1, 1 ));float t = mix( tl, tr, lv.x );return mix( b, t, lv.y );}void main() {vUv = uv;float t = time * 2.;// 頂點位置vec4 mvPosition = vec4( position, 1.0 );#ifdef USE_INSTANCINGmvPosition = instanceMatrix * mvPosition;#endif// 移動float noise = smoothNoise(mvPosition.xz * 0.5 + vec2(0., t));noise = pow(noise * 0.5 + 0.5, 2.) * 2.;// 葉片頂部晃動力度.float dispPower = 1. - cos( uv.y * 3.1416 * 0.5 );float displacement = noise * ( 0.3 * dispPower );mvPosition.z -= displacement;//vec4 modelViewPosition = modelViewMatrix * mvPosition;gl_Position = projectionMatrix * modelViewPosition;}`;const fragmentShader = `varying vec2 vUv;void main() {vec3 baseColor = vec3( 0.41, 1.0, 0.5 );float clarity = ( vUv.y * 0.5 ) + 0.5;gl_FragColor = vec4( baseColor * clarity, 1 );}`;const uniforms = {time: {value: 0}}const leavesMaterial = new ShaderMaterial({vertexShader,fragmentShader,uniforms,side: DoubleSide});return leavesMaterial}

在構(gòu)造函數(shù)中調(diào)用initleavesMaterial方法并賦值給類實例leavesMaterial

this.leavesMaterial = this.initleavesMaterial()

初始化網(wǎng)格表面取樣器,用來在需要生成草的mesh上隨機(jī)取點,通過取到的點的位置來生成草

private initSampler(){this.sampler = new MeshSurfaceSampler(this.mesh).setWeightAttribute(null).build()}

在構(gòu)造函數(shù)中調(diào)用initSampler方法

this.initSampler()

寫一個生成草的方法makegrasses

private makegrasses(grassesAmount:number){const instanceNumber = grassesAmount;const dummy = new Object3D();const geometry = new PlaneGeometry( 0.1, 1, 1, 1 );geometry.translate( 0, 0.5, 0 ); // 吧草葉的最低點設(shè)置到0.const instancedMesh = new InstancedMesh( geometry, this.leavesMaterial, instanceNumber );this.scene.add(instancedMesh)const _position = new Vector3();const_normal = new Vector3();for ( let i=0 ; i<instanceNumber ; i++ ) {this.sampler.sample(_position,_normal)_normal.add(_position)dummy.position.set(_position.x,_position.y,_position.z)dummy.scale.setScalar( 0.2 + Math.random() *0.6 );dummy.rotation.y = Math.random()* Math.PI;dummy.updateMatrix();instancedMesh.setMatrixAt( i, dummy.matrix );}}

這里的草葉模型我們實例化一個簡單的PlaneGeometry,heightSegments參數(shù)控制草葉的高度分段,分段越多草葉在搖擺的時候的弧度越精細(xì)。而分段越多場景的總面數(shù)也就越多,出于性能考慮我分段只給了1,這樣草葉是筆直的在晃動。

最后我們寫一個公共方法update,用來刷新草葉動畫。

public update(){this.leavesMaterial.uniforms.time.value = this.clock.getElapsedTime();this.leavesMaterial.uniformsNeedUpdate = true;}

總結(jié)

以上是生活随笔為你收集整理的【threejs开发随笔】利用shaderMaterial制作草地的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。