【Threejs进阶教程-算法篇】1.常用坐标系介绍与2d/3d随机点位算法

news2024/11/26 22:50:29

2d/3d随机算法

  • 学习ThreeJS的捷径
  • 坐标系简介
    • 平面直角坐标系和极坐标系
    • 空间直角坐标系
    • 圆柱坐标系
    • 球坐标系
      • 球坐标系与直角坐标系的转换
  • 基于坐标系系统的随机点位算法
    • 平面直角坐标系随机
      • 平面直角坐标系随机的变形
    • 空间直角坐标系随机
    • 二维极坐标系随机
    • 圆柱坐标系随机
    • 基于Cylindercal(圆柱坐标系)的圆柱坐标系随机
    • 球坐标系随机
  • 随机算法的应用
    • 土星环(使用极坐标系)
    • 粒子球(使用球坐标系)

学习ThreeJS的捷径

本段内容会写在0篇以外所有的,本人所编写的Threejs教程中

对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久

如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS

  1. 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
  2. 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
  3. 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
    http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
    https://www.wellyyss.cn/ 跃焱邵隼
    http://www.wjceo.com/ 暮志未晚(暮老的站点暂时挂了,请查阅他之前的threejs相关文档)
    暮老的csdn首页
    这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处

坐标系简介

我们常见2D坐标系,一般有平面直角坐标系极坐标系
我们常见的3D坐标系,一般有空间直角坐标系圆柱坐标系球坐标系

平面直角坐标系和极坐标系

平面直角坐标系,一般以 (x,y) 两个数值来表示点位坐标
极坐标系,一般以(radius,theta),半径和旋转角度来表示点位坐标

极坐标系和平面直角坐标系可以互相转换:

	//平面直角坐标系转极坐标系
	let radius = Math.sqrt( x * x + y * y );
	let theta = Math.atan( y / x );

	//极坐标系转平面直角坐标系
	let x = radius * Math.cos(theta);
	let y = radius * Math.sin(theta);

空间直角坐标系

空间直角坐标系,一般使用(x,y,z)三个值来表示点位坐标,也就是我们在threejs中最常用的position

圆柱坐标系

圆柱坐标系,一般使用(radius,theta,height)来表示点位坐标,三个值可以根据实际使用情况做互换,圆柱坐标系,官方已经提供了相关API,我们可以查阅threejs的官方文档来更详细的了解圆柱坐标系
在这里插入图片描述
由于官方文档的内容就这些,所以这里就不贴文档源地址了,具体的圆柱坐标系到平面直角坐标系的转换算法,其实和上面极坐标算法相似,xz平面使用极坐标系来计算,y轴依然是用高度轴来计算,本质上圆柱坐标系就是极坐标系增加了高度轴的一种空间坐标系,转换公式参考极坐标系,这里不再赘述

球坐标系

球坐标系最常用的应用就是计算地球的经纬度,球坐标系一般用( radius,phi,theta)来表示点位坐标,phi可以视为纬度,theta可以视为经度,我们也可以参考threejs官方文档对球坐标系的解释
在这里插入图片描述

球坐标系与直角坐标系的转换

球坐标系到直角坐标系的互转,写法有点多,这里我贴出《3D数学基础》190页的内容,如果你的手边有这本书,书本内的183页到192页对球坐标系做了详细的介绍,这里请根据自身需求做了解即可
在这里插入图片描述
因为考虑到threejs使用右手坐标系,所以我们的公式以Threejs提供的为准

	//直角坐标系转球坐标系,这里我们以threejs官方开发包中
	//src/math/Spherical.js 中为准
	setFromCartesianCoords( x, y, z ) {
		this.radius = Math.sqrt( x * x + y * y + z * z );
		if ( this.radius === 0 ) {
			this.theta = 0;
			this.phi = 0;
		} else {
			this.theta = Math.atan2( x, z );
			this.phi = Math.acos( MathUtils.clamp( y / this.radius, - 1, 1 ) );
		}
		return this;
	}

	//球坐标系转换平面直角坐标系,这里我们以thrjeejs官方开发包中
	//src/math/Vector3.js 564行的算法为准
		setFromSphericalCoords( radius, phi, theta ) {

		const sinPhiRadius = Math.sin( phi ) * radius;

		this.x = sinPhiRadius * Math.sin( theta );
		this.y = Math.cos( phi ) * radius;
		this.z = sinPhiRadius * Math.cos( theta );

		return this;

	}

