1 Star 0 Fork 0

ing10010/verge3d-code-examples

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
webgl_gpgpu_protoplanet.html 15.16 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
<!DOCTYPE html>
<html lang="en">
<head>
<title>Verge3D webgl - gpgpu - protoplanet</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
#warning {
color: #ff0000;
}
</style>
</head>
<body>
<div id="info">
<a href="https://www.soft8soft.com/verge3d" target="_blank" rel="noopener">Verge3D</a> - <span id="protoplanets"></span> webgl gpgpu debris
</div>
<!-- Fragment shader for protoplanet's position -->
<script id="computeShaderPosition" type="x-shader/x-fragment">
#define delta (1.0 / 60.0)
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec4 tmpPos = texture2D(texturePosition, uv);
vec3 pos = tmpPos.xyz;
vec4 tmpVel = texture2D(textureVelocity, uv);
vec3 vel = tmpVel.xyz;
float mass = tmpVel.w;
if (mass == 0.0) {
vel = vec3(0.0);
}
// Dynamics
pos += vel * delta;
gl_FragColor = vec4(pos, 1.0);
}
</script>
<!-- Fragment shader for protoplanet's velocity -->
<script id="computeShaderVelocity" type="x-shader/x-fragment">
// For PI declaration:
#include <common>
#define delta (1.0 / 60.0)
uniform float gravityConstant;
uniform float density;
const float width = resolution.x;
const float height = resolution.y;
float radiusFromMass(float mass) {
// Calculate radius of a sphere from mass and density
return pow((3.0 / (4.0 * PI)) * mass / density, 1.0 / 3.0);
}
void main() {
vec2 uv = gl_FragCoord.xy / resolution.xy;
float idParticle = uv.y * resolution.x + uv.x;
vec4 tmpPos = texture2D(texturePosition, uv);
vec3 pos = tmpPos.xyz;
vec4 tmpVel = texture2D(textureVelocity, uv);
vec3 vel = tmpVel.xyz;
float mass = tmpVel.w;
if (mass > 0.0) {
float radius = radiusFromMass(mass);
vec3 acceleration = vec3(0.0);
// Gravity interaction
for (float y = 0.0; y < height; y++) {
for (float x = 0.0; x < width; x++) {
vec2 secondParticleCoords = vec2(x + 0.5, y + 0.5) / resolution.xy;
vec3 pos2 = texture2D(texturePosition, secondParticleCoords).xyz;
vec4 velTemp2 = texture2D(textureVelocity, secondParticleCoords);
vec3 vel2 = velTemp2.xyz;
float mass2 = velTemp2.w;
float idParticle2 = secondParticleCoords.y * resolution.x + secondParticleCoords.x;
if (idParticle == idParticle2) {
continue;
}
if (mass2 == 0.0) {
continue;
}
vec3 dPos = pos2 - pos;
float distance = length(dPos);
float radius2 = radiusFromMass(mass2);
if (distance == 0.0) {
continue;
}
// Checks collision
if (distance < radius + radius2) {
if (idParticle < idParticle2) {
// This particle is aggregated by the other
vel = (vel * mass + vel2 * mass2) / (mass + mass2);
mass += mass2;
radius = radiusFromMass(mass);
}
else {
// This particle dies
mass = 0.0;
radius = 0.0;
vel = vec3(0.0);
break;
}
}
float distanceSq = distance * distance;
float gravityField = gravityConstant * mass2 / distanceSq;
gravityField = min(gravityField, 1000.0);
acceleration += gravityField * normalize(dPos);
}
if (mass == 0.0) {
break;
}
}
// Dynamics
vel += delta * acceleration;
}
gl_FragColor = vec4(vel, mass);
}
</script>
<!-- Particles vertex shader -->
<script type="x-shader/x-vertex" id="particleVertexShader">
// For PI declaration:
#include <common>
uniform sampler2D texturePosition;
uniform sampler2D textureVelocity;
uniform float cameraConstant;
uniform float density;
varying vec4 vColor;
float radiusFromMass(float mass) {
// Calculate radius of a sphere from mass and density
return pow((3.0 / (4.0 * PI)) * mass / density, 1.0 / 3.0);
}
void main() {
vec4 posTemp = texture2D(texturePosition, uv);
vec3 pos = posTemp.xyz;
vec4 velTemp = texture2D(textureVelocity, uv);
vec3 vel = velTemp.xyz;
float mass = velTemp.w;
vColor = vec4(1.0, mass / 250.0, 0.0, 1.0);
vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
// Calculate radius of a sphere from mass and density
//float radius = pow((3.0 / (4.0 * PI)) * mass / density, 1.0 / 3.0);
float radius = radiusFromMass(mass);
// Apparent size in pixels
if (mass == 0.0) {
gl_PointSize = 0.0;
}
else {
gl_PointSize = radius * cameraConstant / (- mvPosition.z);
}
gl_Position = projectionMatrix * mvPosition;
}
</script>
<!-- Particles fragment shader -->
<script type="x-shader/x-fragment" id="particleFragmentShader">
varying vec4 vColor;
void main() {
float f = length(gl_PointCoord - vec2(0.5, 0.5));
if (f > 0.5) {
discard;
}
gl_FragColor = vColor;
}
</script>
<script type="module">
import * as v3d from '../build/v3d.module.js';
import Stats from './jsm/libs/stats.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { GPUComputationRenderer } from './jsm/misc/GPUComputationRenderer.js';
const isIE = /Trident/i.test(navigator.userAgent);
const isEdge = /Edge/i.test(navigator.userAgent);
// Texture width for simulation (each texel is a debris particle)
const WIDTH = (isIE || isEdge) ? 4 : 64;
let container, stats;
let camera, scene, renderer, geometry;
const PARTICLES = WIDTH * WIDTH;
let gpuCompute;
let velocityVariable;
let positionVariable;
let velocityUniforms;
let particleUniforms;
let effectController;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new v3d.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 5, 15000);
camera.position.y = 120;
camera.position.z = 400;
scene = new v3d.Scene();
renderer = new v3d.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 100;
controls.maxDistance = 1000;
effectController = {
// Can be changed dynamically
gravityConstant: 100.0,
density: 0.45,
// Must restart simulation
radius: 300,
height: 8,
exponent: 0.4,
maxMass: 15.0,
velocity: 70,
velocityExponent: 0.2,
randVelocity: 0.001
};
initComputeRenderer();
stats = new Stats();
container.appendChild(stats.dom);
window.addEventListener('resize', onWindowResize, false);
initGUI();
initProtoplanets();
dynamicValuesChanger();
}
function initComputeRenderer() {
gpuCompute = new GPUComputationRenderer(WIDTH, WIDTH, renderer);
if (isSafari()) {
gpuCompute.setDataType(v3d.HalfFloatType);
}
const dtPosition = gpuCompute.createTexture();
const dtVelocity = gpuCompute.createTexture();
fillTextures(dtPosition, dtVelocity);
velocityVariable = gpuCompute.addVariable("textureVelocity", document.getElementById('computeShaderVelocity').textContent, dtVelocity);
positionVariable = gpuCompute.addVariable("texturePosition", document.getElementById('computeShaderPosition').textContent, dtPosition);
gpuCompute.setVariableDependencies(velocityVariable, [positionVariable, velocityVariable]);
gpuCompute.setVariableDependencies(positionVariable, [positionVariable, velocityVariable]);
velocityUniforms = velocityVariable.material.uniforms;
velocityUniforms["gravityConstant"] = { value: 0.0 };
velocityUniforms["density"] = { value: 0.0 };
const error = gpuCompute.init();
if (error !== null) {
console.error(error);
}
}
function isSafari() {
return !! navigator.userAgent.match(/Safari/i) && ! navigator.userAgent.match(/Chrome/i);
}
function restartSimulation() {
const dtPosition = gpuCompute.createTexture();
const dtVelocity = gpuCompute.createTexture();
fillTextures(dtPosition, dtVelocity);
gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[0]);
gpuCompute.renderTexture(dtPosition, positionVariable.renderTargets[1]);
gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[0]);
gpuCompute.renderTexture(dtVelocity, velocityVariable.renderTargets[1]);
}
function initProtoplanets() {
geometry = new v3d.BufferGeometry();
const positions = new Float32Array(PARTICLES * 3);
let p = 0;
for (let i = 0; i < PARTICLES; i++) {
positions[p ++] = (Math.random() * 2 - 1) * effectController.radius;
positions[p ++] = 0; //(Math.random() * 2 - 1) * effectController.radius;
positions[p ++] = (Math.random() * 2 - 1) * effectController.radius;
}
const uvs = new Float32Array(PARTICLES * 2);
p = 0;
for (let j = 0; j < WIDTH; j ++) {
for (let i = 0; i < WIDTH; i++) {
uvs[p ++] = i / (WIDTH - 1);
uvs[p ++] = j / (WIDTH - 1);
}
}
geometry.setAttribute('position', new v3d.BufferAttribute(positions, 3));
geometry.setAttribute('uv', new v3d.BufferAttribute(uvs, 2));
particleUniforms = {
"texturePosition": { value: null },
"textureVelocity": { value: null },
"cameraConstant": { value: getCameraConstant(camera) },
"density": { value: 0.0 }
};
// v3d.ShaderMaterial
const material = new v3d.ShaderMaterial({
uniforms: particleUniforms,
vertexShader: document.getElementById('particleVertexShader').textContent,
fragmentShader: document.getElementById('particleFragmentShader').textContent
});
material.extensions.drawBuffers = true;
const particles = new v3d.Points(geometry, material);
particles.matrixAutoUpdate = false;
particles.updateMatrix();
scene.add(particles);
}
function fillTextures(texturePosition, textureVelocity) {
const posArray = texturePosition.image.data;
const velArray = textureVelocity.image.data;
const radius = effectController.radius;
const height = effectController.height;
const exponent = effectController.exponent;
const maxMass = effectController.maxMass * 1024 / PARTICLES;
const maxVel = effectController.velocity;
const velExponent = effectController.velocityExponent;
const randVel = effectController.randVelocity;
for (let k = 0, kl = posArray.length; k < kl; k += 4) {
// Position
let x, z, rr;
do {
x = (Math.random() * 2 - 1);
z = (Math.random() * 2 - 1);
rr = x * x + z * z;
} while (rr > 1);
rr = Math.sqrt(rr);
const rExp = radius * Math.pow(rr, exponent);
// Velocity
const vel = maxVel * Math.pow(rr, velExponent);
const vx = vel * z + (Math.random() * 2 - 1) * randVel;
const vy = (Math.random() * 2 - 1) * randVel * 0.05;
const vz = - vel * x + (Math.random() * 2 - 1) * randVel;
x *= rExp;
z *= rExp;
const y = (Math.random() * 2 - 1) * height;
const mass = Math.random() * maxMass + 1;
// Fill in texture values
posArray[k + 0] = x;
posArray[k + 1] = y;
posArray[k + 2] = z;
posArray[k + 3] = 1;
velArray[k + 0] = vx;
velArray[k + 1] = vy;
velArray[k + 2] = vz;
velArray[k + 3] = mass;
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
particleUniforms["cameraConstant"].value = getCameraConstant(camera);
}
function dynamicValuesChanger() {
velocityUniforms["gravityConstant"].value = effectController.gravityConstant;
velocityUniforms["density"].value = effectController.density;
particleUniforms["density"].value = effectController.density;
}
function initGUI() {
const gui = new GUI({ width: 300 });
const folder1 = gui.addFolder('Dynamic parameters');
folder1.add(effectController, "gravityConstant", 0.0, 1000.0, 0.05).onChange(dynamicValuesChanger);
folder1.add(effectController, "density", 0.0, 10.0, 0.001).onChange(dynamicValuesChanger);
const folder2 = gui.addFolder('Static parameters');
folder2.add(effectController, "radius", 10.0, 1000.0, 1.0);
folder2.add(effectController, "height", 0.0, 50.0, 0.01);
folder2.add(effectController, "exponent", 0.0, 2.0, 0.001);
folder2.add(effectController, "maxMass", 1.0, 50.0, 0.1);
folder2.add(effectController, "velocity", 0.0, 150.0, 0.1);
folder2.add(effectController, "velocityExponent", 0.0, 1.0, 0.01);
folder2.add(effectController, "randVelocity", 0.0, 50.0, 0.1);
const buttonRestart = {
restartSimulation: function() {
restartSimulation();
}
};
folder2.add(buttonRestart, 'restartSimulation');
folder1.open();
folder2.open();
}
function getCameraConstant(camera) {
return window.innerHeight / (Math.tan(v3d.MathUtils.DEG2RAD * 0.5 * camera.fov) / camera.zoom);
}
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
gpuCompute.compute();
particleUniforms["texturePosition"].value = gpuCompute.getCurrentRenderTarget(positionVariable).texture;
particleUniforms["textureVelocity"].value = gpuCompute.getCurrentRenderTarget(velocityVariable).texture;
renderer.render(scene, camera);
}
</script>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
HTML
1
https://gitee.com/ing/verge3d-code-examples.git
git@gitee.com:ing/verge3d-code-examples.git
ing
verge3d-code-examples
verge3d-code-examples
master

搜索帮助