球几何体
// 创建球几何体
const sphereGeometry = new THREE.SphereGeometry(3, 20, 20)
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true // 以线框的形式显示顶点
})
const mesh = new THREE.Mesh(sphereGeometry, material)
scene.add(mesh)
点实现球体
// 创建球几何体
const sphereGeometry = new THREE.SphereGeometry(3, 20, 20)
const pointsMaterial = new THREE.PointsMaterial({
size: 0.1, // 点的大小,默认是1.0
color: 0xfff000,
sizeAttenuation: false, // 是否因相机的深度而衰减(近大远小), 默认为true
}) // 点材质
const points = new THREE.Points(sphereGeometry, pointsMaterial)
scene.add(points)
点材质
这里打算是将圆形贴图用在每个点上面,没想到在固定模型下是整体修改 ,通过自定义顶点才可以实现该效果
// 添加纹理
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load(`./circle_05.png`)
// 创建球几何体
const sphereGeometry = new THREE.SphereGeometry(3, 30, 30)
const pointsMaterial = new THREE.PointsMaterial({
size: 0.1, // 点的大小,默认是1.0
color: 0xfff000,
// sizeAttenuation: false, // 是否因相机的深度而衰减(近大远小), 默认为true
map: texture, // 纹理贴图
alphaMap: texture, // 灰度贴图
transparent: true, // 允许透明
depthWrite: false,
// 默认true,渲染引擎会记录每个渲染对象的深度信息,渲染引擎就能知道哪些对象应该被其他对象遮挡,从而创建出具有正确深度感的3D场景。
// false,渲染引擎不会记录对象的深度信息,如果你有一个透明的窗户,你希望它后面的物体可见
blending: THREE.AdditiveBlending // 混合模式:叠加; 当两个或多个对象在屏幕上重叠时,它们的颜色如何组合
}) // 点材质
const points = new THREE.Points(sphereGeometry, pointsMaterial)
scene.add(points)
自定义顶点着色器,打造漫天星空(缓冲区实现)
<template>
<div id="webgl"></div>
</template>
<script setup>
import * as THREE from 'three'
//导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入 dat.gui
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
const gui = new GUI();
//1.创建场景
const scene = new THREE.Scene()
//2.创建相机 角度 宽高比 近端 远端
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 设置相机位置 x y z
camera.position.set(0, 0, 10)
// 把相机添加到场景中
scene.add(camera)
// 封装创建点(可绘制多个不同样的)
const createPoints = (url, size = 0.5) => {
// 添加纹理
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load(`/${url}.png`)
const particlesGeometry = new THREE.BufferGeometry()
const count = 5000
const position = new Float32Array(count * 3)
const colors = new Float32Array(count * 3)
for (let i = 0; i < count * 3; i++) {
position[i] = Math.random() * 10 - 5 // -5 ~ 5
colors[i] = Math.random()
}
particlesGeometry.setAttribute('position', new THREE.BufferAttribute(position, 3))
particlesGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
// 创建球几何体
const pointsMaterial = new THREE.PointsMaterial({
size, // 点的大小,默认是1.0
// color: 0xfff000,
// sizeAttenuation: false, // 是否因相机的深度而衰减(近大远小), 默认为true
map: texture, // 纹理贴图
alphaMap: texture, // 灰度贴图
transparent: true, // 允许透明
depthWrite: false,
// 默认true,渲染引擎会记录每个渲染对象的深度信息,渲染引擎就能知道哪些对象应该被其他对象遮挡,从而创建出具有正确深度感的3D场景。
// false,渲染引擎不会记录对象的深度信息,如果你有一个透明的窗户,你希望它后面的物体可见
blending: THREE.AdditiveBlending, // 混合模式:叠加; 当两个或多个对象在屏幕上重叠时,它们的颜色如何组合
vertexColors: true // 设置启动顶点的颜色
}) // 点材质
const points = new THREE.Points(particlesGeometry, pointsMaterial)
scene.add(points)
return points;
}
const points1 = createPoints("circle_05", 0.1);
const points2 = createPoints("circle_05", 0.1);
// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true
renderer.physicallyCorrectLights = true
// 将webgel渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器的阻尼 更真实 惯性
controls.enableDamping = true
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
// 设置时钟
const clock = new THREE.Clock()
function render() {
points1.rotation.x = clock.getElapsedTime() * 0.1
// 斜着飘
points2.rotation.x = clock.getElapsedTime() * 0.1
points2.rotation.y = clock.getElapsedTime() * 0.1
controls.update()
// 使用渲染器,通过相机将场景渲染进来
renderer.render(scene, camera);
// 渲染下一帧的时候 调用 render函数
requestAnimationFrame(render)
}
render()
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight)
// 设置渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio)
})
</script>
运用数学知识打造复杂形状必状旋星系
for (let i = 0; i < params.count; i++) {
// 当前的点应该在哪一条分支的角度上 取余012,360/3
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch)
// 当前点距离圆心的距离
const distance = Math.random() * params.radius // 0到5的随机数
// 根据距离+弯曲的程度
const current = i * 3;
positions[current] = Math.cos(branchAngel) * distance
positions[current + 1] = 0
positions[current + 2] = Math.sin(branchAngel) * distance
}
for (let i = 0; i < params.count; i++) {
// 当前的点应该在哪一条分支的角度上 取余012,360/3
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch)
// 当前点距离圆心的距离
const distance = Math.random() * params.radius // 0到5的随机数
// 根据距离+弯曲的程度
const current = i * 3;
positions[current] = Math.cos(branchAngel + distance * params.rotateScale) * distance
positions[current + 1] = 0
positions[current + 2] = Math.sin(branchAngel + distance * params.rotateScale) * distance
}
for (let i = 0; i < params.count; i++) {
// 当前的点应该在哪一条分支的角度上 取余012,360/3
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch)
// 当前点距离圆心的距离
const distance = Math.random() * params.radius // 0到5的随机数
const randomX = Math.pow(Math.random() * 2 - 1, 3) // -1到1,3次方
const randomY = Math.pow(Math.random() * 2 - 1, 3)
const randomZ = Math.pow(Math.random() * 2 - 1, 3)
// 根据距离+弯曲的程度
const current = i * 3;
positions[current] = Math.cos(branchAngel + distance * params.rotateScale) * distance + randomX
positions[current + 1] = 0 + randomY
positions[current + 2] = Math.sin(branchAngel + distance * params.rotateScale) * distance + randomZ
}
for (let i = 0; i < params.count; i++) {
// 当前的点应该在哪一条分支的角度上 取余012,360/3
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch)
// 当前点距离圆心的距离
const distance = Math.random() * params.radius // 0到5的随机数
const randomX = Math.pow(Math.random() * 2 - 1, 3) * distance / 5 // 也可以用 distance 中间少两边厚,取反则是 (params.radius - distance)
const randomY = Math.pow(Math.random() * 2 - 1, 3) * distance / 5
const randomZ = Math.pow(Math.random() * 2 - 1, 3) * distance / 5
// 根据距离+弯曲的程度
const current = i * 3;
positions[current] = Math.cos(branchAngel + distance * params.rotateScale) * distance + randomX
positions[current + 1] = 0 + randomY
positions[current + 2] = Math.sin(branchAngel + distance * params.rotateScale) * distance + randomZ
}
<template>
<div id="webgl"></div>
</template>
<script setup>
import * as THREE from 'three'
//导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入 dat.gui
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 目标:点光源
const gui = new GUI();
//1.创建场景
const scene = new THREE.Scene()
//2.创建相机 角度 宽高比 近端 远端
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 设置相机位置 x y z
camera.position.set(0, 0, 10)
// 把相机添加到场景中
scene.add(camera)
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load(`./circle_05.png`)
const params = {
count: 800, // 数量
size: 0.1, // 大小
radius: 5, // 半径
branch: 3, // 分支
color: '#ffffff',
rotateScale: 0.3, // 弯曲程度
endColor: '#1b3984'
}
let geometry = null
let material = null
let points = null
const centerColor = new THREE.Color(params.color)
const endColor = new THREE.Color(params.endColor)
const generateGalaxy = () => {
// 生成顶点
geometry = new THREE.BufferGeometry()
// 随机生成位置
const positions = new Float32Array(params.count * 3)
// 设置顶点颜色
const colors = new Float32Array(params.count * 3)
// 循环生成点
for (let i = 0; i < params.count; i++) {
// 当前的点应该在哪一条分支的角度上 取余012,360/3
const branchAngel = (i % params.branch) * ((2 * Math.PI) / params.branch)
// 当前点距离圆心的距离
const distance = Math.random() * params.radius * Math.pow(Math.random(), 3) // 0到5的随机数
const randomX = Math.pow(Math.random() * 2 - 1, 3) * (params.radius - distance) / 5 // 也可以用 distance 中间少两边厚,取反则是 (params.radius - distance)
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
// 根据距离+弯曲的程度
const current = i * 3;
positions[current] = Math.cos(branchAngel + distance * params.rotateScale) * distance + randomX
positions[current + 1] = 0 + randomY
positions[current + 2] = Math.sin(branchAngel + distance * params.rotateScale) * distance + randomZ
// 混合颜色,形成渐变色
const mixColor = centerColor.clone()
mixColor.lerp(endColor, distance / params.radius) // 当前点距离圆心的距离/半径
colors[current] = mixColor.r
colors[current + 1] = mixColor.g
colors[current + 2] = mixColor.b
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))
material = new THREE.PointsMaterial({
size: params.size, // 点的大小,默认是1.0
// color: params.color,
// sizeAttenuation: false, // 是否因相机的深度而衰减(近大远小), 默认为true
map: texture, // 纹理贴图
alphaMap: texture, // 灰度贴图
transparent: true, // 允许透明
depthWrite: false, // 深度缓冲区写入,默认为true
blending: THREE.AdditiveBlending, // 混合模式, 此时用的是前后材质会叠加
vertexColors: true
}) // 点材质
points = new THREE.Points(geometry, material)
scene.add(points)
}
generateGalaxy()
// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true
renderer.physicallyCorrectLights = true
// 将webgel渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器的阻尼 更真实 惯性
controls.enableDamping = true
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
// 设置时钟
const clock = new THREE.Clock()
function render() {
controls.update()
// 使用渲染器,通过相机将场景渲染进来
renderer.render(scene, camera);
// 渲染下一帧的时候 调用 render函数
requestAnimationFrame(render)
}
render()
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 更新渲染器
renderer.setSize(window.innerWidth, window.innerHeight)
// 设置渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio)
})
</script>