基于坐标系系统的随机点位算法

平面直角坐标系随机

默认的情况下,场景使用的是空间直角坐标系

	     for(let i = 0;i< 100;i++){
            let geometry = new THREE.BoxGeometry(1,1,1);
            let material = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);

            mesh.position.x = Math.random() * 10 - 5;
            mesh.position.z = Math.random() * 10 - 5;
            scene.add(mesh);
        }

在这里插入图片描述
因为我们这里仅操作了x轴和z轴,高度轴均保持一致,这样的随机为平面直角坐标系的随机,当然,我们也可以选择随机x轴和y轴,随机y轴和z轴,根据你自身的需求来做即可

这样的以x轴和z轴为随机的方式,可以用于在某个地区生成随机数量的树木,我们在代码中,xz轴的随机范围均为 -5 ~ 5 ,所以我们实际上是在

Math.random()的取值范围为 0~1,Math.random() * 10的取值范围为0 ~ 10,Math.random() * 10 - 5的取值范围为 -5 ~ 5

平面直角坐标系随机的变形

变形其实非常简单,只需要控制position.x,position.y,position.z其中两个轴,就可以控制物体在哪个平面上随机

空间直角坐标系随机

基本上没啥说的,只是在上面的基础上,将三个轴都参与随机

二维极坐标系随机

	     for(let i = 0;i< 100;i++){
            let geometry = new THREE.BoxGeometry(1,1,1);
            let material = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);

            let angle = Math.random() * Math.PI * 2;
            let radius = Math.random() * 10;

            let x = Math.cos(angle) * radius;
            let z = Math.sin(angle) * radius;
            mesh.position.x = x;
            mesh.position.z = z;
            scene.add(mesh);
        }

在这里插入图片描述
这样其实我们看的不太明显,我们可以选择随机的方块数量大幅增加,或者让半径不再随机
在这里插入图片描述

	替换随机的半径
    // let radius = Math.random() * 10;
    let radius = 10;

在这里插入图片描述
生成1000个盒子,只需要修改for循环的100为1000即可

圆柱坐标系随机

其实就是在极坐标系的基础上,增加对高度轴y轴的随机数即可
这里我们对半径不做随机,相对来说结果更显而易见,如果你需要在圆柱范围内随机,将固定的radius改为随机即可

	     for(let i = 0;i< 1000;i++){
            let geometry = new THREE.BoxGeometry(1,1,1);
            let material = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);

            let angle = Math.random() * Math.PI * 2;
            let radius = 10;

            let x = Math.cos(angle) * radius;
            let z = Math.sin(angle) * radius;
            mesh.position.x = x;
            mesh.position.z = z;
            mesh.position.y = Math.random() * 10 - 5;
            scene.add(mesh);
        }

在这里插入图片描述

基于Cylindercal(圆柱坐标系)的圆柱坐标系随机

这里使用了上述的Cylindercal的概念,如果你实在绕不过来极坐标系,可以考虑使用这个

        let cylindrical = new THREE.Cylindrical();
        for(let i = 0;i< 1000;i++){
            let geometry = new THREE.BoxGeometry(1,1,1);
            let material = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);
            cylindrical.radius = 10;
            cylindrical.theta = Math.random() * Math.PI * 2;
            cylindrical.y = Math.random() * 10 - 5;
            //文档在Vector3中
            mesh.position.setFromCylindrical(cylindrical);
            scene.add(mesh);
        }

效果与上面一致,这里不再截图

球坐标系随机

