显示线框和实色

37

在同一个对象上同时显示其线框和面的实体颜色是否可能?我找到了一种方法,使用对象的克隆并分配不同的材质。

var geometry = new THREE.PlaneGeometry(plane.width, plane.height,width - 1, height - 1);
var materialWireframe = new THREE.MeshPhongMaterial({color:"red",wireframe:true});
var materialSolid = new THREE.MeshPhongMaterial({color:"green",wireframe:false});
var plane = new THREE.Mesh(geometry, materialWireframe );
var plane1 = plane.clone();
plane1.material = materialSolid ;
plane1.material.needsUpdate = true;

有什么想法吗?


也许需要一个自定义着色器? - Shomz
你能进一步解释吗?有什么方法可以使用着色器材料来实现这个目的吗? - prieston
您可以定义自己的着色器,可以尝试使用此链接:https://aerotwist.com/tutorials/an-introduction-to-shaders-part-1/ 如果不行,您也可以始终使用带有实心背景的线框纹理。 - Shomz
请查看:http://threejs.org/examples/#webgl_materials_wireframe - meirm
4个回答

81

要同时呈现模型和其线框图,您可以使用以下类似的模式:

// mesh
var material = new THREE.MeshPhongMaterial( {
    color: 0xff0000,
    polygonOffset: true,
    polygonOffsetFactor: 1, // positive value pushes polygon further away
    polygonOffsetUnits: 1
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh )

// wireframe
var geo = new THREE.EdgesGeometry( mesh.geometry ); // or WireframeGeometry
var mat = new THREE.LineBasicMaterial( { color: 0xffffff } );
var wireframe = new THREE.LineSegments( geo, mat );
mesh.add( wireframe );

使用polygonOffset将有助于防止网格材质和线框线之间的z-fighting。因此,线框看起来会好很多。

three.js r.126


linewidth不会改变EdgesHelper或WireframeHelper中线条的宽度。 - Marcs
1
如果你使用的是Windows系统,那很可能是ANGLE的限制。 - WestLangley
2
如果网格几何形状发生改变,这个解决方案就不起作用了。 - ArmenB
1
这需要额外的GPU调用来添加线框。如果材质着色器可以在一个材质中全部支持它,那会很好。 - trusktr
@den232那不是Object3D类的一个方法,它只属于Box3 - Zach Saucier
显示剩余2条评论

8
这也可以使用WireframeGeometry实现: https://threejs.org/docs/#api/en/geometries/WireframeGeometry。 (并将平面和线条定位在相同位置,您还可以按照文档中的说明调整透明度)。
let geometryWithFillAndWireFrame = () => {

    let geometry = new THREE.PlaneGeometry(250, 250, 10, 10);
    let material = new THREE.MeshBasicMaterial( { color: 0xd3d3d3} );
    let plane = new THREE.Mesh(geometry, material);

    scene.add(plane);

    let wireframe = new THREE.WireframeGeometry( geometry );

    let line = new THREE.LineSegments( wireframe );
        
    line.material.color.setHex(0x000000);
        
    scene.add(line);
        
};

3
为了实现这一点,有一个可能性是使用GLSL片元着色器,在三角形的边缘附近改变片元颜色。以下是我正在使用的GLSL着色器。作为输入,它采用三角形中片段的重心坐标和一个边缘掩码,选择是否应该绘制每个边。(注:出于向后兼容性原因,我必须使用兼容性配置文件来使用它,如果您不想那样做,可以轻松地进行适应)。
#version 150 compatibility

flat in float diffuse;
flat in float specular;
flat in vec3  edge_mask;
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color;

float edge_factor(){
    vec3 bary3 = vec3(bary.x, bary.y, 1.0-bary.x-bary.y);
    vec3 d = fwidth(bary3);
    vec3 a3 = smoothstep(vec3(0.0,0.0,0.0), d*mesh_width, bary3);
    a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask*a3;
    return min(min(a3.x, a3.y), a3.z);
}

void main() {
    float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
    vec4  Kdiff = gl_FrontFacing ?
         gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
    float sdiffuse = s * diffuse;
    vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
    if(sdiffuse > 0.0) {
       result += sdiffuse*Kdiff +
                 specular*gl_FrontMaterial.specular;
    }
    frag_color = (mesh_width != 0.0) ?
                  mix(vec4(mesh_color,1.0),result,edge_factor()) :
                  result;
}

1
使用较新的TS版本,您可以使用this.fragmentSrc = 语法,它允许多行字符串。 - Sentinel
有没有使用这个的在线示例? - shinzou
这里有一个在线示例:http://homepages.loria.fr/BLevy/GEOGRAM/geobox.html - BrunoLevy
我正在尝试使用Autodesk的查看器来实现这个,但它不起作用,我在这里询问了一下:https://stackoverflow.com/questions/45917611/shader-wireframe-of-an-object 有什么想法为什么会这样? - shinzou

2
为了避免对象的克隆,我使用了以下设计模式:
var mat_wireframe = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
var mat_lambert = new THREE.MeshLambertMaterial({color: 0xffffff, shading: THREE.FlatShading});
var meshmaterials = [ mat_wireframe, mat_lambert ];

然后像这样将其应用到我的网格中:
var myMesh = THREE.SceneUtils.createMultiMaterialObject( mesh_geometry, meshmaterials );
scene.add( myMesh ) ; 

I hope it could help...


5
createMultiMaterialObject() 方法会为每个材质实例化一个独立的 Mesh,因此不会“避免克隆”。 - WestLangley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接