当前位置: 首页 > news >正文

iis7 添加php网站建设网站容易吗

iis7 添加php网站,建设网站容易吗,erp软件免费版,云主机免费版先进行了总结哈,具体的请往后看 核心步骤实现思路总结 第一步:搭建基本场景 实现思路: 创建Three.js三要素,通过new THREE.Scene()、new THREE.PerspectiveCamera()、new THREE.WebGLRenderer()来初始化,再用reques…

先进行了总结哈,具体的请往后看

核心步骤实现思路总结

第一步:搭建基本场景

实现思路: 创建Three.js三要素,通过new THREE.Scene()new THREE.PerspectiveCamera()new THREE.WebGLRenderer()来初始化,再用requestAnimationFrame()创建渲染循环,让画面持续刷新。

第二步:立方体内部贴图

实现思路: 加载6张贴图作为材质数组,创建立方体后使用box.geometry.scale(1, 1, -1)翻转Z轴,让贴图面朝内部,实现"站在房间里看墙壁"的效果。

第三步:相机控制

实现思路: 设置相机位置通过camera.position.set(0, 0, 0.01)实现,具体值需结合立方体大小位置来设置。通过监听鼠标事件,用camera.rotation.x/y += event.movementY/X * 0.01实现拖拽转动视角。

第四步:多房间拼接

实现思路: 创建多个立方体房间,通过Vector3精确控制位置让房间无缝拼接,如第一个房间在(0,0,0),第二个在(0,0,-10),两房间共享边界实现连通。

第五步:导航精灵

实现思路: 用Canvas绘制文字标签,转换为CanvasTexture贴到Sprite上。通过Raycaster射线检测判断鼠标点击,将屏幕坐标转换为NDC坐标(-1到+1),检测到点击后执行相机移动。

第六步:信息点处理

实现思路: 创建小图标Sprite放置在场景中,通过userData存储详细信息。鼠标悬停时用射线检测判断命中,再用worldVector.project(camera)将3D坐标转换为2D屏幕坐标,在对应位置显示提示框。

第七步:模块化封装

实现思路: 将重复的房间创建逻辑封装成Class,通过构造函数传入房间名称、贴图路径、位置等参数,内部自动完成材质加载、几何体创建、位置设置的标准流程,提高代码复用性。

核心技术要点:

  • 坐标转换:屏幕坐标 → NDC坐标 → 3D世界坐标
  • 射线检测:Raycaster实现点击和悬停交互
  • 几何体翻转:scale(1,1,-1)让贴图朝向内部
  • 位置计算:精确的Vector3坐标让房间无缝拼接

那么接下来详细的介绍一下:

第一步:搭建基本场景

// 创建场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);// 渲染循环
const render = () => {renderer.render(scene, camera);requestAnimationFrame(render);
};// 窗口自适应
window.addEventListener("resize", () => {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
});

第二步:立方体内部贴图

这一步就是经常使用的天空盒效果,非常常见,核心就是将正方体的六个面贴图处理,这里我们将图片贴在内部,下面的代码就是比较固定的方式
// 加载6面贴图材质
const materials = [];
const faces = ['room_r', 'room_l', 'room_u', 'room_d', 'room_f', 'room_b'];
faces.forEach(face => {const texture = new THREE.TextureLoader().load(`./textures/main/${face}.jpg`);materials.push(new THREE.MeshBasicMaterial({ map: texture }));
});// 创建立方体房间
const geometry = new THREE.BoxGeometry(10, 10, 10);
const box = new THREE.Mesh(geometry, materials);
box.geometry.scale(1, 1, -1); // 翻转Z轴,让贴图朝向内部
scene.add(box);

关键点:scale(1, 1, -1) - 翻转Z轴使贴图面向房间内部

第三步:相机控制