球坐标系随机,这里仅建议使用官方的Spherical来进行随机

        let spherical = new THREE.Spherical()
        for(let i = 0;i< 1000;i++){
            let geometry = new THREE.BoxGeometry(1,1,1);
            let material = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            });
            let mesh = new THREE.Mesh(geometry,material);
            spherical.radius = 10;
            spherical.phi = Math.random() * Math.PI * 2;
            spherical.theta = Math.random() * Math.PI * 2;
            mesh.position.setFromSpherical(spherical);
            scene.add(mesh);
        }

在这里插入图片描述

随机算法的应用

土星环(使用极坐标系)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            border: 0;
        }
        body{
            width:100vw;
            height: 100vh;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
			{
				"imports": {
					"three": "../three/build/three.module.js",
					"three/addons/": "../three/examples/jsm/"
				}
			}
		</script>

<script type="module">

    import * as THREE from "../three/build/three.module.js";
    import {OrbitControls} from "../three/examples/jsm/controls/OrbitControls.js";

    window.addEventListener('load',e=>{
        init();
        addMesh();
        render();
    })

    let scene,renderer,camera;
    let orbit;

    function init(){

        scene = new THREE.Scene();
        renderer = new THREE.WebGLRenderer({
            alpha:true,
            antialias:true
        });
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement);

        camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,0.1,2000);
        camera.add(new THREE.PointLight());
        camera.position.set(10,10,10);
        scene.add(camera);

        orbit = new OrbitControls(camera,renderer.domElement);
        orbit.enableDamping = true;

        scene.add(new THREE.GridHelper(10,10));
    }


    let groups = [];
    function addMesh() {

        //创建中心的球体
        let geometry = new THREE.SphereGeometry(10,32,32);
        let material = new THREE.MeshStandardMaterial({
            color:0xffffff * Math.random()
        });
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);


        //创建5层土星环
        for(let i = 0;i< 5;i++){
            let group = new THREE.Group();

            let material2 = new THREE.MeshStandardMaterial({
                color:0xffffff * Math.random()
            })

            //每层土星环创造100个图块
            for(let j = 0;j < 100;j++){
                let geometry2 = new THREE.BoxGeometry();
                let mesh2 = new THREE.Mesh(geometry2,material2);
                group.add(mesh2);
                //在 15 ~ i*2的半径范围内,生成指定的星环
                let radius = Math.random() * i * 2 + 15;
                let theta = Math.random() * Math.PI * 2;
                mesh2.position.x = Math.cos(theta) * radius;
                mesh2.position.z = Math.sin(theta) * radius;
                //随机初始角度
                mesh2.rotation.set(
                    Math.random() * Math.PI * 2,
                    Math.random() * Math.PI * 2,
                    Math.random() * Math.PI * 2,
                )
                //随机大小
                mesh2.scale.set(
                    Math.random() * 2,
                    Math.random() * 2,
                    Math.random() * 2,
                )
                //注意,onBeforeRender,只有具有材质属性的物体,才生效,对group不生效
                mesh2.onBeforeRender = ()=>{
                    mesh2.rotation.x += 0.01;
                    mesh2.rotation.y += 0.01;
                }
            }
            scene.add(group);
            groups.push(group);
        }

    }

    function render() {
        renderer.render(scene,camera);
        orbit.update();
        requestAnimationFrame(render);
        //让每一层的星环转起来
        for(let i = 0;i< groups.length;i++){
            groups[i].rotation.y += 0.001 * (i+1);
        }
    }

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

在这里插入图片描述
效果如上,我不是设计师,所以不用太纠结好看与不好看的问题

粒子球(使用球坐标系)

这里就不贴完整代码了

    function addMesh() {

        let spherical = new THREE.Spherical();

        let vectors = [];
        for(let i = 0;i< 1000;i++){
            spherical.radius = Math.random() * 100
            spherical.theta = Math.random() * Math.PI * 2;
            spherical.phi = Math.random() * Math.PI * 2;
            let vec = new THREE.Vector3().setFromSpherical(spherical);
            vectors.push(vec);
        }

        let geometry = new THREE.BufferGeometry().setFromPoints(vectors);
        let points = new THREE.Points(
            geometry,
            new THREE.PointsMaterial({
                sizeAttenuation:true,
            })
        );
        points.onBeforeRender = ()=>{
            points.rotation.x += 0.001;
            points.rotation.y += 0.001;
        }
        scene.add(points);
    }

