首页 > 其他分享 >ThreeJS实现屏幕坐标转3d坐标

ThreeJS实现屏幕坐标转3d坐标

时间:2023-11-26 15:47:48浏览次数:34  
标签:ThreeJS pos camera 坐标 屏幕 3d 3D

title: ThreeJS实现屏幕坐标转3d坐标
banner_img: https://drive.studyinglover.com/api/raw/?path=/photos/blog/background/e4127f10a90d5f6fd4f77b0225a19878.jpg
date: 2023-2-4 20:30:00
categories:
- 工具
tags:
- ThreeJS

ThreeJS实现屏幕坐标转3d坐标

本文使用chatGPT辅助完成

在虚拟世界中,3D坐标与屏幕坐标之间的转换是一个重要的问题。使用ThreeJS开发3D场景时,经常需要将屏幕坐标转换为3D坐标。在本文中,我们将介绍如何使用ThreeJS实现屏幕坐标转3D坐标的两种方法

根据相机的投影矩阵和射线拾取

在我的笔记摄像机模型中详细推导了相机的投影矩阵。

在ThreeJS中,相机的投影矩阵是一个4x4的矩阵,它将3D坐标转换为屏幕坐标。我们可以使用这个矩阵将屏幕坐标转换为3D坐标。
官方为我们提供了一个接口vector.unproject(camera),它可以将屏幕坐标转换为3D坐标。但是这个接口只能将屏幕坐标转换为相机坐标系下的3D坐标,如果我们需要将屏幕坐标转换为世界坐标系下的3D坐标,我们需要使用vector.applyMatrix4(camera.matrixWorldInverse)将相机坐标系下的3D坐标转换为世界坐标系下的3D坐标。(这里代码本来不是这么写的,但是copilot给了我好多提示,我就照着他的提示改了改,如果你发现代码有问题,问问chatGPT吧)

function screenToWorld(screenX, screenY, camera,hyper_z) {
    const vector = new THREE.Vector3();
    vector.set(
        (screenX / window.innerWidth) * 2 - 1,
        -(screenY / window.innerHeight) * 2 + 1,
        hyper_z
    );
    vector.unproject(camera);
    vector.applyMatrix4(camera.matrixWorldInverse);
    return vector;
}

这里的hyper_z网上很多教程认为是写0.5,但是我实际试了一下,发现效果很差,就把他改成了一个超参数。后来在一位不能透露姓名的大佬的帮助下,得知这个参数的值应该写成1。我试了下,勉强可以得到预期的效果

通过深度图采样,shader改深度缓冲

这种方法是通过深度图采样,shader改深度缓冲,然后再通过深度缓冲得到3D坐标。这种方法的优点是可以得到更精确的3D坐标,但是缺点是需要使用shader,而且需要修改深度缓冲,可能会影响性能。

感谢chatGPT,我只需要把我需要的内容告诉他,他就会给我写一个完整的代码。

function convert2Dto3D(mouseX, mouseY, camera, width, height, scene) {
        // 构建纹理
        var depthTarget = new THREE.WebGLRenderTarget(width, height);
        depthTarget.texture.minFilter = THREE.LinearFilter;

        // 渲染深度图
        renderer.render(scene, camera, depthTarget);

        // 创建着色器
        var material = new THREE.ShaderMaterial({
            uniforms: {
                mouse: { value: new THREE.Vector2(mouseX, mouseY) },
                depthMap: { value: depthTarget.texture },
                projectionMatrix: { value: camera.projectionMatrix },
                viewMatrix: { value: camera.matrixWorldInverse }
            },
            vertexShader: `
                uniform vec2 mouse;
                uniform mat4 projectionMatrix;
                uniform mat4 viewMatrix;
                uniform sampler2D depthMap;
                varying vec4 pos;
                void main() {
                    pos = vec4(position, 1.0);
                    gl_Position = projectionMatrix * viewMatrix * pos;
                }
            `,
            fragmentShader: `
                uniform vec2 mouse;
                uniform sampler2D depthMap;
                varying vec4 pos;
                void main() {
                    float depth = texture2D(depthMap, mouse).r;
                    vec4 viewPos = vec4(mouse * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
                    vec4 worldPos = viewMatrix * viewPos;
                    worldPos /= worldPos.w;
                    gl_FragColor = vec4(worldPos.xyz, 1.0);
                }
            `
        });

        // 创建一个平面作为渲染目标
        var plane = new THREE.PlaneBufferGeometry(width, height);
        var mesh = new THREE.Mesh(plane, material);
        scene.add(mesh);

        // 渲染一次着色器并获取结果
        renderer.render(scene, camera);
        var pixelBuffer = new Uint8Array(4);
        renderer.readRenderTargetPixels(depthTarget, mouseX, height - mouseY, 1, 1, pixelBuffer);
        var worldPos = new THREE.Vector3(
            (pixelBuffer[0] / 255) * 2 - 1,
            (pixelBuffer[1] / 255) * 2 - 1,
            (pixelBuffer[2] / 255) * 2 - 1
        );
        worldPos.applyMatrix4(camera.matrixWorldInverse);
        scene.remove(mesh);
        return worldPos;
    },

    //获取触摸点的坐标并转换为ThreeJS中的坐标
    touch_crash_detect: function touch_crash_detect() {
        window.addEventListener('touchmove', (event) => {
            // screen3D_to_3DCoord(event.touches[0].clientX, event.touches[0].clientY,camera, window.innerWidth, window.innerHeight);
            let pos = space_pos_convert.get3DPosition(event.touches[0].clientX, event.touches[0].clientY, camera, scene, 1);
            if (pos.y != 0) {
                pos.y = 0;
            }
            return pos;
            // playerMesh.position.set(pos.x, pos.y, pos.z);
        });
    }

