토론

시네마틱 촬영, 강렬한 빛이 있는 행성 위의 추상적인 [주제/환경] 장

Wikiprompt, 무료 프롬프트 백과사전에서

loshu2000

2026년 5월 13일

시네마틱 촬영, 강렬한 빛이 있는 행성 위의 추상적인 [주제/환경] 장 3D 입자 효과 엔지니어로 활동하는 AI용 프롬프트: 메시-투-파티클 모핑, FBO, GPGPU, 노이즈 난기류를 갖춘 WebGL 전환 시스템 설계하기.

프롬프트 내용저장

🌐
퍼포먼스가 높은 WebGL 기반 전환 시스템을 설계하기 위해, 3D 파티클 효과 엔지니어로서 다음의 개념적 셰이더 로직과 핵심 JavaScript 구현을 제공합니다. --- ### 1. 개념적 셰이더 로직 #### (A) 파티클 위치 업데이트 (GPGPU - FBO 기반) **Vertex Shader (Pass 1: Update)** ```glsl // 입력: 이전 위치, 목표 위치(앵커), 속도, 노이즈 오프셋 attribute vec3 aPrevPosition; attribute vec3 aTargetPosition; attribute vec3 aVelocity; attribute float aLife; uniform float uTime; uniform float uDelta; uniform float uNoiseScale; uniform float uForceStrength; varying vec3 vColor; // 3D Simplex 노이즈 (간략화된 의사코드) float snoise(vec3 v) { /* ... 표준 구현 ... */ } void main() { vec3 pos = aPrevPosition; vec3 dirToTarget = aTargetPosition - pos; float dist = length(dirToTarget); // 인력 (Attraction) vec3 attraction = normalize(dirToTarget) * min(dist * 0.1, 1.0); // 노이즈 난류 (Noise Turbulence) vec3 noiseVec = vec3( snoise(pos * uNoiseScale + uTime * 0.5), snoise(pos * uNoiseScale + uTime * 0.3 + 100.0), snoise(pos * uNoiseScale + uTime * 0.7 + 200.0) ); // 속도 갱신 (관성 + 힘) vec3 newVelocity = aVelocity * 0.95 + (attraction + noiseVec) * uForceStrength; // 위치 갱신 vec3 newPos = pos + newVelocity * uDelta; // 속도 기반 동적 색상 (Velocity-based Color) float speed = length(newVelocity); vColor = mix(vec3(0.2, 0.6, 1.0), vec3(1.0, 0.3, 0.8), smoothstep(0.0, 2.0, speed)); // 결과 저장 (FBO 텍스처로 출력) gl_FragColor = vec4(newPos, 1.0); // 속도는 별도 텍스처에 저장하거나, 위치 텍스처의 alpha 채널에 인코딩 } ``` **Fragment Shader (Pass 1: Update)** ```glsl precision highp float; varying vec3 vColor; void main() { gl_FragColor = vec4(vColor, 1.0); } ``` #### (B) 파티클 렌더링 (Pass 2: Draw) **Vertex Shader (Draw)** ```glsl attribute vec2 aUV; // FBO 텍스처 좌표 uniform sampler2D uPositionTexture; uniform mat4 uProjectionMatrix; uniform mat4 uModelViewMatrix; uniform float uPointSize; void main() { // FBO에서 위치 읽기 vec3 pos = texture2D(uPositionTexture, aUV).xyz; vec4 mvPosition = uModelViewMatrix * vec4(pos, 1.0); gl_PointSize = uPointSize * (300.0 / -mvPosition.z); gl_Position = uProjectionMatrix * mvPosition; } ``` **Fragment Shader (Draw)** ```glsl precision highp float; varying vec3 vColor; // 필요 시 varying으로 전달 void main() { // 원형 파티클 (거리 기반 알파) vec2 center = gl_PointCoord - 0.5; float dist = length(center); if (dist > 0.5) discard; float alpha = 1.0 - smoothstep(0.0, 0.5, dist); gl_FragColor = vec4(vColor, alpha); } ``` --- ### 2. 핵심 JavaScript 구현 (Three.js + GPGPU) ```javascript import * as THREE from 'three'; import { GPUComputationRenderer } from 'three/examples/jsm/misc/GPUComputationRenderer.js'; class ParticleMorphSystem { constructor(scene, renderer, meshA, meshB, particleCount = 20000) { this.scene = scene; this.renderer = renderer; this.particleCount = particleCount; // 1. FBO 초기화 (GPGPU) this.gpuCompute = new GPUComputationRenderer(256, 256, renderer); this.positionTexture = this.gpuCompute.createTexture(); this.velocityTexture = this.gpuCompute.createTexture(); // 2. 메시에서 파티클 앵커 포인트 추출 const anchorsA = this.extractAnchors(meshA, particleCount); const anchorsB = this.extractAnchors(meshB, particleCount); // 3. 초기 위치 및 목표 위치 설정 this.initParticleData(anchorsA, anchorsB); // 4. GPGPU 셰이더 설정 this.setupGPGPU(); // 5. 렌더링용 파티클 지오메트리 생성 this.createParticleGeometry(); } // 3D 모델의 버텍스 데이터를 파티클 속성 버퍼로 매핑 extractAnchors(mesh, count) { const geometry = mesh.geometry; const positions = geometry.attributes.position.array; const vertexCount = positions.length / 3; // 샘플링 인덱스 (균등 분포) const indices = new Uint32Array(count); for (let i = 0; i < count; i++) { indices[i] = Math.floor(Math.random() * vertexCount); } // Float32Array로 앵커 포인트 저장 const anchors = new Float32Array(count * 3); for (let i = 0; i < count; i++) { const idx = indices[i] * 3; anchors[i * 3] = positions[idx]; anchors[i * 3 + 1] = positions[idx + 1]; anchors[i * 3 + 2] = positions[idx + 2]; } return anchors; } initParticleData(anchorsA, anchorsB) { const data = this.positionTexture.image.data; const velData = this.velocityTexture.image.data; for (let i = 0; i < this.particleCount; i++) { // 시작 위치: 메시 A의 표면 data[i * 4] = anchorsA[i * 3]; data[i * 4 + 1] = anchorsA[i * 3 + 1]; data[i * 4 + 2] = anchorsA[i * 3 + 2]; data[i * 4 + 3] = 1.0; // life // 목표 위치: 메시 B의 표면 (별도 텍스처에 저장하거나 uniform으로 전달) // 여기서는 간단히 두 번째 텍스처에 저장 velData[i * 4] = anchorsB[i * 3]; velData[i * 4 + 1] = anchorsB[i * 3 + 1]; velData[i * 4 + 2] = anchorsB[i * 3 + 2]; velData[i * 4 + 3] = 0.0; // 초기 속도 0 } } setupGPGPU() { // 위치 업데이트 셰이더 const updateShader = ` uniform float uTime; uniform float uDelta; uniform float uNoiseScale; uniform float uForceStrength; uniform sampler2D uTargetPositions; void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec4 posData = texture2D(positionTexture, uv); vec4 velData = texture2D(velocityTexture, uv); vec3 target = texture2D(uTargetPositions, uv).xyz; vec3 pos = posData.xyz; vec3 vel = velData.xyz; vec3 dirToTarget = target - pos; float dist = length(dirToTarget); // 인력 vec3 attraction = normalize(dirToTarget) * min(dist * 0.1, 1.0); // 노이즈 난류 (3D Simplex) vec3 noiseVec = vec3( snoise(pos * uNoiseScale + uTime * 0.5), snoise(pos * uNoiseScale + uTime * 0.3 + 100.0), snoise(pos * uNoiseScale + uTime * 0.7 + 200.0) ); // 속도 및 위치 갱신 vel = vel * 0.95 + (attraction + noiseVec) * uForceStrength; pos += vel * uDelta; gl_FragColor = vec4(pos, 1.0); } `; this.positionVariable = this.gpuCompute.addVariable('positionTexture', updateShader); this.gpuCompute.setVariableDependencies(this.positionVariable, [this.positionVariable]); // 목표 위치 텍스처 생성 const targetTexture = this.gpuCompute.createTexture(); targetTexture.image.data.set(this.anchorsB); this.gpuCompute.addUniform('uTargetPositions', targetTexture); } createParticleGeometry() { // 파티클 렌더링용 지오메트리 const geometry = new THREE.BufferGeometry(); const uvs = new Float32Array(this.particleCount * 2); // FBO 텍스처 좌표 생성 (256x256 그리드) const size = 256; for (let i = 0; i < this.particleCount; i++) { uvs[i * 2] = (i % size) / size; uvs[i * 2 + 1] = Math.floor(i / size) / size; } geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)); // 파티클 머티리얼 const material = new THREE.ShaderMaterial({ uniforms: { uPositionTexture: { value: null }, uProjectionMatrix: { value: null }, uModelViewMatrix: { value: null }, uPointSize: { value: 3.0 } }, vertexShader: `...`, // 위의 Draw Vertex Shader fragmentShader: `...`, // 위의 Draw Fragment Shader transparent: true, depthWrite: false, blending: THREE.AdditiveBlending }); this.particles = new THREE.Points(geometry, material); this.scene.add(this.particles); } // 애니메이션 루프에서 호출 update(time, delta) { // GPGPU 업데이트 실행 this.gpuCompute.compute(); // 렌더링 패스에 위치 텍스처 전달 this.particles.material.uniforms.uPositionTexture.value = this.gpuCompute.getCurrentRenderTarget(this.positionVariable).texture; // 셰이더에 시간 전달 this.gpuCompute.getUniforms().uTime.value = time; this.gpuCompute.getUniforms().uDelta.value = delta; } } ``` --- ### 3. 핵심 개념 설명 **메시 데이터 → 파티클 속성 버퍼 매핑:** 1. **버텍스 추출**: `geometry.attributes.position.array`에서 모든 버텍스 좌표를 읽습니다. 2. **랜덤 샘플링**: 파티클 수만큼 버텍스 인덱스를 무작위로 선택합니다 (균등 분포 보장). 3. **앵커 포인트 저장**: 선택된 좌표를 `Float32Array`로 변환하여 FBO 텍스처에 저장합니다. 4. **GPU 전송**: 텍스처 데이터로 변환하여 GPGPU 계산의 입력으로 사용합니다. **성능 최적화 팁:** - FBO 해상도를 파티클 수에 맞게 조정 (예: 20000개 → 256x256 = 65536 슬롯) - 노이즈 함수는 GLSL 내장 구현 사용 (ASHIMA 또는 Stefan Gustavson의 Simplex) - 파티클 수가 많을 경우 LOD(Level of Detail) 시스템 도입 이 시스템은 토러스에서 커스텀 GLTF 모델로의 형태 변환을 수천 개의 인터랙티브 파티클로 표현하며, 모든 계산이 GPU에서 수행되어 60fps를 유지할 수 있습니다.

전체 프롬프트를 보려면 로그인하세요

Continue with:

By logging in, you agree to our Terms of Use and Privacy Policy

사용법

이 프롬프트는 coding와 함께 사용하도록 설계되었습니다. 위의 프롬프트 내용을 복사하여 원하는 AI 도구에 붙여넣으세요.

최상의 결과를 얻으려면 자리 표시자(대괄호 또는 대문자로 표시)를 특정 요구 사항으로 사용자 지정할 수 있습니다.

참고 자료

분류:coding| prompts.chat| 3d-particle-effects| webgl

토론