在这里插入图片描述

有的人也许已经看出来了,粒子球可以用作创建星空(也不一定非要用球坐标系来创建也可以创建星空),粒子球也是烟花效果的基础

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 整数类型(int)详解:无限范围与多种进制

引言 在编程中&#xff0c;整数是最基本的数据类型之一。不同编程语言对整数的处理方式各不相同&#xff0c;这往往影响到程序的性能和开发者的选择。本文将深入探讨 Python 中的整数类型&#xff08;int&#xff09;&#xff0c;其独特的处理方式&#xff0c;以及它在日常编程…

Lambda表达式 怎么debug调试

前言 Lambda 表达式是 JDK8 的一个重要新特性&#xff0c;可以取代大部分的匿名内部类&#xff0c;写出更优雅的 Java 代码&#xff0c;尤其在集合的遍历和其他集合操作中&#xff0c;可以极大地优化代码结构。JDK 也提供了大量的内置函数式接口供我们使用&#xff0c;使得 La…

【Chrome实用命令笔记】

文章目录 Chrome实用命令笔记1、chrome基本介绍2. 打开开发者工具&#xff08;DevTools&#xff09;方法一&#xff1a;快捷键方法二&#xff1a;右键菜单方法三&#xff1a;浏览器设置 2. 开发者工具面板Elements面板Console面板Sources面板Network面板Performance面板Memory面…

C++ 数据结构算法 学习笔记(25) - 图及其企业级应用

C 数据结构算法 学习笔记(25) - 图及其企业级应用 图的故事导入 故事情节 Jack 自从买车后&#xff0c;交通出行方便了&#xff0c;心自然就野了&#xff01;身边的各种朋友自然就多了起来&#xff01; 有一天晚上&#xff0c;一个年轻漂亮的女同事生日&#xff0c;Jack 受邀…

python 自定义包的实现

1. 代码目录 创建自定义包的时候&#xff0c;原理是当 python 检测到一个目录下存在 __init__.py 文件时&#xff0c;python 就会把它当成一个模块(module)。 下面这个例子是网上整理的代码&#xff0c;但是有些小改动&#xff0c;可以直接拿来就用。 看代码结构&#xff1a;…

springboot+vue+mybatis社交网络平台+PPT+论文+讲解+售后

近些年来&#xff0c;随着科技的飞速发展&#xff0c;互联网的普及逐渐延伸到各行各业中&#xff0c;给人们生活带来了十分的便利&#xff0c;社交网络平台利用计算机网络实现信息化管理&#xff0c;使整个社交网络管理的发展和服务水平有显著提升。 本文拟采用Eclipse开发工具…

免费证件照一键换底色

最近星期天在家搞了一个小工具&#xff0c;在这里分享下! 废话不多说看看效果&#xff1a; 效果还不错&#xff0c;需要的可以联系我!!!!!!!!! 别的网上可都是一次五块钱这种。太贵了。。&#xff01;&#xff01;

Python - 深度学习系列33 - ollama_langchain_ppt生成

说明 只是为了速记一下这个实践过程。整体上说&#xff0c;这个结果并不是那么好用&#xff0c;但有一些可以借鉴的地方。 先看结果&#xff1a; 生成的PPT 说的直白点&#xff0c;就是用大模型生成了一堆没太有意义的文字&#xff0c;然后做成ppt。所以实用是不成的&#…

Golang | Leetcode Golang题解之第85题最大矩形

题目&#xff1a; 题解&#xff1a; func maximalRectangle(matrix [][]byte) (ans int) {if len(matrix) 0 {return}m, n : len(matrix), len(matrix[0])left : make([][]int, m)for i, row : range matrix {left[i] make([]int, n)for j, v : range row {if v 0 {continu…