将相机移动到正方体的内部,并且使鼠标可以转动
// 相机位置:房间中心点稍微偏移,避免计算错误
camera.position.set(0, 0, 0.01); // (X轴, Y轴, Z轴)// 鼠标拖拽控制
let isMouseDown = false;
container.addEventListener("mousedown", () => { isMouseDown = true; });
container.addEventListener("mouseup", () => { isMouseDown = false; });container.addEventListener("mousemove", (event) => {if (isMouseDown) {camera.rotation.x += event.movementY * 0.01; // 上下转动camera.rotation.y += event.movementX * 0.01; // 左右转动camera.rotation.order = "YXZ"; // 旋转顺序,避免万向锁}
});

关键点:

  • Vector3(0, 0, 0.01) - 房间中心微偏移
  • rotation.order = "YXZ" - 更加符合人类的习惯

第四步:多房间拼接

其实就是再创建一个正方体,这里需要注意设置好位置,避免出现缝隙。其实你也可以不使用Vector3设置位置,通过position.set()也行
// 第二个房间材质
const bedroomMaterials = [];
const bedroomFaces = ['bedroom_r', 'bedroom_l', 'bedroom_u', 'bedroom_d', 'bedroom_f', 'bedroom_b'];
bedroomFaces.forEach(face => {const texture = new THREE.TextureLoader().load(`./textures/bedroom/${face}.jpg`);bedroomMaterials.push(new THREE.MeshBasicMaterial({ map: texture }));
});// 创建第二个房间
const bedroomGeometry = new THREE.BoxGeometry(10, 10, 10);
const bedroomBox = new THREE.Mesh(bedroomGeometry, bedroomMaterials);
bedroomBox.geometry.scale(1, 1, -1);// 房间位置:Z轴-10,与第一个房间(Z轴-5到+5)相连
const bedroomPosition = new THREE.Vector3(0, 0, -10);
bedroomBox.position.copy(bedroomPosition);
scene.add(bedroomBox);// 相机移动到第二个房间
gsap.to(camera.position, { duration: 1, x: 0, y: 0, z: -10 });

关键点:

  • Vector3(0, 0, -10) - 房间1占据Z(-5到+5),房间2占据Z(-15到-5),无缝拼接
  • Euler - 控制物体旋转角度(绕X轴, 绕Y轴, 绕Z轴)

第五步:导航精灵

极其常见的功能,就是一个卡片效果,用来展示信息或者点击之类的操作,这部分代码可以拿去复用,经常能用到;这里有一个重点,那就是如何确定拿到我想和点击的元素,那就是使用Raycaster ,注意Raycaster 的值是负一到一需要转换一下 :
// 假设屏幕尺寸 1920x1080
// 鼠标在屏幕中心点击:clientX=960, clientY=540pointer.x = (960 / 1920) * 2 - 1 = 0.5 * 2 - 1 = 0  // 中心X
pointer.y = -(540 / 1080) * 2 + 1 = -0.5 * 2 + 1 = 0 // 中心Y
// 结果:(0, 0) 正好是NDC坐标的中心点
// Canvas创建文字标签
const canvas = document.createElement("canvas");
canvas.width = 1024;
canvas.height = 1024;
const context = canvas.getContext("2d");
context.fillStyle = "rgba(50,50,50,.7)";
context.fillRect(0, 256, canvas.width, canvas.height / 2);
context.font = "bold 200px Arial";
context.fillStyle = "white";
context.fillText("Room B", canvas.width / 2, canvas.height / 2);// 创建精灵
const spriteTexture = new THREE.CanvasTexture(canvas);
const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: spriteTexture, transparent: true 
}));
sprite.position.set(0, 0, -4); // 两房间之间位置
scene.add(sprite);// 点击检测
const raycaster = new THREE.Raycaster(); // 射线检测器
const pointer = new THREE.Vector2(); // 鼠标坐标window.addEventListener("click", (event) => {// 鼠标坐标转换为NDC坐标(-1到+1)pointer.x = (event.clientX / window.innerWidth) * 2 - 1;pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;raycaster.setFromCamera(pointer, camera);const intersects = raycaster.intersectObjects([sprite]);if (intersects.length > 0) {gsap.to(camera.position, { duration: 1, x: 0, y: 0, z: -10 });}
});

关键点:

  • Sprite - 始终面向相机的2D元素
  • Raycaster - 从相机发射射线检测点击物体
  • NDC坐标 - 标准化设备坐标,范围(-1, +1)

第六步:信息点处理

1. 鼠标悬停 → 射线检测命中sprite
2. 获取userData → intersects[0].object.userData,如果射线命中了物体,返回数组(按距离排序,近到远)
3. 更新Vue数据 → tooltipContent.value = userData
4. 计算2D位置 → 3D坐标转屏幕坐标
5. 显示HTML元素 → Vue响应式更新DOM

// 创建信息点
const infoTexture = new THREE.TextureLoader().load("./images/marker.png");
const infoSprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: infoTexture, transparent: true 
}));
infoSprite.scale.set(0.2, 0.2, 0.2); // 缩放到20%
infoSprite.position.set(1.5, -0.1, -3);
infoSprite.userData = { // 存储自定义数据type: "information",name: "展示品A",description: "精美装饰品"
};// 鼠标悬停检测
function showTooltip(event) {pointer.x = (event.clientX / window.innerWidth) * 2 - 1;pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;raycaster.setFromCamera(pointer, camera);const intersects = raycaster.intersectObjects([infoSprite]);if (intersects.length > 0) {// 3D坐标转屏幕坐标const worldVector = intersects[0].object.position.clone();const screenPos = worldVector.project(camera);const x = (screenPos.x + 1) * window.innerWidth / 2;const y = (-screenPos.y + 1) * window.innerHeight / 2;// 显示tooltiptooltipElement.style.left = `${x}px`;tooltipElement.style.top = `${y}px`;}
}

关键点:

  • userData - 存储自定义数据的属性
  • project() - 将3D坐标投影到2D屏幕坐标

第七步:模块化封装

class Room {constructor(name, prefix, imagePath, scene, position = new THREE.Vector3(0,0,0)) {const materials = [];const faces = ['r', 'l', 'u', 'd', 'f', 'b'];faces.forEach(face => {const texture = new THREE.TextureLoader().load(`${imagePath}${prefix}_${face}.jpg`);materials.push(new THREE.MeshBasicMaterial({ map: texture }));});const geometry = new THREE.BoxGeometry(10, 10, 10);const room = new THREE.Mesh(geometry, materials);room.geometry.scale(1, 1, -1);room.position.copy(position);scene.add(room);}
}// 使用
new Room("主厅", "hall", "./textures/main/", scene);
new Room("卧室", "bedroom", "./textures/bedroom/", scene, new THREE.Vector3(0, 0, -10));

核心API速查

  • Vector3(x, y, z) - 3D空间位置坐标
  • Euler(x, y, z) - 3D物体旋转角度
  • scale(x, y, z) - 缩放几何体
  • Raycaster - 射线检测,用于点击/悬停判断
  • Sprite - 始终面向相机的2D元素
  • project() - 3D坐标转2D屏幕坐标
  • userData - 存储自定义数据

补充

intersects[0]的来源

1. intersects数组的产生

const raycaster = new THREE.Raycaster();
const intersects = raycaster.intersectObjects([infoSprite]);
//     ↑
//  这里返回一个数组

intersects数组结构:

// 如果射线命中了物体,返回数组(按距离排序,近到远)
intersects = [{distance: 3.2,           // 第1个物体,距离3.2object: infoSprite,      // 被命中的物体point: Vector3(1,2,3),   // 命中点坐标// ...其他信息},{distance: 5.8,           // 第2个物体,距离5.8object: anotherSprite,   // ...}
]// intersects[0] = 距离最近的被命中物体信息
// intersects.length > 0 表示至少命中了一个物体

2. 为什么用[0]?

if (intersects.length > 0) {// intersects[0] = 距离相机最近的物体// 通常我们只关心最近的那个const hitObject = intersects[0].object;const userData = intersects[0].object.userData;
}

3D坐标转2D屏幕坐标详解

1. 获取3D坐标

// 从被命中的物体获取3D世界坐标
const worldVector = new THREE.Vector3(intersects[0].object.position.x,  // 物体的X坐标intersects[0].object.position.y,  // 物体的Y坐标intersects[0].object.position.z   // 物体的Z坐标
);

2. 3D转NDC坐标

// project()方法:3D世界坐标 → NDC坐标(-1到+1)
const screenPosition = worldVector.project(camera);
// 结果:screenPosition.x 和 screenPosition.y 都在 -1 到 +1 范围内

3. NDC转屏幕像素坐标

// NDC坐标(-1到+1) → 屏幕像素坐标(0到屏幕宽高)
const elementWidth = window.innerWidth / 2;   // 屏幕宽度的一半
const elementHeight = window.innerHeight / 2; // 屏幕高度的一半const left = screenPosition.x * elementWidth + elementWidth;
const top = -screenPosition.y * elementHeight + elementHeight;
//           ↑ 注意这里有负号,因为屏幕Y轴向下,3D Y轴向上

4. 转换公式详解

// X轴转换:NDC(-1到+1) → 屏幕像素(0到屏幕宽)
// screenPosition.x = -1 时:-1 * (宽/2) + (宽/2) = 0     (屏幕左边)
// screenPosition.x = 0  时:0 * (宽/2) + (宽/2) = 宽/2   (屏幕中心)  
// screenPosition.x = +1 时:+1 * (宽/2) + (宽/2) = 宽    (屏幕右边)// Y轴转换:NDC(-1到+1) → 屏幕像素(0到屏幕高)
// screenPosition.y = +1 时:-1 * (高/2) + (高/2) = 0     (屏幕顶部)
// screenPosition.y = 0  时:0 * (高/2) + (高/2) = 高/2   (屏幕中心)
// screenPosition.y = -1 时:1 * (高/2) + (高/2) = 高     (屏幕底部)

5. 完整流程示例

// 假设物体在3D空间的位置是 (1.5, -0.1, -3)
const worldVector = new THREE.Vector3(1.5, -0.1, -3);// 转换为NDC坐标,假设结果是 (0.2, 0.1, ...)
const screenPosition = worldVector.project(camera);// 假设屏幕是1920x1080
const left = 0.2 * 960 + 960 = 1152;   // X像素位置
const top = -0.1 * 540 + 540 = 486;    // Y像素位置// 最终HTML元素显示在屏幕的(1152, 486)位置
tooltipElement.style.left = '1152px';
tooltipElement.style.top = '486px';

关键概念:

  • intersects[0] - 射线检测返回的最近物体
  • project() - Three.js内置方法,3D转NDC坐标
  • NDC坐标 - 标准化设备坐标(-1到+1)
  • 坐标系差异 - 3D Y轴向上,屏幕Y轴向下
http://www.yayakq.cn/news/389809/

相关文章:

  • 长尾关键词挖掘爱站网全免费建立自己的网站
  • 给网站做公正需要带什么公司宣传片视频怎么做
  • 个人网站备案名称填写的注意事项wordpress如何调用文章页到首页
  • 动漫网站做毕业设计简单吗河北网站建设哪家好
  • 太仓网站公司电池优化大师下载
  • 轻松筹网站可以做吗店铺推广语
  • 哪有宝安网站推广为什么不用h5做网站
  • 网站用什么构建wordpress游客登录
  • 便宜网站建设模板网站wordpress客户端linux
  • 什么网站可以做旅行行程心悦免做卡领取网站
  • 外贸电商平台哪个网站最好宁波市城乡和建设网站
  • 用什么软件来做网站网业版浏览器
  • 个人博客网站注册南开网站建设优化seo
  • 网站怎么销售天津做网站好的公司
  • 中小企业建站服务wordpress网上在线插件
  • 深圳做网站龙华信科vi手册模板60页
  • 网页设计国外设计欣赏网站如何做收机微网站
  • 青海建设网站价格低群晖nas可以做网站服务器
  • 高效网站推广网站建设推广销售话术
  • 遵义网站开发培训门户网站建设考核总结
  • 杭州企业网站制作哪个好罗定市住房和城乡建设局网站
  • 青海公司网站建设哪家好龙岗区住房建设局网站
  • 云数据库可以做网站吗郴州网站seo
  • 网站域名注册证明软件著作权登记
  • 上海 网站公司男朋友抱着我在教室做网站
  • 网站制作软件都是什么常州网络优化排名
  • 医院网站建设需求分析调研表百度下载并安装最新版
  • 网站建设礼品韩国风网站
  • 站酷网app网站利用e4a做app
  • 怎样建立营销网站软件怎么做出来的