three.js - 如何在 Three.js 中将 3D 对象投影到 2D 平面上?

标签 three.js

我有一组大约二十条线,形成一个形状(“小鸟”)。我目前正在“镜子”顶部绕 y 轴(“上”轴)旋转它。这是屏幕截图:

[complex shape rotating on yellow mirror ] 我想要做的是将旋转形状投影到“镜子”(黄色平面)的 xy 平面上,只需忽略 z 分量,这样您就只会看到形状从其角度看时的二维投影侧面。

目前,我的攻击计划如下:

  1. 保持原始形状为 3 维形式,以便正确旋转。我认为如果此时将其减少到二维,旋转将不正确。
  2. 绕 y 轴旋转 3D 原型(prototype),但还不显示它。这是我当前使用的代码:

var m = new THREE.Matrix4();
var mat = m.makeRotationY(base.ONE_DEGREE * 0.2);
birdyGroupClone.applyMatrix(mat);
  • 通过子数组遍历组中的各个线,然后转到 Geometry.vertices 并将 z 分量设置为零。
  • 最后,将这些二维线(作为一组)渲染到 xy 平面上。
  • 我陷入了第 3 点,因为当我将组中的行乘以矩阵时,我无法在层次结构中的任何位置找到中间旋转结果。顶点本身不受影响——它们仍然包含规范的“根”值。

    以下是从 Chrome 浏览器调试 session 中获取的组的对象层次结构的相关部分:

    birdyGroupClone: THREE.Object3D
        __webglActive: true
        __webglInit: true
        _listeners: Object
        _modelViewMatrix: THREE.Matrix4
        _normalMatrix: THREE.Matrix3
        castShadow: false
        children: Array[30]
            0: THREE.Line
            1: THREE.Line
            2: THREE.Line
            3: THREE.Line
            4: THREE.Line
            __webglActive: true
            __webglInit: true
            _listeners: Object
            _modelViewMatrix: THREE.Matrix4
            _normalMatrix: THREE.Matrix3
            castShadow: false
            children: Array[0]
            eulerOrder: (...)
            frustumCulled: true
            geometry: THREE.Geometry
                __colorArray: Float32Array[6]
                __lineDistanceArray: Float32Array[2]
                __vertexArray: Float32Array[6]
                __webglColorBuffer: WebGLBuffer
                __webglInit: true
                __webglLineCount: 2
                __webglLineDistanceBuffer: WebGLBuffer
                __webglVertexBuffer: WebGLBuffer
                _listeners: Object
                boundingBox: null
                boundingSphere: THREE.Sphere
                colors: Array[0]
                colorsNeedUpdate: false
                dynamic: true
                elementsNeedUpdate: false
                faceVertexUvs: Array[1]
                faces: Array[0]
                groupsNeedUpdate: false
                hasTangents: false
                id: 160
                lineDistances: Array[0]
                lineDistancesNeedUpdate: false
                morphColors: Array[0]
                morphNormals: Array[0]
                morphTargets: Array[0]
                name: ""
                normalsNeedUpdate: false
                skinIndices: Array[0]
                skinWeights: Array[0]
                tangentsNeedUpdate: false
                type: "Geometry"
                uuid: "55EE9F6D-0DD1-4581-817A-9E324EC5225D"
                uvsNeedUpdate: false
                vertices: Array[2]
                    0: THREE.Vector3  <-- These are unaffected by the rotation
                        x: -0.616     <--  Where are the transformed coordinates?
                        y: 0
                        z: -0.68
                        __proto__: THREE.Vector3
                    1: THREE.Vector3
                        x: -0.5
                        y: 0
                        z: -1
                        __proto__: THREE.Vector3
                    length: 2
    

    这是旋转之后的结果。中间的变换后顶点在哪里,我可以将其用于我的变换“管道”(以进行二维投影)。它们仅反射(reflect)在浏览器 Canvas 中吗?

    所以我的问题是:

    1. 我的攻击计划听起来正确吗?或者有更好的方法吗?
    2. 如果是,我如何访问中间转换的结果,以便应用处理“管道”?

    非常感谢。

    最佳答案

    根据 WestLangley 的输入,我找到了解决方案。现在我已经完成了,我意识到描述我的问题的更好方法是说我想将 3-d 对象的阴影投影到平面上。

    我基本上必须单独对每个线条几何图形进行变换,而不是对组进行变换。通过这种方式,线的顶点被更新,然后我可以按照前面所述继续执行计划的其余部分。

    这是我的代码:

    var m = new THREE.Matrix4();
    var mat = m.makeRotationY(base.ONE_DEGREE * 0.2);
    
    // loop over each line and transform individually
    // I had to do in a try catch block, but you shouldn't have to
    try {
        for (var i = 0; i < birdyGroupClone.children.length; i++) {
            birdyGroupClone.children[i].geometry.applyMatrix(mat);
        }
    }
    catch (e) {
        console.log('caught error=' + e);
        return false;
    }
    
    // Create a new Shadow group on each render
    // make sure to remove the old one, otherwise your frame rate will bog down
    // I had trouble with simply cloning birdyGroupClone because it doesn't
    // deep copy all the way down (?), so I create anew each time.
    factory.xyProjectionMesh.remove(birdyGroupShadow);
    birdyGroupShadow = new THREE.Object3D();
    
    //remove z-component from birdyGroupClone vertices
    for (var i = 0; i < birdyGroupClone.children.length; i++) {
        var line, lineGeometry, vertex;
    
        lineGeometry = new THREE.Geometry();
    
        vertex = birdyGroupClone.children[i].geometry.vertices[0];
        lineGeometry.vertices.push(new THREE.Vector3(vertex.x, vertex.y, 0));
        vertex = birdyGroupClone.children[i].geometry.vertices[1];
        lineGeometry.vertices.push(new THREE.Vector3(vertex.x, vertex.y, 0));
    
        line = new THREE.Line(lineGeometry, birdyGroupClone.children[i].material);
    
        birdyGroupShadow.add(line);
    };
    
    birdyGroupShadow.position.set(0, 0, 0);
    this.xyProjectionMesh.add(birdyGroupShadow);
    

    也许这不是最漂亮的方法,但它确实有效。

    这是显示结果的屏幕截图。注意,它是如何完全存在于平面上并且没有“深度”的:

    enter image description here

    关于three.js - 如何在 Three.js 中将 3D 对象投影到 2D 平面上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32153295/

    相关文章:

    node.js - 将 WebGLRenderer() 与 jsdom 一起使用时出错

    mobile - 移动设备上是否支持 Canvas 和 WebGL(three.js)?

    javascript - 缩放后居中 Canvas 上下文

    javascript - 具有形态属性的动画缓冲区几何不更新阴影

    javascript - 三个js键盘旋转

    javascript - 基于对象边界框的相机控制?

    javascript - 如何保存然后加载 Three.js 场景

    javascript - 为什么我无法在 Three.js 中缩放或设置网格的位置?

    node.js - 将 HTML Canvas/WebGL 动画服务器端录制到视频中的最佳方法?

    javascript - Three.js 将map分配给object.children[0]会改变整个对象的map