简体   繁体   English

使用Three.js在3D对象上绘制轮廓

[英]drawing an outline on a 3D object with Three.js

I have several objects in the scene leaving the outcome of the .mesh of Three.js ... I separate ways but not how. 我在场景中有几个对象,离开Three.js .mesh的结果...我分开了几种方法,但没有分开。

I want to put a boundary to clearly see the shapes. 我想划界清楚地看到形状。 http://www.subirimagenes.com/imagen-captura-9427322.html http://www.subirimagenes.com/imagen-captura-9427322.html

extrude_geometria[i]=new    THREE.ExtrudeGeometry(forma_figura[i],datos_extrusion);
materialFront[i] = new THREE.MeshBasicMaterial( { color: "#FF0000"} );

municipios[i] = new THREE.Mesh( extrude_geometria[i], materialFront[i] );

Composer and Outline pass are needed. 需要Composer和Outline Pass。 See my example below which is a simplification of the official example at https://threejs.org/examples/?q=out#webgl_postprocessing_outline 请参阅下面的示例,它是https://threejs.org/examples/?q=out#webgl_postprocessing_outline上官方示例的简化版

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js webgl - post processing - Outline Pass</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
<script src="three.js"></script>

<script src="CopyShader.js"></script>
<script src="FXAAShader.js"></script>
<script src="EffectComposer.js"></script>
<script src="RenderPass.js"></script>
<script src="ShaderPass.js"></script>
<script src="OutlinePass.js"></script>


<div id="info">
    <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Outline Pass by <a href="http://eduperiment.com" target="_blank" rel="noopener">Prashant Sharma</a> and <a href="https://clara.io" target="_blank" rel="noopener">Ben Houston</a><br/><br/>
</div>

<script>

    var container, camera, scene, renderer, composer, effectFXAA, outlinePass;

    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();

    init();
    animate();

    function init() {
        container = document.createElement('div');
        document.body.appendChild(container);

        var width = window.innerWidth || 1;
        var height = window.innerHeight || 1;

        renderer = new THREE.WebGLRenderer({antialias: false});
        renderer.setSize(width, height);
        document.body.appendChild(renderer.domElement);

        camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100);
        camera.position.z = 8;
        camera.position.x = 0;

        scene = new THREE.Scene();


        var light = new THREE.DirectionalLight(0xddffdd, 0.4);
        light.position.z = 1;
        light.position.y = 1;
        light.position.x = 1;
        scene.add(light);

        var floorMaterial = new THREE.MeshLambertMaterial();
        floorMaterial.side = THREE.DoubleSide;
        var floorGeometry = new THREE.PlaneBufferGeometry(12, 12);
        var floorMesh = new THREE.Mesh(floorGeometry, floorMaterial);
        floorMesh.rotation.x -= Math.PI * 0.5;
        floorMesh.position.y -= 1.5;
        scene.add(floorMesh);




        // postprocessing
        composer = new THREE.EffectComposer(renderer);

        var renderPass = new THREE.RenderPass(scene, camera);
        composer.addPass(renderPass);

        outlinePass = new THREE.OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera);
        composer.addPass(outlinePass);

        effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
        effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
        effectFXAA.renderToScreen = true;
        composer.addPass(effectFXAA);

        window.addEventListener('mousemove', onTouchMove);
        window.addEventListener('touchmove', onTouchMove);

        function onTouchMove(event) {
            mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
            mouse.y = -( event.clientY / window.innerHeight ) * 2 + 1;

            raycaster.setFromCamera(mouse, camera);

            var intersects = raycaster.intersectObjects([scene], true);

            if (intersects.length > 0) {
                var selectedObject = intersects[0].object;
                outlinePass.selectedObjects = [selectedObject];
            }
        }
    }

    function animate() {
        requestAnimationFrame( animate );
        composer.render();
    }

</script>
</body>
</html>

查看THREE.js中内置的WireframeHelper和edgeHelper实用程序-它们可以添加您所描述的内容。

There is the THREE.BoundingBoxHelper() that can help you. THREE.BoundingBoxHelper()可以为您提供帮助。 It shows the bounding box for an object. 它显示了对象的边界框。 An example is: 一个例子是:

# hexadecimal value to define color
var hex  = 0xff0000;
var bbox = new THREE.BoundingBoxHelper( your_mesh, hex );
bbox.update();
scene.add( bbox );

Where your_mesh is the object3D to show the boundingbox. 其中your_mesh是用于显示边界框的object3D。

A roughly way to render only the outline of a mesh is render your mesh twice with a flat color using frontface culling and a specific shader that offset each vertex along its normal. 仅渲染网格轮廓的一种粗略方法是使用正面剔除和特定的着色器(使用沿每个顶点的法线偏移每个顶点的特定着色器)将网格两次渲染为纯色。 An example would be: 一个例子是:

var vertexShader = 
"void main(){"+
    "float offset = 2.0;"+
    "vec4 pos = modelViewMatrix * vec4( position + normal * offset, 1.0 );"+
    "gl_Position = projectionMatrix * pos;"+
"}\n";

var fragmentShader =
"void main(){"+
    "gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );"+
"}\n";

You could use EdgesGeometry, worked great in my case. 您可以使用EdgesGeometry,在我的案例中效果很好。 Insert this after you added the mesh: 在添加网格之后插入:

const geometry = new THREE.PlaneBufferGeometry(200, 200) // whatever geometry you use
const line = new THREE.LineSegments(new THREE.EdgesGeometry(geometry), new THREE.LineBasicMaterial({color: 0x00000}))
scene.add(line)

https://threejs.org/docs/#api/en/geometries/EdgesGeometry https://threejs.org/docs/#api/en/geometries/EdgesGeometry

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM