日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Processing 案例 | 扑面而来的满天繁星

發布時間:2024/1/8 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Processing 案例 | 扑面而来的满天繁星 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 引言
  • 效果展現
  • 原理分析
  • 代碼實現
    • 確定代碼執行流程
    • 星星繪制在屏幕上
    • 讓星星動起來
    • 點擊鼠標,星星的速度發生改變
    • 視角改變
  • 完整代碼
  • 結語

??

引言

清明時節雨紛紛,路上行人欲斷魂”,每到清明,你總能從那如絲如雨縷的春雨綿綿中感到心上繚繞的那點憂愁。

很少有這樣一個節日,像清明這樣的矛盾。當你放歌踏青時,它是一個輕盈的日子,是節氣;當你慎終追遠的時候,它是一個悲愴的日子,是節日。

在每一個清明冰涼的夜,你是否也曾仰望滿天的繁星,追憶那已故的人?他們就像那滿天的繁星,在你生命的漫漫長夜中匆匆劃過,照亮了一段時光。

現在就讓我們一起用 Processing 來模擬那片星域,讓記憶中的人和事翻上心頭,細細評味。

效果展現


??

原理分析

首先通過觀看視頻,我們可以發現在鼠標所在的點附近的星星是最小的,離該點越遠,星星的面積越大,移動的速度越快。就好像星星都從這個點里出來一樣,我們暫且把這個點叫做消失點。并且觀察可得,消失點把屏幕分成了四個區域A,B,C,D(如圖一所示),同時把星星也分成了四類。其中A中的星星向左上方移動,B中點向右上方移動,C中的點向左下方移動,D中的點向右下方移動。

接下來我們來看一下代碼實現的大概思路。

我們在腦海里假想一個長方體,以這個長方體的一個頂點為原點,建立世界坐標系。然后選取一個面作為Processing 程序的窗口,建立屏幕坐標系。然后在屏幕上任選一個點,作為消失點,該點在屏幕坐標系下的坐標為(x_endpoint,y_endpoint )。

接著在這個長方體里隨機生成一系列的星星,每個星星由一個三維向量(x_world,y_world,z_world)表示,這是它在世界坐標系下的坐標。

接下來我們要做的就是把每一個星星的在世界坐標系的坐標,轉換成在processing窗口里面的坐標(x_screen,y_screen),這樣我們就可以在屏幕上把星星繪制出來。

首先需要計算星星在世界坐標系下相對于消失點(endpoint)x,y方向的偏移量,接下來將這個偏移量根據星星的z_world進行放縮,最后再將放縮完成的偏移量加回消失點的坐標,得到星星在屏幕上的坐標。
公式如下:

x s c r e e n = ( x w o r l d ? x e n d p o i n t ) / z w o r l d ? s c a l e + x e n d p o i n t x_{screen}=(x_{world}-x_{endpoint})/z_{world} *scale+x_{endpoint} xscreen?=(xworld??xendpoint?)/zworld??scale+xendpoint?
y s c r e e n = ( y w o r l d ? y e n d p o i n t ) / z w o r l d ? s c a l e + y e n d p o i n t y_{screen}=(y_{world}-y_{endpoint})/z_{world} *scale+y_{endpoint} yscreen?=(yworld??yendpoint?)/zworld??scale+yendpoint?

其中scale是放縮比例,用來控制控制星域的范圍。

分析公式可以發現z_world越大對應的 x_screen、y_screen 越大,也就是說離消失點越遠。也就說我們只要將z_world 初始設為一個比較大的值,然后在不斷減小它,這樣就會出現星星離消失點越來越遠,離屏幕越來越近的效果。同時我們根據 z_world 的大小設置星星的直徑 diam 設置,z_world 越大,diam 越小,這樣就符合近大遠小的透視規律。
??

代碼實現

首先我們來確定代碼的結構,創建三個 Processing 文件,分別為 main.pde、StarField.pde、Star.pde。其中main.pde 里面是程序執行的主流程。StarField.pde 里面主要定義了 StarField類、Star.pde 主要定義了 Star 類。
?

確定代碼執行流程

在 main.pde 中輸入如下代碼:

/*這個是一個由星星構成的粒子系統 擁有星星的所有狀態和行為*/ StarField sf; void setup(){ size(400, 400); sf = new StarField(); } void draw(){ background(0); /*運行星域系統 更新星星的狀態和繪制星星*/ sf.run(); } /*鼠標按下時調用的函數 用來改變星域的速度*/ void mousePressed(){ } /*鼠標移動的時候調用的函數 用來改變視角*/ void mouseMoved(){ }

?

星星繪制在屏幕上


首先在StarField.pde中輸入如下代碼:

