移动skill位置
This commit is contained in:
305
.codex/skills/webgpu-threejs-tsl/templates/compute-shader.js
Normal file
305
.codex/skills/webgpu-threejs-tsl/templates/compute-shader.js
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Compute Shader Template
|
||||
*
|
||||
* A template for GPU compute shaders with:
|
||||
* - Storage buffer setup
|
||||
* - Initialize and update shaders
|
||||
* - Visualization with instanced mesh
|
||||
*
|
||||
* Usage:
|
||||
* 1. Modify PARTICLE_COUNT and buffer types
|
||||
* 2. Implement your initialization logic
|
||||
* 3. Implement your update logic
|
||||
* 4. Customize visualization
|
||||
*/
|
||||
|
||||
import * as THREE from 'three/webgpu';
|
||||
import {
|
||||
Fn,
|
||||
If,
|
||||
Loop,
|
||||
float,
|
||||
int,
|
||||
vec2,
|
||||
vec3,
|
||||
vec4,
|
||||
color,
|
||||
uniform,
|
||||
instancedArray,
|
||||
instanceIndex,
|
||||
hash,
|
||||
time,
|
||||
deltaTime
|
||||
} from 'three/tsl';
|
||||
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
|
||||
// ============================================
|
||||
// CONFIGURATION
|
||||
// ============================================
|
||||
|
||||
const PARTICLE_COUNT = 50000;
|
||||
|
||||
// ============================================
|
||||
// STORAGE BUFFERS
|
||||
// ============================================
|
||||
|
||||
// Define your storage buffers here
|
||||
// Available types: 'float', 'vec2', 'vec3', 'vec4', 'int', 'uint'
|
||||
|
||||
const positions = instancedArray(PARTICLE_COUNT, 'vec3');
|
||||
const velocities = instancedArray(PARTICLE_COUNT, 'vec3');
|
||||
// Add more buffers as needed:
|
||||
// const colors = instancedArray(PARTICLE_COUNT, 'vec3');
|
||||
// const lifetimes = instancedArray(PARTICLE_COUNT, 'float');
|
||||
// const states = instancedArray(PARTICLE_COUNT, 'uint');
|
||||
|
||||
// ============================================
|
||||
// UNIFORMS
|
||||
// ============================================
|
||||
|
||||
const dt = uniform(0);
|
||||
// Add your uniforms here:
|
||||
// const gravity = uniform(-9.8);
|
||||
// const attractorPosition = uniform(new THREE.Vector3());
|
||||
// const forceStrength = uniform(1.0);
|
||||
|
||||
// ============================================
|
||||
// COMPUTE SHADERS
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Initialize particles
|
||||
* Called once at startup
|
||||
*/
|
||||
const computeInit = Fn(() => {
|
||||
const position = positions.element(instanceIndex);
|
||||
const velocity = velocities.element(instanceIndex);
|
||||
|
||||
// ========================================
|
||||
// IMPLEMENT YOUR INITIALIZATION HERE
|
||||
// ========================================
|
||||
|
||||
// Example: Random positions in a cube
|
||||
position.x.assign(hash(instanceIndex).sub(0.5).mul(10));
|
||||
position.y.assign(hash(instanceIndex.add(1)).sub(0.5).mul(10));
|
||||
position.z.assign(hash(instanceIndex.add(2)).sub(0.5).mul(10));
|
||||
|
||||
// Example: Zero velocity
|
||||
velocity.assign(vec3(0));
|
||||
})().compute(PARTICLE_COUNT);
|
||||
|
||||
/**
|
||||
* Update particles each frame
|
||||
* Called every frame in animation loop
|
||||
*/
|
||||
const computeUpdate = Fn(() => {
|
||||
const position = positions.element(instanceIndex);
|
||||
const velocity = velocities.element(instanceIndex);
|
||||
|
||||
// ========================================
|
||||
// IMPLEMENT YOUR UPDATE LOGIC HERE
|
||||
// ========================================
|
||||
|
||||
// Example: Simple gravity
|
||||
velocity.y.addAssign(float(-9.8).mul(dt));
|
||||
|
||||
// Example: Update position
|
||||
position.addAssign(velocity.mul(dt));
|
||||
|
||||
// Example: Ground bounce
|
||||
If(position.y.lessThan(0), () => {
|
||||
position.y.assign(0);
|
||||
velocity.y.assign(velocity.y.negate().mul(0.8));
|
||||
});
|
||||
|
||||
// Example: Boundary wrapping
|
||||
// If(position.x.abs().greaterThan(5), () => {
|
||||
// position.x.assign(position.x.negate());
|
||||
// });
|
||||
})().compute(PARTICLE_COUNT);
|
||||
|
||||
/**
|
||||
* Optional: Additional compute pass (e.g., for interactions)
|
||||
*/
|
||||
const computeInteraction = Fn(() => {
|
||||
const position = positions.element(instanceIndex);
|
||||
const velocity = velocities.element(instanceIndex);
|
||||
|
||||
// ========================================
|
||||
// IMPLEMENT INTERACTION LOGIC HERE
|
||||
// ========================================
|
||||
|
||||
// Example: Attract to point
|
||||
// const toTarget = attractorPosition.sub(position);
|
||||
// const dist = toTarget.length();
|
||||
// const force = toTarget.normalize().mul(forceStrength).div(dist.add(0.1));
|
||||
// velocity.addAssign(force.mul(dt));
|
||||
})().compute(PARTICLE_COUNT);
|
||||
|
||||
// ============================================
|
||||
// VISUALIZATION
|
||||
// ============================================
|
||||
|
||||
function createVisualization(scene) {
|
||||
// Choose visualization type:
|
||||
// - Points (fastest, simplest)
|
||||
// - Instanced Mesh (more control)
|
||||
|
||||
// Option 1: Points
|
||||
// return createPointsVisualization(scene);
|
||||
|
||||
// Option 2: Instanced Mesh
|
||||
return createInstancedVisualization(scene);
|
||||
}
|
||||
|
||||
function createPointsVisualization(scene) {
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute(
|
||||
'position',
|
||||
new THREE.Float32BufferAttribute(new Float32Array(PARTICLE_COUNT * 3), 3)
|
||||
);
|
||||
|
||||
const material = new THREE.PointsNodeMaterial();
|
||||
|
||||
// Position from compute buffer
|
||||
material.positionNode = positions.element(instanceIndex);
|
||||
|
||||
// ========================================
|
||||
// CUSTOMIZE POINT APPEARANCE HERE
|
||||
// ========================================
|
||||
|
||||
material.sizeNode = float(3.0);
|
||||
|
||||
material.colorNode = Fn(() => {
|
||||
// Example: Color based on velocity
|
||||
const velocity = velocities.element(instanceIndex);
|
||||
const speed = velocity.length();
|
||||
return mix(color(0x0066ff), color(0xff6600), speed.div(5).saturate());
|
||||
})();
|
||||
|
||||
const points = new THREE.Points(geometry, material);
|
||||
scene.add(points);
|
||||
return points;
|
||||
}
|
||||
|
||||
function createInstancedVisualization(scene) {
|
||||
// Geometry for each instance
|
||||
const geometry = new THREE.SphereGeometry(0.05, 8, 8);
|
||||
// Or use simpler geometry for better performance:
|
||||
// const geometry = new THREE.IcosahedronGeometry(0.05, 0);
|
||||
|
||||
const material = new THREE.MeshStandardNodeMaterial();
|
||||
|
||||
// Position from compute buffer
|
||||
material.positionNode = positions.element(instanceIndex);
|
||||
|
||||
// ========================================
|
||||
// CUSTOMIZE MESH APPEARANCE HERE
|
||||
// ========================================
|
||||
|
||||
material.colorNode = Fn(() => {
|
||||
// Example: Color based on position
|
||||
const position = positions.element(instanceIndex);
|
||||
return color(0x0088ff).add(position.mul(0.05));
|
||||
})();
|
||||
|
||||
material.roughnessNode = float(0.5);
|
||||
material.metalnessNode = float(0.2);
|
||||
|
||||
const mesh = new THREE.InstancedMesh(geometry, material, PARTICLE_COUNT);
|
||||
scene.add(mesh);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MAIN SETUP
|
||||
// ============================================
|
||||
|
||||
let camera, scene, renderer, controls;
|
||||
let visualization;
|
||||
|
||||
async function init() {
|
||||
// Scene
|
||||
scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x111122);
|
||||
|
||||
// Camera
|
||||
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
|
||||
camera.position.set(0, 5, 15);
|
||||
|
||||
// Lights
|
||||
const ambientLight = new THREE.AmbientLight(0x404040);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
|
||||
directionalLight.position.set(5, 10, 5);
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Optional: Ground plane
|
||||
const ground = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry(20, 20),
|
||||
new THREE.MeshStandardNodeMaterial({ color: 0x333333 })
|
||||
);
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
scene.add(ground);
|
||||
|
||||
// Renderer
|
||||
renderer = new THREE.WebGPURenderer({ antialias: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
document.body.appendChild(renderer.domElement);
|
||||
await renderer.init();
|
||||
|
||||
// Initialize particles
|
||||
await renderer.computeAsync(computeInit);
|
||||
|
||||
// Create visualization
|
||||
visualization = createVisualization(scene);
|
||||
|
||||
// Controls
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.enableDamping = true;
|
||||
controls.target.set(0, 2, 0);
|
||||
|
||||
// Events
|
||||
window.addEventListener('resize', onWindowResize);
|
||||
|
||||
// Start
|
||||
renderer.setAnimationLoop(animate);
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
}
|
||||
|
||||
const clock = new THREE.Clock();
|
||||
|
||||
function animate() {
|
||||
// Update delta time uniform
|
||||
dt.value = Math.min(clock.getDelta(), 0.1);
|
||||
|
||||
// Run compute shaders
|
||||
renderer.compute(computeUpdate);
|
||||
// renderer.compute(computeInteraction);
|
||||
|
||||
// Update controls
|
||||
controls.update();
|
||||
|
||||
// Render
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
init().catch(console.error);
|
||||
|
||||
// Export for external control
|
||||
export {
|
||||
positions,
|
||||
velocities,
|
||||
dt,
|
||||
computeInit,
|
||||
computeUpdate,
|
||||
computeInteraction
|
||||
};
|
||||
Reference in New Issue
Block a user