如何为细分的每次迭代制作彩色顶点

问题描述 投票:0回答:1

我有一个具有各种标准几何形状的应用程序(例如,盒子几何形状https://thirdjs.org/docs/#api/en/geometries/BoxGeometry),并且该应用程序在原始模型上应用最多 5 级细分几何学。我正在努力弄清楚如何对顶点进行颜色编码以可视化迭代/细分级别之间的差异。一般来说,我希望原始几何体的原始顶点(迭代0,不应用细分)为一种颜色(例如紫色),然后在下一次迭代(迭代1,细分1级)中,我想保留紫色顶点和从细分创建的新顶点应该是另一种颜色(例如红色)。有办法做到这一点吗?

更新:我想出了如何在每个顶点上获取彩色点,但是仍然存在一些问题。例如,盒子几何点都是完美的,但是所有其他形状(例如圆柱体)的原始(“正常几何”)似乎有额外的顶点,我无法弄清楚为什么要放置它们或如何摆脱它们它的。 我也仍然不知道如何区分不同的细分级别。非常感谢任何帮助。

代码:

import * as THREE from 'three';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import LoopSubdivision from './LoopSubdivision.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';

let renderer, scene, camera;
let standardMat;
let meshNormal, meshSmooth;
let wireNormal, wireSmooth;
let wireMaterial;
let coloredPoints;



// Create a gray color
var grayColor = new THREE.Color(0.5, 0.5, 0.5); // base color

var color0 = new THREE.Color(1, 0, 0); // Red
var color1 = new THREE.Color(0, 1, 0); // Green
var color2 = new THREE.Color(0, 0, 1); // Blue
var color3 = new THREE.Color(1, 1, 0); // Yellow
var color4 = new THREE.Color(1, 0, 1); // Pink
var color5 = new THREE.Color(0, 1, 1); // Cyan

var colors = [
    color0.toArray(),
    color1.toArray(),
    color2.toArray(),
    color3.toArray(),
    color4.toArray(),
    color5.toArray()
];

// Define colors for each iteration
var colorsByIteration = [
    [color0.toArray()],
    [color0.toArray(), color1.toArray()],
    [color0.toArray(), color1.toArray(), color2.toArray()],
    [color0.toArray(), color1.toArray(), color2.toArray(), color3.toArray()],
    [color0.toArray(), color1.toArray(), color2.toArray(), color3.toArray(), color4.toArray()],
    [color0.toArray(), color1.toArray(), color2.toArray(), color3.toArray(), color4.toArray(), color5.toArray()]
];

const params = {
    geometry: 'Box',
    iterations: 3,
    split: true,
    wireframe: true
};

init();

function init() {
    const version = parseInt(THREE.REVISION.replace(/\D/g, ''));

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    if (version && version > 151) renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
    document.body.appendChild(renderer.domElement);

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight);
    camera.position.set(0, 0.7, 2.1);

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.addEventListener('change', render);
    controls.rotateSpeed = 0.5;
    controls.minZoom = 1;
    controls.target.set(0, 0, 0);
    controls.update();

    const light = new THREE.PointLight(0xff0000, 1, 100);
    light.position.set(2.5, 7.5, 15);
    scene.add(light);

    // standardMat = new THREE.MeshBasicMaterial(); // rainbow color
    // standardMat.vertexColors = THREE.VertexColors;
    standardMat = new THREE.MeshBasicMaterial({ color: grayColor });

    meshNormal = new THREE.Mesh(new THREE.BufferGeometry(), standardMat);
    meshSmooth = new THREE.Mesh(new THREE.BufferGeometry(), standardMat);
    meshNormal.position.set(-0.7, 0, 0);
    meshSmooth.position.set(0.7, 0, 0);
    scene.add(meshNormal, meshSmooth);

    wireMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, depthTest: true, wireframe: true });
    wireNormal = new THREE.Mesh(new THREE.BufferGeometry(), wireMaterial);
    wireSmooth = new THREE.Mesh(new THREE.BufferGeometry(), wireMaterial);
    wireNormal.visible = false;
    wireSmooth.visible = false;
    wireNormal.position.copy(meshNormal.position);
    wireSmooth.position.copy(meshSmooth.position);
    scene.add(wireNormal, wireSmooth);

    updateMeshes();

    window.addEventListener('resize', onWindowResize);

    const geomTypes = ['Box', 'Capsule', 'Circle', 'Cylinder', 'Dodecahedron', 'Icosahedron', 'Octahedron', 'Plane', 'Ring', 'Sphere', 'Tetrahedron', 'Torus'];//, 'Upload'];

    const gui = new GUI();

    const folder1 = gui.addFolder('Subdivide Params');
    const geomController = folder1.add(params, 'geometry', geomTypes).onFinishChange(() => {
        const geom = params.geometry.toLowerCase();
        params.split = geom === 'box' || geom === 'ring' || geom === 'plane';
        refreshDisplay();
    });

    folder1.add(params, 'iterations').min(0).max(5).step(1).onFinishChange(updateMeshes);
    const splitController = folder1.add(params, 'split').onFinishChange(updateMeshes);

    const folder2 = gui.addFolder('Material');
    folder2.add(params, 'wireframe').onFinishChange(updateWireframe);

    function refreshDisplay() {
        geomController.updateDisplay();
        splitController.updateDisplay();
        updateMeshes();
    }
}