class StarField{ //常量聲明 //變量聲明 //構造函數 //成員函數 }

以上代碼我們確定了該類的四大組成部分,接下來我們在將構造函數替換為如下代碼:

StarField(){ /*將初始消失點設置在鼠標最開始的位置*/ endpoint = new PVector(mouseX, mouseY); /*初始化所有的星星*/ stars = new ArrayList(); for(int i = 0; i < STAR_COUNT; i++){ stars.add(new Star()); } }

接著在StarField類的成員函數中定義run函數:

void run(){ for(Star s : stars){ /*對星星進行坐標變換 獲得星星在屏幕坐標系的坐標 用于之后的星星的渲染*/ s.transform(endpoint); /*對屏幕外的星星進行裁剪 同時生成一個新的星星 使得星星可以源源不斷的出現*/ s.checkEdge(); /*依據屏幕坐標系渲染星星, 使得星星在屏幕上出現*/ s.display(); } }

接下來我們來定義出現在 StarField 的構造函數中和 run 函數中的變量和常量。

/*該粒子系統包含的星星的個數 星星越多畫面越密*/ final int STAR_COUNT = width / 2; /*數據類型為Star object的動態數組 存儲該星域中所有的星星*/ ArrayList<Star> stars; /*消失點 用來控制視角*/ PVector endpoint;

之后我們來定義Star對象,輸入如下代碼:

class Star{ //常量聲明 //變量聲明 //構造函數 //成員函數 }

將 Star 類的構造函數替換為:

Star(){ /*在一個長方體區域內隨機生成一個點 返回它在世界坐標系下的坐標*/ worldPosition = new PVector(random(0, width), random(0, height), random(0, MAX_DEPTH)); }

接下來在Star類成員函數部分加入 transfrom 函數,這個函數是本作品最關鍵的地方,希望大家能好好體會一下。

void transform(PVector endpoint){ /*將星星的坐標從世界世界坐標系變換到消失點坐標系 以下代碼等同于: viewPosition.x = (worldPosition.x - endpoint.x) / worldPosition.z * SCALE; viewPosition.y = (worldPosition.y - endpoint.y) / worldPosition.z * SCALE; */ viewPosition = PVector.sub(worldPosition, endpoint).div(worldPosition.z).mult(SCALE); /*將星星的坐標從消失點坐標系變換到屏幕坐標系 以下代碼等同與: screenPosition.x = endpoint.x + viewPosition.x; screenPosition.y = endpoint.y + viewPosition.y; */ screenPosition = PVector.add(endpoint, viewPosition); /*根據世界坐標z的大小來確定星星的直徑 z越小,說明越靠近屏幕,所以星星越大*/ diam = map(worldPosition.z, 0, MAX_DEPTH, MAX_DIAM, 0); }

??接著在Star類的成員函數部分加入checkEdge函數的定義

void checkEdge(){ if(screenPosition.x <= 0 || screenPosition.x >= width || screenPosition.y <=0 || screenPosition.y >= height){ /*如果這個點已經在屏幕外了,那么將其裁剪, 同時在相同的長方體區域隨機生成一個新的點*/ worldPosition.set(random(0, width), random(0, height), MAX_DEPTH); } }

然后繼續在Star類的成員函數部分Star類的display函數。

void display(){ /*在屏幕上繪制該星星 每一個星星是一個白色的、沒有邊的圓*/ fill(255); noStroke(); ellipse(screenPosition.x, screenPosition.y, diam, diam); }

在第二步的最后我們把Star類需要的一些成員變量和常量加上,把它們添加到Star類的常量和變量部分。

/*星星在屏幕坐標系直徑的最大值 用于控制星星在屏幕上的整體大小*/ final float MAX_DIAM = 16; /*星星里屏幕最遠的距離 用來控制星域的立體感*/ final float MAX_DEPTH = width / 2; /*進行坐標變換時候的 用來控制星星在屏幕上的分布范圍*/ final float SCALE = MAX_DEPTH; /*星星在三個坐標系下的坐標 記錄它們在不同參考系下的位置*/ PVector worldPosition, screenPosition, viewPosition; /*星星在屏幕坐標系下的直徑 確定星星在屏幕上的大小*/ float diam;

?

讓星星動起來


首先我們在 StarField 的 run 方法中,給每一個星星添加如下的行為:

/*更新在世界坐標系的坐標 讓星星飛向觀察者*/ s.move(speed);

接著在StarField的構造方法中初始化 speed 這個值。

/*初始化星星的移動速度 讓移動速度不用太快和太慢*/ speed = (MAX_SPEED + MIN_SPEED) / 2;

然后在 StarField 的變量和常量部分,定義新增加和星星速度有關的常量和變量。

/*分別代表星星移動的最大速度,最小速度, 用來控制星星移動速度的范圍*/ final int MAX_SPEED = 11, MIN_SPEED = 1; /*速度改變的步長 每一次增加或者減小速度的時速度改變的最小值*/ final int SPEED_STEP = 1; /*星星移動的速度 控制星星移動快慢*/ int speed;

這之后我們在 Star 的成員函數部分加入如下代碼,然后第三階段就到此結束。

void move(float speed){ worldPosition.z -= speed; /*限制星星世界坐標系的位置 防止出現星星移動到屏幕外的情況*/ worldPosition.z = constrain(worldPosition.z, 0, MAX_DEPTH); }

?

點擊鼠標,星星的速度發生改變



直接在 main.pde 的 mousePressed 中加入如下代碼:

if(mouseButton == LEFT){ /*如果是鼠標左鍵按下了 提高星域的速度*/ sf.speedUP(); }else if(mouseButton == RIGHT){ /*如果是鼠標右鍵按下了 降低星域的速度*/ sf.speedDown(); }

然后在 StarField 的成員函數中定義 speedUP 和 speedDown 函數:

void speedUP(){ speed += SPEED_STEP; /*限制speed在最大和最小值之間 防止速度太快*/ speed = constrain(speed, MIN_SPEED, MAX_SPEED); } void speedDown(){ speed -= SPEED_STEP; /*限制speed在最大和最小值之間 防止速度小于零*/ speed = constrain(speed, MIN_SPEED, MAX_SPEED); }

&enmsp;

視角改變


首先在 mouseMoved 函數里面加入如下代碼:

/*根據鼠標的位置來更新消失點的位置 達到改變視角的目的*/ sf.updateEndpoint(mouseX, mouseY); 然后再StarField的成員函數部分對上面調用的updateEndpoint函數進行定義:void updateEndpoint(float x, float y){ endpoint.x = x; endpoint.y = y; }

到了現在我們就完成了代碼的所有編寫。
??

完整代碼

我的github
我的openprocessing
?

結語

我們有很多可以擴展的地方,比如改變 Star 類里的 MAX_DEPTH 來改變星域的立體感,改變 StarField 類的 STAR_COUNT,Star 類 SCALE 的來改變星域的密度和范圍。

目前為止對于每一星星我們只是簡單的畫了一個白色的小圓,其實這里有很大的發揮空間。比如用 Noise 函數根據星星在屏幕坐標系的位置計算星星的顏色,或者用你思念的人的名字或者其中的字母來替代圓圈,創造出那一片獨一無二,只屬于你的燦爛的星域!

最后,祝大家清明節快樂!

總結

以上是生活随笔為你收集整理的Processing 案例 | 扑面而来的满天繁星的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久精品国产sm调教 | 欧美大片免费在线观看 | 中文在线a天堂 | 亚洲成人午夜在线 | 日人视频 | 亚洲国产电影在线观看 | 亚洲高潮无码久久 | 国产精品一区二区免费视频 | 无码人妻丰满熟妇区毛片18 | 放荡的美妇在线播放 | 搞中出| 久久精品国产亚洲AV黑人 | 免费成人激情视频 | 理论片91 | 国产精品一区二区三区免费看 | 日韩视频在线观看一区二区三区 | 国产主播专区 | 葵司av在线 | 大肉大捧一进一出好爽视频 | 久久a毛片| 韩国三级在线播放 | 欧美大片大全 | 亚洲一区二区在线 | 男女插插插视频 | 在线观看福利网站 | 日韩一级片在线 | 欧美人与野 | 成人av资源站 | 中文字幕第22页 | 欧美成人aaa | 波多野42部无码喷潮在线 | 国产特黄级aaaaa片免 | 久久久天堂 | 男女黄色片 | 91成人黄色| 激情偷乱人成视频在线观看 | 国产成人精品一区二区三区免费 | 色婷婷av一区二区三区大白胸 | 国产特黄毛片 | 久久精品三级视频 | 国产盗摄精品一区二区酒店 | 欧美熟妇另类久久久久久不卡 | 99精品视频一区二区 | 亚洲顶级毛片 | 色偷偷噜噜噜亚洲男人 | 五月av| 国产精品国产三级国产播12软件 | 亚洲图片小说区 | 特黄特色大片免费播放器使用方法 | 久久精品91 | av大西瓜| 精品aaa | 亚洲丝袜在线观看 | 日韩免费播放 | 国产精品99久久久久久久久 | 暗呦丨小u女国产精品 | 97日日夜夜 | 亚洲色图25p | 日韩簧片 | 天堂а在线中文在线新版 | 琪琪色在线视频 | 亚洲成人网在线观看 | 亚洲熟妇无码乱子av电影 | 国外av网站 | 中文字幕网站在线观看 | 天天干视频在线观看 | 国产乱码精品一区二区三 | 黄色av网站在线 | 国产小视频在线免费观看 | 日韩av一区二区在线播放 | 欧美丰满老熟妇aaaa片 | 精品成人免费一区二区在线播放 | 精品小视频在线观看 | 波多野久久 | 毛片网站免费在线观看 | 性av在线 | 一亲二脱三插 | 波多野结衣一本一道 | 白浆网站 | 亚洲男人天堂2022 | 久久久久久国产精品一区 | 欧美成人久久久免费播放 | 日本a√在线观看 | 日韩二区三区 | 免费欧美黄色 | 麻豆久久精品 | 国产精品老熟女一区二区 | 亚洲精品一区二三区不卡 | 天天天天干 | 性综艺节目av在线播放 | 性欢交69国产精品 | 极品白嫩丰满少妇无套 | 亚洲av无码片一区二区三区 | 99热在线看 | 香蕉二区 | av在线观| 久久久久国产精品人妻 | 欧美日a| 精品视频国产 |