3D山脉——java实现山脉模型

平面及3D山脉——Java实现 1,画平面山脉 大概思路就是给定两个点(x1,y1),(x2,y2),然后取他们的中点(px,py),然后再取(x1,y1)和(px,py)的中点和(x2,y2)和(px,py)的中点,同时给定一个范围[-range,range]和一个比率rate,每次取中点后的中点纵坐标都加上这个范围内的随机值,每次中点后range都乘以rate来缩小range的范围。当两个点的横坐标小于某个值或者不能再取中点时就连接起来,即可。 递归方法的代码 public void draw(double x1,doubl. 阅读详情

做这个3D山脉搞了我一下午的时间,从开始的大体构造到一步一步地解决细节问题,在此篇文章中我将一一描述我在构造山脉时遇到的问题,希望对大家有帮助

先上效果图吧
在这里插入图片描述

在这里插入图片描述

基本原理

在这里插入图片描述
递归,分形的灵魂
首先我们在屏幕上随机取三个点,然后每两个点取中值动荡点,再利用新产生的点画三角形,最后就能有这样的3D效果

随机取三个点

int x1=rand.nextInt(200)+480;
			int y1=rand.nextInt(200);
			int x2=rand.nextInt(300);
			int y2=rand.nextInt(100)+800;
			int x3=rand.nextInt(300)+1600;
			int y3=rand.nextInt(100)+800;

中值动荡点的生成
以一个点为例

double ranx1=(x1+x2)/k;//产生动荡值,k会随着迭代次数成倍增加
double rany1=(y1+y2)/k;
X1=(x1+x2)/2+rand.nextInt((int)ranx1*2+1)-ranx1;
Y1=(y1+y2)/2+rand.nextInt((int)rany1*2+1)-rany1;

基本点就是这样,下面我们来写这个迭代的具体方法

代码实现

我这里给出常见的错误代码,应该是最开始写这种东西都会有的错误

//参数分别为三个点的坐标,迭代层数,和震荡程度k
public void draw3D(Graphics g, int x1, int y1, int x2, int y2, int x3, int y3, int depth, int k) {
		if (depth > 1) {
//取震荡值
			double ranx1 = (x1 + x2) / k;
			double rany1 = (y1 + y2) / k;
			double ranx2 = (x2 + x3) / k;
			double rany2 = (y2 + y3) / k;
			double ranx3 = (x1 + x3) / k;
			double rany3 = (y1 + y3) / k;

			double Y1;
			double X2;
			double Y2;
			double X3;
			double Y3;
//中值震荡点
				X1 = (x1 + x2) / 2 + rand.nextInt((int) ranx1 * 2 + 1) - ranx1;
				Y1 = (y1 + y2) / 2 + rand.nextInt((int) rany1 * 2 + 1) - rany1;

				X2 = (x2 + x3) / 2 + rand.nextInt((int) ranx2 * 2 + 1) - ranx2;
				Y2 = (y2 + y3) / 2 + rand.nextInt((int) rany2 * 2 + 1) - rany2;

				X3 = (x1 + x3) / 2 + rand.nextInt((int) ranx3 * 2 + 1) - ranx3;
				Y3 = (y1 + y3) / 2 + rand.nextInt((int) rany3 * 2 + 1) - rany3;
//根据新的点迭代
			draw3D(g, (int) x1, (int) y1, (int) X1, (int) Y1, (int) X3, (int) Y3, depth - 1, k * 2);
			draw3D(g, (int) X1, (int) Y1, (int) x2, (int) y2, (int) X2, (int) Y2, depth - 1, k * 2);
			draw3D(g, (int) X1, (int) Y1, (int) X2, (int) Y2, (int) X3, (int) Y3, depth - 1, k * 2);
			draw3D(g, (int) X3, (int) Y3, (int) X2, (int) Y2, (int) x3, (int) y3, depth - 1, k * 2);

		} else {
			int[] px = { x1, x2, x3 };
			int[] py = { y1, y2, y3 };
			g.drawPolygon(px, py, 3);
		}
	}

我们看着这个代码会觉得没问题啊,逻辑很明确,但实际上这只完成了一半的工作,我们看看效果
在这里插入图片描述
出现了大量的空白,为什么?
我们把迭代次数调小一点看看

draw3D(g, x1, y1, x2, y2, x3, y3, /*9*/3, 8);

把9改为3
效果是这样的
在这里插入图片描述
原来,在迭代取中值震荡点的时候取到了两次,就产生了两个震荡点,这就是问题所在。

问题解决

要解决这样的问题有很多种方法,主要思路就是将每次生成的边存起来(两个点确定一条边),如果在迭代的过程中出现了相同的点,那么就不再生成中值震荡点,选用最初产生的中值震荡点,所以我们想到建立一个存储点和中值震荡点的方法。我这里选用的是最基础的方法,创建一个类来储存。

此类如下

public class Points {
		Points(int x1, int x2, int y1, int y2, double X, double Y) {
			this.x1 = x1;
			this.x2 = x2;
			this.y1 = y1;
			this.y2 = y2;
			this.X = X;
			this.Y = Y;
		}

		int x1;
		int x2;
		int y1;
		int y2;
		double X;
		double Y;
	}
	Points[] po = new Points[5000000];//创建足够大的数组存储对象

接下来就好办了,
每次产生一个之前未出现的边时就将其存入数组对象中

Points p = new Points(x1, x2, y1, y2, X1, Y1);
				po[count ] = p;
				count++;

然后在每次迭代的时候判断此边是否出现过即可
完整代码如下

public class Points {
		Points(int x1, int x2, int y1, int y2, double X, double Y) {
			this.x1 = x1;
			this.x2 = x2;
			this.y1 = y1;
			this.y2 = y2;
			this.X = X;
			this.Y = Y;
		}

		int x1;
		int x2;
		int y1;
		int y2;
		double X;
		double Y;
	}

	Points[] po = new Points[5000000];
	Random rand = new Random();//创建随机数对象
	int count = 0;

	public void draw3D(Graphics g, int x1, int y1, int x2, int y2, int x3, int y3, int depth, int k) {
		if (depth > 1) {
			int u = 0, j = 0, o = 0;//这里必须要赋值,否则会报错说可能没有被赋予初始值,这个问题在c++里只是个warning。其实这里不赋值理论上也可,其没有值的时候也不会用到它们,细心的小伙伴可以看看是否是这样
			double ranx1 = (x1 + x2) / k;
			double rany1 = (y1 + y2) / k;
			double ranx2 = (x2 + x3) / k;
			double rany2 = (y2 + y3) / k;
			double ranx3 = (x1 + x3) / k;
			double rany3 = (y1 + y3) / k;
			boolean f1 = true;
			boolean f2 = true;
			boolean f3 = true;
			for (int i = 0; i < count; i++) {//边的确定,也就是两个点的确定一定要把x和y的坐标一起加上,我最开始认为只用判断横坐标即可,大家可以试试只判断横坐标出来的效果,我这里就不展示了
				if ((x1 == po[i].x1 && x2 == po[i].x2 && y1 == po[i].y1 && y2 == po[i].y2)
						|| (x1 == po[i].x2 && x2 == po[i].x1 && y1 == po[i].y2
								&& y2 == po[i].y1){
					f1 = false;
					u = i;
					break;
				}
			}
			for (int i = 0; i < count; i++) {
				if ((x2 == po[i].x1 && x3 == po[i].x2 && y2 == po[i].y1 && y3 == po[i].y2)
						|| (x2 == po[i].x2 && x3 == po[i].x1 && y2 == po[i].y2
								&& y3 == po[i].y1) {
					f2 = false;
					j = i;
					break;
				}
			}
			for (int i = 0; i < count; i++) {
				if ((x1 == po[i].x1 && x3 == po[i].x2 && y1 == po[i].y1 && y3 == po[i].y2)
						|| (x1 == po[i].x2 && x3 == po[i].x1 && y1 == po[i].y2
								&& y3 == po[i].y1) {
					f3 = false;
					o = i;
					break;
				}
			}
			double X1;
			double Y1;
			double X2;
			double Y2;
			double X3;
			double Y3;
			if (f1 == false) {
				X1 = po[u].X;
				Y1 = po[u].Y;
			} else {
				X1 = (x1 + x2) / 2 + rand.nextInt((int) ranx1 * 2 + 1) - ranx1;
				Y1 = (y1 + y2) / 2 + rand.nextInt((int) rany1 * 2 + 1) - rany1;
				Points p = new Points(x1, x2, y1, y2, X1, Y1);
				count++;
				po[count - 1] = p;
			}
			if (f2 == false) {
				X2 = po[j].X;
				Y2 = po[j].Y;
			} else {
				X2 = (x2 + x3) / 2 + rand.nextInt((int) ranx2 * 2 + 1) - ranx2;
				Y2 = (y2 + y3) / 2 + rand.nextInt((int) rany2 * 2 + 1) - rany2;
				Points p = new Points(x2, x3, y2, y3, X2, Y2);
				count++;
				po[count - 1] = p;
			}
			if (f3 == false) {
				X3 = po[o].X;
				Y3 = po[o].Y;
			} else {
				X3 = (x1 + x3) / 2 + rand.nextInt((int) ranx3 * 2 + 1) - ranx3;
				Y3 = (y1 + y3) / 2 + rand.nextInt((int) rany3 * 2 + 1) - rany3;
				Points p = new Points(x1, x3, y1, y3, X3, Y3);
				count++;
				po[count - 1] = p;
			}
			draw3D(g, (int) x1, (int) y1, (int) X1, (int) Y1, (int) X3, (int) Y3, depth - 1, k * 2);
			draw3D(g, (int) X1, (int) Y1, (int) x2, (int) y2, (int) X2, (int) Y2, depth - 1, k * 2);
			draw3D(g, (int) X1, (int) Y1, (int) X2, (int) Y2, (int) X3, (int) Y3, depth - 1, k * 2);
			draw3D(g, (int) X3, (int) Y3, (int) X2, (int) Y2, (int) x3, (int) y3, depth - 1, k * 2);

		} else {
			int[] px = { x1, x2, x3 };
			int[] py = { y1, y2, y3 };
			g.drawPolygon(px, py, 3);
		}
	}				

事实上,用数组来存点的效率是很低的,但是,说来惭愧,我能力有限,可能在之后掌握了map和list等用法过后会加以改进的吧,如果有感兴趣的朋友的话可以找我一起讨论讨论,我的QQ是 869083577.

递归分形--山脉 绘制面板 public class DrawPanel extends JFrame{ static Graphics g; ImageObserver imageObserver; public Graphics getG() { return g; } public void ShowUi() { //流式布局 this.setLayout(new FlowLayout()); Button 阅读详情

相关推荐

3D模拟自然——山体

之前分形论文的工作,3d分形

幺鸡报晓的博客 1609

java---实现3D山脉模型

核心理念:递归 其实3D山脉基本思路可以认为是平面山脉和谢冰斯基三角形的结合体,敲代码之前请大家先了解一个概念中值震荡点,即取两个点中点时需要让中点的横坐标或纵坐标或同时减或加上一个极小的随机值,来产生山脉连绵起伏的效果 初步思路: 1.图中随机选取三个点 2.然后取中值震荡点 3. 大功告成,感谢观众老爷们阅读 ≧◇≦,如有错误,敬请指正 ...

ReturnTmp的博客 995

Python构建Minecraft风格体素引擎:从零实现3D游戏核心架构

游戏引擎是驱动现代电子游戏运行的核心软件框架,它负责图形渲染、物理模拟、资源管理等关键任务。其基本原理是通过游戏循环持续处理用户输入、更新游戏状态并渲染画面,实现实时交互体验。在3D游戏开发中,体素引擎作为一种特殊类型,使用三维像素(体素)构建游戏世界,具有独特的视觉风格和数据结构优势。从技术价值看,亲手实现引擎能深入理解图形管线、空间数据结构等底层原理,比使用现成引擎更能培养系统架构能力。常见的应用场景包括教育演示、原型开发以及特定风格的独立游戏制作。本文聚焦于使用Python及相关库构建Minecraf

cuhongjiao7003的博客 287

java画图板之3D地形图(hashmap初步使用)

    之前我们已经尝试过了绘制平面山水画了,这次我们用与之相类似的方法,绘制“3D”地形图。     为什么加了引号?因为我们的点的坐标还是二维的,所以只是看起来有3D的效果,但是我们可以扩展一下,用同样的方法,将点的坐标改为三维,绘制出来的就是真正的三维图像了。 原理    &nbsp...

thunder200的博客 1214

基于分形理论的三维地形生成算法研究与实现

这是关于图形学的文章,基于分形理论的三维地形生成算法研究与实现,研 究和分析基 于分形理论的三维立体地形建模算法的数 学原理 , 实现 步骤 , 优 点和存在 的不足。 重点讨论 四 边形细分 法的基本原理 以及在三维地形建模 中 的应 用 , 并通过 O penGL 语 言对其进行 可视化仿真。 实验结果表 明 , 算法有效 、可行 , 完 全 可 应 用 于 大型 地 理 信 息 系统 和 可视 化 系统 中。

用opengl实现分形山

opengl实现分形山 程序通过ForTree类建立分形山的三角面片构形,在MFC_FrameView类中通过OpenGL进行三角面片的绘制,法向量的设置,光照的效果灯。在ColorSettingDialog类中进行颜色属性的调整,在主框架中通过6个按钮进行视角的变换。

三角形分形山脉

三角形分形山脉原理 原型图 如图,这是三角形分形山脉的一个原型图。首先我们让x1、x2、x3三个点组成的三角形的各条边的中点mid1、mid2、mid3可以在大三角形内部画一个三角形,这时就会有四个小三角形,那么我们对这四个小三角形做同样的操作,如此就可以画出雏形了。接下来我们只需要对内部每个需要连线三角形的y坐标 ...

qq_44836027的博客 1751

U3D山脉模型资源

U3D山脉模型资源

matlab三维山峰/山脉/山地曲面数据图

matlab三维山峰/山脉/山地曲面数据图可以使用peaks函数。比如直接peaks(80):peaks(80) z = 3*(1-x).^2.*exp(-(x.^2) - (y+1).^2) ... - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2-y.^2) ... - 1/3*exp(-(x+1).^2 - y.^2) peaks(80)的三维数据

Zhang Phil 2万+

opengl实现分形山脉

opengl实现分形山脉,计算机图形学的作业。

基于Java的地层3维建模与可视化

摘 要:利用 Java 3D技术建立一个地层可视化 3 维建模系统,实现地层 3 维模型漫游、旋转、剖切等功能,并以某地区地下水资源调查评价中采集的地质钻孔数据为例,验证该系统的有效性。该系统将不仅为地下水模型的 3 维实体建模提供理论支持,而且将推动 WebGIS在地下水模型中的应用。

java——从心率图到分形山脉再到神级抽象山脉

前言 整这个山脉花了我好长时间,最开始老师给我提出这个课题的时候大概是5天前吧,开始的时候想了一段时间,没想出来,结果落下了。中间断了几天搞学校的事儿去了,今天晚上又去上课了解了一下,再参考了一下学长的代码才终于整了出来,并且在途中还弄出了一些意想不到的结果(图像还是挺有趣的,就是不知道原理是什么) 先上几张我做的过程中的图吧 这是第一次的,直接做成对称心率了。。。 第二次,线条不连接,但是有勒味儿了 这就是意外的结果,老师说比要求做的还好,还让我把代码发给他,实际上我是懵逼的,为啥会出现这种,我也不知道啊

CatCatchCap的博客 446

FMCW毫米波雷达原理一

1、简介 毫米波雷达的优点是角分辨率高、频带宽因而有利于采用脉冲压缩技术、多普勒颇移大和系统的体积小。目前笔者接触到的有24G毫米波雷达和77G毫米波雷达。 24G毫米波雷达主要应用在交通领域的测距和车辆测速,在其他领域也有使用24G毫米波雷达。 77G毫米波雷达主要应用在无人驾驶,汽车周围的目标检测等领域。 在首次接触雷达时,一头雾水。搞不清一个chirp的时域图和频域图的关系、中频信号以及其他名词的基本概念。在TI培训官网上看到一些毫米波雷达原理的视频才豁然开朗。TI培训官网毫米波传感介绍 本文主要是通

擎天柱工坊 8147

山脉2D-3D绘制

山脉2d-3d绘制

qq_46931102的博客 242

网格自适应实战 | 攻克超弹性体大变形不收敛难题

本文针对超弹性体(如橡胶)在大变形仿真中因网格严重扭曲导致计算不收敛的难题,提供了基于ANSYS网格自适应技术的实战解决方案。文章详细阐述了从问题诊断、模型准备到核心参数设置的完整流程,并介绍了结合混合U-P单元技术的进阶组合策略,有效攻克了材料压缩等场景下的仿真收敛问题。

week9的博客 522

matlab/simulink saw谐振器仿真,基于Matlab的SAW模态耦合模型的仿真研究

第32卷 第 4 期Vol. 32 No. 4重 庆 理 工 大 学 学 报 (自然科学)Journal of Chongqing University of Technology( Natural Science)2 0 1 8年 4 月Apr. 2018doi : 10.3969/j . issn. 1674-8425(z). 2018.04.002本文引用格式 :李志鹏,马龙祥,孟旭,等•基...

weixin_36192634的博客 1386

Android 3D模型展示

开发工具:Unity3d 2017.3       Android Studio 3.       Visual studio 2017 开发语言 : C#  , java   3D场景,本人做的是一个简单的3D海岛场景,里面有山脉,椰子树,草 岛周围是海,海水可以动,虽然效果不明显。 下面是单指拖动,双指放大缩小的脚本代码 using System.Collections; using...

congcong7267的博客 1万+

Allegro如何用自带的功能将线段变成铜皮操作指导

在做PCB设计的时候,有时根据设计需要将线段变成铜皮,可以借助辅助工具来实现这一操作,但是Allegro自身也自带这个功能,如下图。勾选Delete original objects。如何用自带的功能将线段变成铜皮操作指导。勾选Convert to shape,需要把这段走线变成铜皮。

weixin_54787054的博客 2946

网页游戏3D技术

首家网页游戏3D技术团队诞生 惊爆,国内已有一团队研发出纯3D网页游戏的引擎。面对市面上那些简单的页面游戏、FLASH2D游戏,拥有绝对的技术优势,网页游戏是否就要进入3D时代?网页游戏目前发展非常迅速,网页游戏非常多,但是真正的3D网页游戏目前国内一款都没有,全世界仅有一款英国公司制作的纯3D网页游戏。 3D网页游戏相对传统网页游戏来说,从技术层面主要有以下几个优势: 1、3D即时渲染画面 基于三角形的渲染流水线,全即时渲染的真3D画面,支持视角的自由平移旋转缩放,支持各种特性如光照、半透明、真实感阴影、

水上漂的专栏 4353

pycharm下载continue插件接入DeepSeek的API,向其提问输出乱码,如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 2224

【升级U8+】不能将值 NULL 插入列 ‘VT_ID‘,表 ‘VoucherItems‘;列不允许有 Null 值。

不能将值 NULL 插入列 ‘VT_ID’,表 ‘UFDATA_006_2012.dbo.VoucherItems’;列不允许有 Null 值。INSERT 失败。

努力不懈的为广大客户提供优质的产品与真诚、贴心、专业的服务! 517

ArcGIS Maps SDK for Unity实战:把真实世界山脉‘搬进’游戏场景的五个关键步骤

本文详细介绍了使用ArcGIS Maps SDK for Unity将真实世界山脉融入游戏场景的五个关键步骤,包括高程数据获取、格式转换、Unity地形系统集成、视觉增强和性能优化。通过实战案例和技术建议,帮助开发者高效处理离线高程数据,实现真实地形与虚拟场景的无缝结合,特别适合需要高精度地理数据的游戏开发项目。

weixin_33704234的博客 432

Swin Transformer 与 CNN 结合实现图像分类

Swin Transformer 与 CNN 结合实现图像分类。(含swin transformer 结构讲解,cnn网络搭建,代码)

这里是Mae。 5027

Arnis:将现实世界搬进Minecraft的3D城市生成神器

你是否曾梦想在Minecraft中重建自己家乡的街道,或是在虚拟世界中游览世界著名城市?现在,Arnis让这一切成为可能。这款开源工具能将真实世界的地理数据转化为精美的Minecraft城市,无论你是编程新手还是Minecraft爱好者,都能轻松创造出令人惊叹的虚拟世界。 ## 为什么Arnis与众不同? Arnis不仅仅是一个简单的Minecraft地图生成器,它是一款基于真实地理数据的专业

gitblog_00190的博客 410

解决MiGPT部署痛点:小米账号异地登录安全验证的解决方案

为让小米音箱更智能🤖,部署MiGPT时遇到小米账号异地登录验证问题,手动验证后仍无法解决。本文分享亲测有效的简化方案✨:通过浏览器F12获取passToken📝,手动创建mi.json配置文件并挂载到Docker容器,无需本地运行MiGPT,直接绕过异地验证,附完整操作步骤和问题排查指南。

XiaoqiangClub的博客 1454

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

j2me 3D开发-基本地形渲染技术

本章将讲述3D中常用的一些技术:包括HeightMap高度地图、粒子系统和碰撞检测技术。 HeightMap是地形的输入数据,可以理解为位图,一个2D矩阵,和位图不同的是,把元素的颜色值映射为高度值,建立HeightMap的方法有很多,这里使用灰度图来创建高度地图。 粒子系统在模仿自然现象、物理现象及空间扭曲上具备得天独厚的优势。每一种粒子系统都有一些相似的参数,但也都存在差异,如何优化它们

David.Wang 做你喜欢的事情 1562

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

上一篇: 矩阵计算——C++练习
下一篇: 文件排版(文本文件读写)
南懿烨曦
博客等级 码龄6年 108粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值