上图
着色器设置点材质时,在顶点着色器中,最好设置gl_PointSize,不然看不到你在页面中添加的点
main.js
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import gsap from 'gsap' import theVertexShader from './shader/13/vertex.glsl?raw'
import theFragmentShader from './shader/13/fragment.glsl?raw' const scene = new THREE. Scene ( ) const camera = new THREE. PerspectiveCamera ( 75 , window. innerHeight / window. innerHeight, 0.1 , 1000 )
camera. position. set ( 0 , 0 , 5 )
camera. aspect = window. innerWidth / window. innerHeight
scene. add ( camera) const axesHelper = new THREE. AxesHelper ( 5 )
scene. add ( axesHelper)
const textureLoader = new THREE. TextureLoader ( )
let texture = textureLoader. load ( '../public/assets/texture/particles/9.png' )
let texture1 = textureLoader. load ( '../public/assets/texture/particles/10.png' )
let texture2 = textureLoader. load ( '../public/assets/texture/particles/11.png' ) const params = { count : 1000 , size : 0.1 , radius : 5 , branch : 4 , color : '#ff6030' , outColor : '#1b3984'
} let geometry = null
let material = null
let point = null
let galaxyColor = new THREE. Color ( params. color)
let outGalaxyColor = new THREE. Color ( params. outColor) const generateGalaxy = ( ) => { if ( point !== null ) { geometry. dispose ( ) material. dispose ( ) scene. remove ( point) } geometry = new THREE. BufferGeometry ( ) const position = new Float32Array ( params. count * 3 ) const colors = new Float32Array ( params. count * 3 ) const imgIndex = new Float32Array ( params. count) const size_arr = new Float32Array ( params. count) for ( let i = 0 ; i < params. count; i++ ) { const current = i * 3 const branchAngel = ( i % params. branch) * ( ( 2 * Math. PI ) / params. branch) const distance = Math. random ( ) * params. radiusconst randomX = ( Math. pow ( Math. random ( ) * 2 - 1 , 3 ) * ( params. radius - distance) ) / 5 const randomY = ( Math. pow ( Math. random ( ) * 2 - 1 , 3 ) * ( params. radius - distance) ) / 5 const randomZ = ( Math. pow ( Math. random ( ) * 2 - 1 , 3 ) * ( params. radius - distance) ) / 5 position[ current] = Math. cos ( branchAngel) * distance + randomXposition[ current + 1 ] = 0 + randomYposition[ current + 2 ] = Math. sin ( branchAngel) * distance + randomZconst mixColor = galaxyColor. clone ( ) mixColor. lerp ( outGalaxyColor, distance / params. radius) colors[ current] = mixColor. rcolors[ current + 1 ] = mixColor. gcolors[ current + 2 ] = mixColor. bimgIndex[ current] = i % 3 size_arr[ current] = Math. random ( ) } geometry. setAttribute ( 'position' , new THREE. BufferAttribute ( position, 3 ) ) geometry. setAttribute ( 'color' , new THREE. BufferAttribute ( colors, 3 ) ) geometry. setAttribute ( 'imgIndex' , new THREE. BufferAttribute ( imgIndex, 1 ) ) geometry. setAttribute ( 'asize' , new THREE. BufferAttribute ( size_arr, 1 ) ) material = new THREE. ShaderMaterial ( { vertexShader : theVertexShader, fragmentShader : theFragmentShader, transparent : true , vertexColors : true , depthWrite : false , blending : THREE . AdditiveBlending, uniforms : { uTime : { value : 0 } , uTexture : { value : texture} , uTexture1 : { value : texture1} , uTexture2 : { value : texture2} , uColor : { value : galaxyColor} } } ) point = new THREE. Points ( geometry, material) scene. add ( point)
} generateGalaxy ( ) const renderer = new THREE. WebGLRenderer ( )
renderer. shadowMap. enabled = true
renderer. setSize ( window. innerWidth, window. innerHeight)
document. body. appendChild ( renderer. domElement) const controls = new OrbitControls ( camera, renderer. domElement)
controls. enableDamping = true
controls. dampingFactor = 0.01 const clock = new THREE. Clock ( )
function animate ( ) { const elapsedTime = clock. getElapsedTime ( ) material. uniforms. uTime. value = elapsedTimerequestAnimationFrame ( animate) renderer. render ( scene, camera)
}
animate ( ) window. addEventListener ( 'resize' , ( ) => { camera. aspect = window. innerWidth / window. innerHeightcamera. updateProjectionMatrix ( ) renderer. setSize ( window. innerWidth, window. innerHeight) renderer. setPixelRatio ( window. devicePixelRatio)
} )
vertex.glsl
precision lowp float; varying vec2 vUv; attribute float asize;
attribute float imgIndex;
varying float vImgIndex; uniform float uTime; varying vec3 vColor; void main ( ) { vUv = uv; vColor = color; vImgIndex = imgIndex; vec4 modelPosition = modelMatrix* vec4 ( position, 1.0 ) ; ` 获取顶点的角度注:【atan(y, x)】计算两点之间的角度(以弧度为单位) ` float angle = atan ( modelPosition. x, modelPosition. z) ; ` 获取顶点到中心的距离注:按道理得这么写:【length(vec2(modelPosition.x, modelPosition.z))】如果 modelPosition 是一个三维向量,并且,你只需要 x 和 z 分量,length(modelPosition.xz)这样写也可以 ` float distanceToCenter = length ( modelPosition. xz) ; ` 角度偏移angleOffset,是基于,顶点到中心距离的倒数,乘以时间uTime来计算的这种方法会导致:当顶点接近中心时,偏移量变得非常大,导致快速旋转 ` float angleOffset = 1.0 / distanceToCenter* uTime; ` 当前旋转的度数 ` angle = angle+ angleOffset; modelPosition. x = cos ( angle) * distanceToCenter; modelPosition. z = sin ( angle) * distanceToCenter; vec4 viewPosition = viewMatrix* modelPosition; gl_Position = projectionMatrix* viewPosition; ` 不设置 gl_PointSize 页面上就啥也没有1、GLSL中, ` gl_PointSize` 是一个特殊的输出变量,用于,设置点渲染时点的大小,2、以【gl_PointSize = 200.0/-viewPosition.z*asize】为例:涉及,视点空间中,顶点的z坐标(viewPosition.z),和一个属性asize的值 ` gl_PointSize = 200.0 / - viewPosition. z* asize;
}
fragment.glsl
precision lowp float; uniform sampler2D uTexture;
uniform sampler2D uTexture1;
uniform sampler2D uTexture2; varying float vImgIndex; varying vec3 vColor; void main ( ) { vec4 textureColor; if ( vImgIndex== 0.0 ) { textureColor = texture2D ( uTexture, gl_PointCoord) ; } else if ( vImgIndex== 1.0 ) { textureColor = texture2D ( uTexture1, gl_PointCoord) ; } else { textureColor = texture2D ( uTexture2, gl_PointCoord) ; } gl_FragColor = vec4 ( vColor, textureColor. r) ;
}