上图
着色器设置点材质时,在顶点着色器中,最好设置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. radius
const 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 + randomX
position[ current + 1 ] = 0 + randomY
position[ current + 2 ] = Math. sin ( branchAngel) * distance + randomZ
const mixColor = galaxyColor. clone ( )
mixColor. lerp ( outGalaxyColor, distance / params. radius)
colors[ current] = mixColor. r
colors[ current + 1 ] = mixColor. g
colors[ current + 2 ] = mixColor. b
imgIndex[ 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 = elapsedTime
requestAnimationFrame ( animate)
renderer. render ( scene, camera)
}
animate ( )
window. addEventListener ( 'resize' , ( ) => {
camera. aspect = window. innerWidth / window. innerHeight
camera. 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) ;
}