gpt4 book ai didi

javascript - 如何将此 Three.js ConvexGeometry 更改为非凸几何形状?

转载 作者:行者123 更新时间:2023-11-28 04:18:27 26 4
gpt4 key购买 nike

我以前使用过 Three.JS,但不是在网格上。我认为我正在以正确的方式解决我的问题,但我不确定。

目标

我正在尝试制作一个具有特定顶点的 3D Blob 对象。顶点的方向是固定的,但它们距中心的半径不同。您可以将其想象为有点像音频均衡器,除了径向均衡器和 3D 均衡器之外。

如果有更简单的方法,我愿意放弃这种方法并采取完全不同的方法。

当前进度

我拿了this example并根据我的需要对其进行清理/修改。这是 HTML 和 JavaScript:

HTML (disco-ball.html)

<!DOCTYPE html>
<html>
<head>
<title>Disco Ball</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/ConvexGeometry.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style type='text/css'>
/* set margin to 0 and overflow to hidden, to go fullscreen */
body { margin: 0; overflow: hidden; }
</style>
</head>
<body>

<div id="Stats-output"></div>
<div id="WebGL-output"></div>
<script type="text/javascript" src="01-app.js"></script>
</body>
</html>

和 JavaScript (01-app.js):

window.onload = init;

const PARAMS = {
SHOW_SURFACE : true,
SHOW_POINTS : true,
SHOW_WIREFRAME : true,

SHOW_STATS : true
};

// once everything is loaded, we run our Three.js stuff.
function init() {
var renderParams = {
webGLRenderer : createWebGLRenderer(),
step : 0,
rotationSpeed : 0.007,
scene : new THREE.Scene(),
camera : createCamera(),
};

// Create the actual points.
var points = getPoints(
100, // Number of points (approximate)
10, // Unweighted radius
// Radius weights for a few points. This is a multiplier.
[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2]
);

if (PARAMS.SHOW_STATS) {
renderParams.stats = initStats();
}

if (PARAMS.SHOW_SURFACE) {
renderParams.surface = getHullMesh(points);
renderParams.scene.add(renderParams.surface);
}

if (PARAMS.SHOW_POINTS) {
renderParams.sphereGroup = getSphereGroup(points);
renderParams.scene.add(sphereGroup);
}

render(renderParams);
}

function render(params) {
if (params.stats) {
params.stats.update();
}

if (params.sphereGroup) {
params.sphereGroup.rotation.y = params.step;
}

params.step += params.rotationSpeed;

if (params.surface) {
params.surface.rotation.y = params.step;
}


// render using requestAnimationFrame
requestAnimationFrame(function () {render(params)});
params.webGLRenderer.render(params.scene, params.camera);
}


// ******************************************************************
// Helper functions
// ******************************************************************

function getPoints (count, baseRadius, weightMap) {
// Because this is deterministic, we can pass in a weight map to adjust
// the radii.
var points = distributePoints(count,baseRadius,weightMap);

points.forEach((d,i) => {
points[i] = new THREE.Vector3(d[0],d[1],d[2]);
});

return points;
}


// A deterministic function for (approximately) evenly distributing n points
// over a sphere.
function distributePoints (count, radius, weightMap) {
// I'm not sure why I need this...
count *= 100;

var points = [];

var area = 4 * Math.PI * Math.pow(radius,2) / count;
var dist = Math.sqrt(area);

var Mtheta = Math.round(Math.PI / dist);
var distTheta = Math.PI / Mtheta
var distPhi = area / distTheta;

for (var m = 0; m < Mtheta; m++) {
let theta = (Math.PI * (m + 0.5)) / Mtheta;
let Mphi = Math.round((2 * Math.PI * Math.sin(theta)) / distPhi);
for (var n = 0; n < Mphi; n++) {
let phi = ((2 * Math.PI * n) / Mphi);
// Use the default radius, times any multiplier passed in through the
// weightMap. If no multiplier is present, use 1 to leave it
// unchanged.
points.push(createPoint(radius * (weightMap[points.length] || 1),theta,phi));
}
}

return points;
}

function createPoint (radius, theta, phi) {
var x = radius * Math.sin(theta) * Math.cos(phi);
var y = radius * Math.sin(theta) * Math.sin(phi);
var z = radius * Math.cos(theta);

return [Math.round(x), Math.round(y), Math.round(z)];
}

function createWebGLRenderer () {
// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
return webGLRenderer;
}

function createCamera () {
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 50;

camera.lookAt(new THREE.Vector3(0, 0, 0));
return camera;
}

function getSphereGroup (points) {
sphereGroup = new THREE.Object3D();
var material = new THREE.MeshBasicMaterial({color: 0xFF0000, transparent: false});

points.forEach(function (point) {
var spGeom = new THREE.SphereGeometry(0.2);
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.copy(point);
sphereGroup.add(spMesh);
});

return sphereGroup;
}