function getGeometry() {

    switch ( params.geometry.toLowerCase() ) {

        case 'box':
            return new THREE.BoxGeometry();

        case 'capsule':
            return new THREE.CapsuleGeometry( 0.5, 0.5, 3, 5 );

        case 'circle':
            return new THREE.CircleGeometry( 0.6, 10 );

        case 'cylinder':
            return new THREE.CylinderGeometry( 0.5, 0.5, 1, 5, 4 );

        case 'dodecahedron':
            return new THREE.DodecahedronGeometry( 0.6 );

        case 'icosahedron':
            return new THREE.IcosahedronGeometry( 0.6 );

        case 'octahedron':
            return new THREE.OctahedronGeometry( 0.7 );

        case 'plane':
            return new THREE.PlaneGeometry();

        case 'ring':
            return new THREE.RingGeometry( 0.3, 0.6, 10 );

        case 'sphere':
            return new THREE.SphereGeometry( 0.6, 8, 4 );

        case 'tetrahedron':
            return new THREE.TetrahedronGeometry( 0.8 );

        case 'torus':
            return new THREE.TorusGeometry( 0.48, 0.24, 4, 6 );

        // case 'Upload':
        //     // when user wants to upload their own obj file
    }

}





function createColoredPoints(geometry, color, offset) {
    const positions = geometry.attributes.position;

    if (!positions) {
        console.error('Invalid geometry for colored points.');
        return null;
    }

    const pointsGeometry = new THREE.BufferGeometry();
    pointsGeometry.setAttribute('position', positions);

    const pointsMaterial = new THREE.PointsMaterial({ color: color, size: 0.05 }); // Adjust the size as needed
    const points = new THREE.Points(pointsGeometry, pointsMaterial);

    // Center the points on the geometry and apply the offset
    const boundingBox = new THREE.Box3().setFromBufferAttribute(positions);
    const center = new THREE.Vector3();
    boundingBox.getCenter(center);
    const adjustedOffset = offset.clone().add(center); // Adjusted offset based on the bounding box center
    points.position.copy(adjustedOffset);

    return points;
}


function updateMeshes() {
    const normalGeometry = getGeometry();
    const smoothGeometry = LoopSubdivision.modify(normalGeometry, params.iterations, params);

    meshNormal.geometry.dispose();
    meshSmooth.geometry.dispose();
    meshNormal.geometry = normalGeometry;
    meshSmooth.geometry = smoothGeometry;

    wireNormal.geometry.dispose();
    wireSmooth.geometry.dispose();
    wireNormal.geometry = normalGeometry.clone();
    wireSmooth.geometry = smoothGeometry.clone();

    // Create colored points for the normal and smooth geometries and add to the scene
    if (coloredPoints) {
        scene.remove(coloredPoints);
    }

    const coloredPointsNormal = createColoredPoints(normalGeometry, color0, new THREE.Vector3(-0.7, 0, 0));
    const coloredPointsSmooth = createColoredPoints(smoothGeometry, color0, new THREE.Vector3(0.7, 0, 0));

    // Check if coloredPoints are defined before adding them to the scene
    if (coloredPointsNormal) {
        scene.add(coloredPointsNormal);
    }

    if (coloredPointsSmooth) {
        scene.add(coloredPointsSmooth);
    }

    // Ensure wireframe visibility is updated
    updateWireframe();

    // Update the material if needed
    updateMaterial();

    // Render the scene
    render();
}




function disposeMaterial(material) {
    const materials = Array.isArray(material) ? material : [material];
    for (let i = 0; i < materials.length; i++) {
        if (materials[i].dispose) materials[i].dispose();
    }
}



function updateMaterial() {
    disposeMaterial(meshNormal.material);
    disposeMaterial(meshSmooth.material);

    meshNormal.material = meshSmooth.material = standardMat;

    render();
}



function updateWireframe() {
    wireNormal.visible = wireSmooth.visible = params.wireframe;
    render();
}

function onWindowResize() {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    render();
}

function render() {
    renderer.render(scene, camera);
}


javascript three.js 3d geometry vertices
1个回答
0
投票

我不确定你想要实现什么行为。

所以,这是一个疯狂的镜头:

body{
  overflow: hidden;
  margin: 0;
}
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/[email protected]/build/three.module.js",
      "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
    }
  }
</script>
<script type="module">
import * as THREE from "three";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

let colors = ["#f00", "#0f0", "#00f", "#ff0", "#0ff", "#f0f"].map(c => new THREE.Color(c));
console.log(colors);

for(let i = 0; i < colors.length; i++){
  
  let mesh = new THREE.Mesh(
    new THREE.IcosahedronGeometry(1, i),
    new THREE.MeshBasicMaterial({color: "gray", wireframe: true})
  );
  setPointsColor(mesh, i);
  
  mesh.position.x = (-(colors.length - 1) * 0.5 + i) * 3;
  
  scene.add(mesh);

}

renderer.setAnimationLoop(() => {
  controls.update();
  renderer.render(scene, camera);
})

function setPointsColor(mesh, colorIndex){
  let g = mesh.geometry;
  let p = new THREE.Points(g, new THREE.PointsMaterial({size: 0.2, color: colors[colorIndex]}));
  mesh.add(p);
}
</script>

© www.soinside.com 2019 - 2024. All rights reserved.