标签:ThreeJS,pos,camera,坐标,屏幕,3d,3D
From: https://www.cnblogs.com/studyinglover/p/17857339.html

相关文章

  • I3D笔记
    title:I3D笔记banner_img:https://drive.studyinglover.com/api/raw/?path=/photos/blog/background/1679397045791.jpgdate:2023-4-2322:14:00I3D笔记I3D是一个视频理解模型,采用双流网络的架构,他的核心贡献是提出了如何对2d网络进行膨胀操作,同时提出了一个新的数据集Ki......
  • Cesium 中坐标相互转换
    Cesium中坐标相互转换经纬度degree<->弧度radianradians->degrees[static]Cesium.Math.toDegrees(radians)→numberconstcoordWGS84Lon=Cesium.Math.toDegrees(coordCartographic.longitude);constcoordWGS84Lat=Cesium.Math.toDegrees(coordCartographic.......
  • django13days
    csrf跨站请求伪造钓鱼网站:模仿一个正规的网站让用户在该网站上做操作但是操作的结果会影响到用户正常的网站账户但是其中有一些猫腻 eg:英语四六级考试需要网上先缴费但是你会发现卡里的钱扣了但是却交到了一个莫名其妙的账户并不是真正的四六级官方账户模拟钓鱼......
  • threejs—01—概念
    一、物体如何移动所有的物体不管是PerspectiveCamera()还是mesh()构造函数,都是继承Object3D()的。因为继承,所以,camera实例和mesh实例,不仅可以访问自己构造函数的函数原型prototype对象里的东西,也可以访问Object3D()函数的属性。其中,Object3D()函数有一个position属性很重要,通......
  • Unity3d中使用sketchup 3dwarehouse模型
    1、选择菜单【文件】【导出】【三维模型】,打开导出对话框。选择保存类型为“*.fbx”。2、进行选项配置,“几何图形”类别勾选【导出两边的平面】【分离不连接的平面】,“材料”类别勾选【导出纹理映射】,“比例”类别中勾选【切换yz坐标(Y向上)】,单位选择【米】点击【确定】按钮。3......
  • CSE 167 3DOpenGL 开发
    我们将在本作业中开发一个用于检查3D模型的交互式界面。正如您可能从以前的家庭作业中了解到的那样,渲染需要在数百万像素和数十亿三角形。这会给性能带来重大挑战,尤其是在我们希望与内容实时交互。为了让事情变得更快,计算机图形学的先驱们提出了使用特定领域硬件加速渲染的解决......
  • Rhinoceros 8:塑造真实世界的3D建模软件 mac/win版
    Rhinoceros8是一款专业的3D建模软件,广泛应用于工业设计、建筑设计、游戏设计等领域。它拥有强大的建模工具和精准的建模功能,能够帮助设计师们快速创建高质量的3D模型。点击获取Rhinoceros8首先,Rhinoceros8具有非常直观的3D建模工具和界面。它支持各种常用的3D建模命令和操作......
  • Civil 3D使用COM API时对象版本号的查询方法
     查询对象版本有多种方法,方法一:在developer'sguide中查找,APIDeveloper'sGuide→AbouttheDeveloper'sGuide→NewFeaturesintheAutoCADCivil3DAPI→COMChanges这里有详细的介绍,不仅有当前的版本,还有上一版的版本号。方法二:在AutoCAD命令行中输入命令AeccVersio......
  • Cocos Creator 教程 : 坐标系统
    主要简单讲解下坐标系统,由于Creator是基于Cocos2dx,也就是使用OpenGL的坐标系,即原点在屏幕左下角,x轴向右,y轴向上。然后讲解下本地坐标与世界坐标,最后讲下坐标转换。点击链接加入群聊【unity/cocos交流二群】坐标系基于OpenGL坐标,也就是原点在屏幕左下角,x轴向右,y轴向上。下面讲解......
  • 论文阅读:Few-shot 3D Point Cloud Semantic Segmentation
    摘要许多现有的3D点云语义分割方法是完全监督的。这些完全监督的方法严重依赖难以获得的大量标记的训练数据,并且在训练后不能分割新的类别。为了缓解这些局限性,我们提出了一种新颖的注意力感知的多原型过渡性小样本点云语义分割方法,以分割给定的少数标记的例子的新类别。具体来说,每......