【Spring Boot】Spring Boot 中的 Starter

Spring Boot 中的 Starter 1.常用 Starter2.为什么要用 Starter3.Starter 有哪些要素 我们都知道&#xff0c;Spring 的功能非常强大&#xff0c;但也有些弊端。比如&#xff1a;我们需要手动去配置大量的参数&#xff0c;没有默认值&#xff0c;需要我们管理大量的 jar 包和它…

SAP-CentralFinance - 学习心得2

过账总账中的交易 业务示例 创建大量日记账分录是会计日常工作的一部分。在SAP,会计可以使用不同的输入屏幕。使用所有方法,总账科目过账会自动列在损益表报表中(如果财务报表版本中包含科目)。查询已过账科目时还可显示对应的过账。 贵公司计划通过企业基金增加资本。在…

kafka安装配置及集成springboot

1. 安装 单机安装kafka Kafka对于zookeeper是强依赖&#xff0c;保存kafka相关的节点数据&#xff0c;所以安装Kafka之前必须先安装zookeeper dockerhub网址: https://hub.docker.com Docker安装zookeeper 下载镜像&#xff1a; docker pull zookeeper:3.4.14创建容器 doc…

《C++学习笔记---初阶篇6》---string类 上

目录 1. 为什么要学习string类 1.1 C语言中的字符串 2. 标准库中的string类 2.1 string类(了解) 2.2 string类的常用接口说明 2.2.1. string类对象的常见构造 2.2.2. string类对象的容量操作 2.2.3.再次探讨reserve与resize 2.2.4.string类对象的访问及遍历操作 2.2.5…

PPMP_char3

PMPP char3 – Multidimensional grids and data ​ 五一过后&#xff0c;有些工作要赶&#xff0c;抽出时间更新一下。这一章基本都熟练掌握&#xff0c;在做习题过程中有一些思考。这里涉及到了一点点GEMM&#xff08;矩阵乘&#xff09;&#xff0c;GEMM有太多可深挖的了&a…

Ubuntu24 文件目录结构——用户——权限 详解

目录 权限 用户 文件目录结构 一个目录可以有程序&#xff0c;目录&#xff0c;文件&#xff0c;以及这三者的链接。可以看到还分别有使用者和权限信息。 每个文件和目录都有与之关联的三个主要属性&#xff1a;所有者&#xff08;owner&#xff09;、组&#xff08;group&a…

【ESP32接入ATK-MO1218 GPS模块】

【ESP32接入ATK-MO1218 GPS模块】 1. 引言2. ATK-MO1218 GPS模块概述3. 接入ATK-MO1218 GPS模块的步骤4. 示例代码5. 结论1. 引言 在现代的嵌入式系统和物联网项目中,精确的位置信息是至关重要的。ATK-MO1218 GPS模块作为一款高性能的GPS/北斗双模定位模块,为开发者提供了强…

【Qt 学习笔记】Qt常用控件 | 容器类控件 | Tab Widget的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 容器类控件 | Tab Widget的使用及说明 文章编号&#xf…

实现红黑树

目录 红黑树的概念 红黑树的节点结构定义 红黑树的插入 红黑树的验证 实现红黑树完整代码 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red 或 Black 。 通过对 任何一条从根到叶子的…

You Only Cache Once:YOCO 基于Decoder-Decoder 的一个新的大语言模型架构

这是微软再5月刚刚发布的一篇论文提出了一种解码器-解码器架构YOCO&#xff0c;因为只缓存一次KV对&#xff0c;所以可以大量的节省内存。 以前的模型都是通过缓存先前计算的键/值向量&#xff0c;可以在当前生成步骤中重用它们。键值(KV)缓存避免了对每个词元再次编码的过程&…

基于SSM的“网约车用户服务平台”的设计与实现(源码+数据库+文档)

基于SSM的“网约车用户服务平台”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能 首页 站内新闻浏览 打车信息查询功能 在线打车功能…