function getHullMesh (points) {
// use the same points to create a convexgeometry
var surfaceGeometry = new THREE.ConvexGeometry(points);
var surface = createMesh(surfaceGeometry);
return surface;
}

function createMesh(geom) {
// assign two materials
var meshMaterial = new THREE.MeshBasicMaterial({color: 0x666666, transparent: true, opacity: 0.25});
meshMaterial.side = THREE.DoubleSide;

var wireFrameMat = new THREE.MeshBasicMaterial({color: 0x0000ff});
wireFrameMat.wireframe = PARAMS.SHOW_WIREFRAME;

// create a multimaterial
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);

return mesh;
}

function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms

// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';

document.getElementById("Stats-output").appendChild(stats.domElement);

return stats;
}

我缺少什么

  1. 您可以看到“球”上有两个点,我将其半径加倍(大尖峰)。当然,由于我使用的是 ConvexGeometry,形状是凸的......因此许多点被隐藏。我可以使用什么样的...非凸几何体来使这些点不再被隐藏?
  2. 我想稍微分割一下网格,这样它就不仅仅是顶点到顶点,而是更平滑一些。我怎样才能做到这一点(尖刺更少尖刺,更多 Blob )?
  3. 我想修改网格,以便不同的点每隔几秒就会出现不同的峰值(我有一些数据数组来描述多少)。几何图形制作完成后如何修改?理想情况下使用某种补间,但我可以不使用它,这非常困难 =)

谢谢!

最佳答案

平滑网格并为其设置动画。

三提供了广泛的选择。这些只是建议,您最好的选择是阅读 Three documentation start point并找到适合您的内容。

网格只是一组 3D 点和描述每个三 Angular 形的索引数组。一旦你构建了网格,你只需要更新顶点并让三更新着色器属性和网格法线

您的问题

第一季度。使用Three.Geometry对于网格。

Q2。当您构建网格时,您可以使用曲线助手,例如 Three.CubicBezierCurve3Three.QuadraticBezierCurve3或者也许是您最好的选择Three.SplineCurve

另一个选择是使用修改器并创建简单的网格,然后让 Three 为您分割网格。例如 three example webgl modifier subdivision

虽然不是最快的解决方案,但如果顶点数较低,它会在每帧执行此操作,而不会损失任何帧速率。

第三季度。使用 Three.Geometry您可以设置网格morph targets ,顶点数组。

另一种选择是使用修饰符,例如 three example webgl modifier subdivision

或者您可以直接修改每一帧的顶点。

for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) {
geometry.vertices[ i ].x = ?;
geometry.vertices[ i ].y = ?;
geometry.vertices[ i ].z = ?;
}
mesh.geometry.verticesNeedUpdate = true;

你是如何做到的?

还有无数其他方法可以做到这一点。哪个是最好的取决于您想要创建的负载和复杂程度。花一些时间阅读文档并进行实验。

我会做什么!也许?

我不太确定您想要实现什么目标,但以下是一种让动画充满活力的方法,而不是当今似乎无处不在的过度曲线。

因此,如果顶点数不太高,我会使用 Three.BufferGeometry并修改每一帧的顶点。我不会使用曲线,而是对分割顶点进行加权以遵循多项式曲线 f(x) = x^2/(x^2 + (1-x)^2)其中 x 是两个控制顶点之间的标准化距离(注意不要使用 x=0.5,而是将网格分割 > 2 倍)

EG 两个控制点和两个平滑顶点

   // two control points
const p1 = {x,y,z};
const p2 = {x,y,z};

// two weighted points
// dx,dy,dz are deltas
// w is the weighted position s-curve
// wa, and wd are acceleration and drag coefficients. Try to keep their sum < 1

const pw1 = {x, y, z, dx, dy, dz, w : 1/3, wa : 0.1,wd : 0.7};
const pw2 = {x, y, z, dx, dy, dz, w : 2/3, wa : 0.1,wd : 0.7};
// Compute w
pw1.w = Math.pow(pw1.w,2) / ( Math.pow(pw1.w,2) + Math.pow(1 - pw1.w,2));
pw2.w = Math.pow(pw2.w,2) / ( Math.pow(pw2.w,2) + Math.pow(1 - pw2.w,2));

然后对于每个加权点,您可以找到新的增量并更新位置

   // do for x,y,z
x = (p2.x - p1.x); // these points are updated every frame

// get the new pw1 vert target position
x = p1.x + x * w;

// get new delta
pw1.dx += (x - pw1.x) * pw1.wa; // set delta
pw1.dx *= pw1.wd;

// set new position
pw1.x += pw1.dx;

对所有加权点进行操作,然后设置 geometry.vertices

wa , wd系数将改变平滑的行为,您必须使用这些值来适应您自己的口味。必须是0 <= (wa,wd) < 1总和应该是 wa + wd < 1 。求和值过高会导致振荡,过高则振荡失控。

关于javascript - 如何将此 Three.js ConvexGeometry 更改为非凸几何形状?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45647849/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com