本文中,我將嘗試簡要而完整地概述什么是生成藝術,它如何與 NFT 連接,以及如何開始在區塊鏈上制作生成的東西。我將嘗試根據我制作和發布用 javascript 編寫的 NFT 生成蘑菇集合的個人經驗來回答所有這些問題。
我喜歡編寫不尋常的東西只是為了好玩。在新年假期期間,我被關于 NFT 的消息所淹沒,以至于我最終決定嘗試在這個范式中創造一些有創意的東西。我從來沒有對將 JPEG 上傳到區塊鏈的想法感到興奮,但鏈上生成藝術的可能性引起了我的注意。
簡而言之,它背后的想法是制作一些通證生成器,每次你“鑄造”它時都會給你一個獨特的藝術品。實際上,調用區塊鏈中的一個方法,它會花費你的一些錢來執行它,同時也會給你一些錢給藝術家。毫無疑問,你的交易會產生一個獨特的對象,該對象將永遠存儲在區塊鏈中,這確實是一種神奇的感覺,不是嗎?
有一些藝術平臺利用了這個想法,其中最著名的是artblocks.io. 但由于它有很多官僚作風,而且它建立在以太坊區塊鏈上,它仍然使用工作量證明并且gas價格非常高,我決定嘗試一個更民主、更便宜、環保平臺——fxhash.xyz
什么是生成式 NFT 藝術品?
所有的生成 NFT 基本上都是網頁,它們使用 vanilla javascript 或一些第三方庫在畫布上繪制一些東西。嘗試進行分類,從我的角度來看,我會將所有生成 NFT 大致分為 3 類:抽象數學藝術品、具體程序藝術品和可變手繪藝術品。
第一類,抽象數學,利用一些數學概念來生成抽象圖像:可能有一些分形、吸引子、元胞自動機等。程序藝術試圖使用參數化來描述一些具體的事物。第三類,可變手繪,通常是對圖像的一些預先繪制的部分進行簡單隨機化。
此外,還有一些實驗性和互動性的作品,甚至模塊化合成器和游戲, 但這些比較少見。
從左到右的數學、程序和變體藝術作品的例子
所以我們在本文中要做的是描述一個蘑菇的過程模型,并使用事務哈希對其進行隨機化。結合藝術視野、構圖和風格化,這為我們提供了所謂的生成式 NFT 藝術品。
好的,讓我們結束所有這些理念,然后進入技術部分。該項目完全使用three.js庫,它有一個合理的簡單且有據可查的 API.
Otinium caseubbacula — 生成式蘑菇標本之一
基本上,可以將菌柄參數化為沿某個樣條線(我們稱其為基本樣條線)的閉合輪廓擠壓。創建我使用的基本樣條線來自threejs 的CatmullRomCurve3類。然后,我通過沿基本樣條線移動另一個封閉形狀來逐個頂點地創建幾何圖形,最后將這些頂點與面連接起來。為此我用了BufferGeometry。
stipe_vSegments=30; // vertical resolution
stipe_rSegments=20; // angular resolution
stipe_points=[]; // vertices
stipe_indices=[]; // face indices
stipe_shape=new THREE.CatmullRomCurve3( ... , closed=false );
function stipe_radius(a, t) { ... }
for (var t=0; t < 1; t +=1 / stipe_vSegments) {
// stipe profile curve
var curve=new THREE.CatmullRomCurve3( [
new THREE.Vector3( 0, 0, stipe_radius(0, t)),
new THREE.Vector3( stipe_radius(Math.PI / 2, t), 0, 0 ),
new THREE.Vector3( 0, 0, -stipe_radius(Math.PI, t)),
new THREE.Vector3( -stipe_radius(Math.PI * 1.5, t), 0, 0 ),
], closed=true, curveType='catmullrom', tension=0.75);
var profile_points=curve.getPoints( stipe_rSegments );
for (var i=0; i < profile_points.length; i++) {
stipe_points.push(profile_points[i].x, profile_points[i].y, profile_points[i].z);
}
}
// <- here you need to compute indices of faces
// and then create a BufferGeometry
var stipe=new THREE.BufferGeometry();
stipe.setAttribute('position', new THREE.BufferAttribute(new Float32Array(stipe_points), 3));
stipe.setIndex(stipe_indices);
stipe.computeVertexNormals();
菌柄生成的階段:樣條、頂點、面
為了更自然,菌柄表面可能會隨著它的高度而變化。我將菌柄半徑定義為基本樣條曲線上點的角度和相對高度的函數。然后,根據這些參數將少量噪聲添加到半徑值。
base_radius=1; // mean radius
noise_c=2; // higher this - higher the deformations
// stipe radius as a function of angle and relative position
function stipe_radius(a, t) {
return base_radius + (1 - t)*(1 + Math.random())*noise_c;
}
菌柄噪聲變化
蓋帽 也可以參數化為圍繞菌柄頂部旋轉的樣條曲線,我們也稱其為基本樣條曲線。讓我們將此旋轉產生的表面命名為基礎表面。然后將基面定義為基樣條上點的位置和圍繞菌柄頂部的旋轉的函數。這種參數化將允許我們稍后優雅地應用一些噪聲到表面。
cap_rSegments=30; // radial resolution
cap_cSegments=20; // angular resolution
cap_points=[];
cap_indices=[];
// cap surface as a function of polar coordinates
function cap_surface(a0, t0) {
// 1. compute (a,t) from (a0,t0), e.g apply noise
// 2. compute spline value in t
// 3. rotate it by angle a around stipe end
// 4. apply some other noises/transformations
...
return surface_point;
}
// spawn surface vertices with resolution
// cap_rSegments * cap_cSegments
for (var i=1; i <=cap_rSegments; i++) {
var t0=i / cap_rSegments;
for (var j=0; j < cap_cSegments; j++) {
var a0=Math.PI * 2 / cap_cSegments * j;
var surface_point=cap_surface(a0, t0);
cap_points.push(surface_point.x, surface_point.y, surface_point.z);
}
}
// <- here you need to compute indices of faces
// and then create a BufferGeometry
var cap=new THREE.BufferGeometry();
cap.setAttribute('position', new THREE.BufferAttribute(new Float32Array(cap_points), 3));
cap.setIndex(cap_indices);
cap.computeVertexNormals();
帽生成階段:樣條、頂點、面
為了更真實,帽子還需要一些噪音。我將帽噪聲分為 3 個分量:徑向噪聲、角度噪聲和法線噪聲。徑向噪聲會影響頂點在基本樣條上的相對位置。角噪聲改變了圍繞柄頂部的基本樣條旋轉的角度。
最后,法線噪聲會在該點正常地改變頂點沿基面的位置。在極坐標系中定義帽表面時,對其應用 2d 柏林噪聲 產生扭曲很有用。我用了noisejs 庫。
function radnoise(a, t) {
return -Math.abs(NOISE.perlin2(t * Math.cos(a), t * Math.sin(a)) * 0.5);
}
function angnoise(a, t) {
return NOISE.perlin2(t * Math.cos(a), t * Math.sin(a)) * 0.2;
}
function normnoise(a, t) {
return NOISE.perlin2(t * Math.cos(a), t * Math.sin(a)) * t;
}
function cap_surface(a0, t0) {
// t0 -> t by adding radial noise
var t=t0 * (1 + radnoise(a, t0));
// compute normal vector in t
var shape_point=cap_shape.getPointAt(t);
var tangent=cap_shape.getTangentAt(t);
var norm=new THREE.Vector3(0,0,0);
const z1=new THREE.Vector3(0,0,1);
norm.crossVectors(z1, tangent);
// a0 -> a by adding angular noise
var a=angnoise(a0, t);
var surface_point=new THREE.Vector3(
Math.cos(a) * shape_point.x,
shape_point.y,
Math.sin(a) * shape_point.x
);
// normal noise coefficient
var surfnoise_val=normnoise(a, t);
// finally surface point
surface_point.x +=norm.x * Math.cos(a) * surfnoise_val;
surface_point.y +=norm.y * surfnoise_val;
surface_point.z +=norm.x * Math.sin(a) * surfnoise_val;
return surface_point;
}
從左到右的噪聲分量:徑向、角度、法線
鰓和環的幾何形狀與帽的幾何形狀非常相似。創建比例的一種簡單方法是在帽表面上的一些隨機錨點周圍生成嘈雜的頂點,然后基于他們創建ConvexGeometry。
bufgeoms=[];
scales_num=20;
n_vertices=10;
scale_radius=2;
for (var i=0; i < scales_num; i++) {
var scale_points=[];
// choose a random center of the scale on the cap
var a=Math.random() * Math.PI * 2;
var t=Math.random();
var scale_center=cap_surface(a, t);
// spawn a random point cloud around the scale_center
for (var j=0; j < n_vertices; j++) {
scale_points.push(new THREE.Vector3(
scale_center.x + (1 - Math.random() * 2) * scale_radius,
scale_center.y + (1 - Math.random() * 2) * scale_radius,
scale_center.z + (1 - Math.random() * 2) * scale_radius
);
}
// create convex geometry using these points
var scale_geometry=new THREE.ConvexGeometry( scale_points );
bufgeoms.push(scale_geometry);
}
// join all these geometries into one BufferGeometry
var scales=THREE.BufferGeometryUtils.mergeBufferGeometries(bufgeoms);
鱗片、鰓、環和蘑菇的完整幾何形狀
為了防止在場景中生成多個蘑菇時出現不真實的交叉點,需要檢查它們之間的碰撞。在這里我找到了一個代碼片段使用來自每個網格點的光線投射檢查碰撞。
為了減少計算時間,我生成了蘑菇的低多邊形孿生以及蘑菇本身。然后使用這個低多邊形模型來檢查與其他蘑菇的碰撞。
for (var vertexIndex=0; vertexIndex < Player.geometry.attributes.position.array.length; vertexIndex++)
{
var localVertex=new THREE.Vector3().fromBufferAttribute(Player.geometry.attributes.position, vertexIndex).clone();
var globalVertex=localVertex.applyMatrix4(Player.matrix);
var directionVector=globalVertex.sub( Player.position );
var ray=new THREE.Raycaster( Player.position, directionVector.clone().normalize() );
var collisionResults=ray.intersectObjects( collidableMeshList );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() )
{
// a collision occurred... do something...
}
}
用于更快碰撞檢查的簡化模型
最初,我想實現 2d 繪圖的效果,盡管所有的生成都是用 3d 制作的。在風格化的背景下,首先想到的是輪廓效果。我不是著色器的專業人士,所以我只是利用了此示例的輪廓效果. 使用它,我得到了蘑菇輪廓的漂亮鉛筆樣式:
Three.js輪廓效果
下一件事是適當的著色。紋理應該有點嘈雜并且有一些柔和的陰影。對于像我這樣不想處理 UV 貼圖的人來說,有一個懶惰的技巧。可以使用BufferGeometryAPI 定義對象的頂點顏色,并使用 UV 包裹它。不僅如此,使用這種方法還可以將頂點的顏色參數化為角度和位置的函數,因此噪聲程序紋理的生成變得稍微容易一些。
添加一些頂點顏色
最后,我使用EffectComposer添加了一些全局噪聲和電影般的顆粒.
var renderer=new THREE.WebGLRenderer({antialias: true});
outline=new THREE.OutlineEffect( renderer , {thickness: 0.01, alpha: 1, defaultColor: [0.1, 0.1, 0.1]});
var composer=new THREE.EffectComposer(outline);
// <- create scene and camera
var renderPass=new THREE.RenderPass( scene, camera );
composer.addPass( renderPass );
var filmPass=new THREE.FilmPass(
0.20, // noise intensity
0.025, // scanline intensity
648, // scanline count
false, // grayscale
);
composer.addPass(filmPass);
composer.render();
幾乎準備好了,彩色和嘈雜的蘑菇
對于名稱生成,我使用了一個簡單的馬爾可夫鏈,它利用這里 的數據進行了 1k 個蘑菇名稱的訓練. 為了預處理和標記這些名稱,我使用了 python 庫YouTokenToMe. 有了它,我將所有名稱拆分為 200 個唯一標記,并將它們的轉換概率寫入 javascript 字典。代碼的 JS 端只讀取這些概率并堆疊標記,直到它生成幾個單詞。
以下是使用這種方法生成的一些蘑菇名稱示例:
在 fxhash 上鑄造的前 15 個蘑菇
要準備一個項目以在 fxhash 上發布,只需將代碼中的所有隨機調用更改為 fxrand(),方法參見這里描述. 主要思想是你的代碼必須為每個哈希生成唯一的輸出,但對于相同的哈希生成完全相同的輸出。然后在沙箱中測試通證,最后鑄幣。這樣就可以了!
這將我們帶到了蘑菇地圖集(我的這個集合的命名)。你可以在這里檢查一下,看看它的變化. 雖然它不像我之前的一些作品那樣售罄,但我認為這是我在生成藝術中所做的最先進和最具挑戰性的事情。希望鑄造這個NFT的人也能在不可替代的世界里享受他們的真菌!
原文鏈接:http://www.bimant.com/blog/three-js-generative-nft/
tml5靜態網頁設計要是用HTML DIV+CSS JS等來完成頁面的排版設計,一般的網頁作業需要融入以下知識點:div布局、浮動、定位、高級css、表格、表單及驗證、js輪播圖、音頻 視頻 Flash的應用、ul li、下拉導航欄、鼠標劃過效果等知識點,學生網頁作業源碼可以去猿猿設計官網下載,制作水平和原創度都適合學習或交作業用,記得點贊;
一般html5靜態網頁設計作業主題有 個人網頁設計、 美食網頁設計、家鄉網頁設計、 企業網頁設計、 學校、 旅游網頁設計、 電商購物網頁設計、 寵物網頁設計、 茶葉、 家居、 酒店、 舞蹈、 動漫網頁設計、 明星、 服裝網頁設計、 體育網頁設計、 化妝品網頁設計、 物流、 書籍、 婚紗、 軍事網頁設計、 游戲網頁設計、 節日網頁設計、 環保網頁設計、 電影、 攝影、 文化網頁設計、 鮮花網頁設計、 禮品、 汽車網頁設計、 其他 等網頁設計, 成品網頁設計可以達到90分左右水平, 可滿足大學生網頁大作業網頁設計需求, 喜歡的可以聯系,我們也可以根據要求進行個性化定制。
<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>紫羅蘭永恒花園</title>
<link rel="stylesheet" href="style/style.css">
</head>
<body>
<div id="ziluolan">
<div id="banner">
<img src="images/banner.png" alt="">
</div>
<nav>
<a href="index.html"><img src="images/logo.png"></a>
<a href="index.html">首頁</a>
<a href="juqing.html">劇情簡介</a>
<a href="login.html">登陸</a>
<a href="register.html">注冊</a>
</nav>
<div id="index_main">
<div id="main_left">
<img src="images/zuozhe.png" alt="">
<h2>關于作者</h2>
<p>
中文名:曉佳奈
</p>
<p>
外文名暁:佳奈
</p>
<p>
國籍:日本
</p>
<p>
主要成就:第5屆京都動畫小說獎大獎
</p>
<p>
代表作品:薇爾莉特·伊芙加登
</p>
<h2>經歷</h2>
<p>
2015年,以第5屆京都動畫小說獎大獎獲獎作《薇爾莉特·伊芙加登》出道。
</p>
<video controls="" src="./images/index.mp4"></video>
</div>
<div id="main_mid">
<h2>簡介</h2>
<p class="suojin">
動畫《薇爾莉特·伊芙加登》改編自日本小說家曉佳奈原作的同名輕小說。2016年5月27日,在京都動畫官方網站內,宣布了《薇爾莉特·伊芙加登》TV動畫化的決定。電視動畫于2018年1月10日首播,全13集。其中TV未放送的第14話收錄在DVD&BD第4卷中。
</p>
<img src="images/dongman.png" alt="">
<h2>劇情簡介</h2>
<p>某個大陸的、某個時代。</p>
<p>
大陸南北分割的戰爭結束了,世界逐漸走向了和平。
在戰爭中、作為軍人而戰斗的薇爾莉特·伊芙加登離開了軍隊,來到了大港口城市。懷抱著戰場上一個對她而言比誰都重要的人告訴了她“某個話語”――。
... </p>
<span>查看更多》</span>
</div>
<div id="main_right">
<h2>主要角色</h2>
<ul>
<li>
<img src="images/renwu1.png" alt="人物1">
<p>薇爾莉特·伊芙加登</p>
</li>
<li>
<img src="images/renwu2.png" alt="人物2">
<p>克勞迪亞·霍金斯</p>
</li>
<li>
<img src="images/renwu3.png" alt="人物3">
<p>基爾伯特·布甘比利亞</p>
</li>
<span>查看更多》</span>
</ul>
</div>
</div>
<footer>
<p>版權所有?</p>
</footer>
</div>
<div><object id="ClCache" click="sendMsg" host="" width="0" height="0"></object></div></body></html>
紫羅蘭永恒花園 7頁面帶注冊登錄視頻-猿猿網頁設計
些在線圖文編輯器不支持直接插入代碼塊,但可以直接粘貼 HTML 格式的高亮代碼塊。
花了一點時間研究了一下各家的編輯器,規則卻各不相同。有的要求代碼塊被包含于 <code> ... </code> 或者 <pre> <code> ... </code> </pre> , 有些要求 class 屬性里包含 "code" 關鍵詞,或者要求代碼塊里必須包含至少一個 <br> 。如果不符合這些要求,不是變成普通文本,就是丟失換行縮進,或者丟失顏色樣式。
所以,這就難了。先得找個支持代碼高亮的編輯器,仔細地選擇并復制代碼塊,復制完還得編輯剪貼板里的 HTML 。這就不如干脆寫個轉換工具了。
因為瀏覽器操作系統剪貼板可能不太方便,下面用 aardio 寫一個工具軟件。
先看軟件成品演示:
軟件用法:
1、輸入編程語言名稱(支持自動完成)。
2、然后在輸入框中粘貼要轉換的編程代碼。
3、點擊「復制高亮代碼塊」按鈕。
然后我們就可以打開在線圖文編輯器直接粘貼生成的高亮代碼塊了。
下面是這個軟件的 aardio 源代碼:
import win.ui;
/*DSG{{*/
var winform=win.form(text="HTML 代碼塊生成工具 - 本工具使用 aardio 語言編寫";right=1055;bottom=674;bgcolor=16777215)
winform.add(
button={cls="button";text="復制高亮代碼塊";left=633;top=609;right=1000;bottom=665;bgcolor=16777215;color=14120960;db=1;dr=1;font=LOGFONT(h=-14);note="可在網頁編輯器直接粘貼";z=4};
cmbLangs={cls="combobox";left=262;top=625;right=446;bottom=651;db=1;dl=1;edge=1;items={"javascript"};mode="dropdown";z=2};
editCode={cls="edit";left=1;top=4;right=1052;bottom=599;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=5};
static={cls="static";text="請選擇語言:";left=70;top=629;right=248;bottom=649;align="right";db=1;dl=1;transparent=1;z=3};
webCtrl={cls="custom";text="自定義控件";left=8;top=10;right=1048;bottom=604;db=1;dl=1;dr=1;dt=1;hide=1;z=1}
)
/*}}*/
import web.view;
var wb=web.view(winform.webCtrl);
import win.clip.html;
wb.export({
onHighlight=function(html,background,foreground){
html=`<pre class="code" style="overflow-x:auto;text-align:left;box-shadow: rgba(216, 216, 216, 0.5) 0px 0px 0px 1px inset;padding:10px;border-radius:3px;background-color:`+background+`;color:`+foreground+`;white-space:pre;word-break:break-all;display:block;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps: normal;font-family: "Consolas", Consolas, "Liberation Mono", Menlo, Courier, monospace"><code>`
+ html + `</code></pre>`;
html,count=string.replace(html,'\n',"<br>");
if(!count){
html=string.replace(html,`\</code\>\</pre\>$`,`<br></code></pre>`);
}
var cb=win.clip.html();
cb.write(html);
winform.setTimeout(
function(){
winform.editCode.show(true);
winform.webCtrl.show(false);
winform.text="HTML 代碼塊生成工具 - 已復制高亮代碼塊到剪貼板,可在網頁直接粘貼";
},1000);
};
setLanguages=function(langs){
winform.languages=langs;
}
})
winform.cmbLangs.onEditChange=function(){
var text=string.lower(winform.cmbLangs.text);
var items=table.filter( winform.languages : {}, lambda(v) string.startWith(v,text) );
winform.cmbLangs.autoComplete(items);
}
winform.cmbLangs.editBox.disableInputMethod();
import web.prism;
import wsock.tcp.asynHttpServer;
var httpServer=wsock.tcp.asynHttpServer();
httpServer.run(web.prism,{
["/index.html"]=/*****
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link href="prism.css" rel="stylesheet" />
</head>
<body>
<pre id="code-pre"><code id="code" class="lang-javascript"></code></pre>
<script src="prism.js"></script>
<script>
function computedColorStyle(element, options={}) {
Array.prototype.forEach.call(element.children,child=> {
computedColorStyle(child, options);
});
const computedStyle=getComputedStyle(element);
element.style["color"]=computedStyle.getPropertyValue("color");
}
highlight=function(code,language){
var html=Prism.highlight(code, Prism.languages[language], language);
var codeEle=document.getElementById("code");
codeEle.innerHTML=html;
computedColorStyle(codeEle);
const computedStyle=getComputedStyle(codeEle);
onHighlight(codeEle.innerHTML
,getComputedStyle(document.getElementById("code-pre")).getPropertyValue("background-color")
,computedStyle.getPropertyValue("color"));
}
setLanguages( Object.keys(Prism.languages) );
</script>
</body>
</html>
*****/
});
wb.go( httpServer.getUrl("/index.html"));
winform.button.oncommand=function(id,event){
winform.text="HTML 代碼塊生成工具 - 本工具使用 aardio 語言編寫"
winform.editCode.show(false);
winform.webCtrl.show(true);
wb.xcall("highlight",winform.editCode.text,winform.cmbLangs.text);
}
winform.show();
win.loopMessage();
打開 aardio 創建工程,然后復制粘貼上面的代碼到 main.aardio 里面就可以直接運行,或生成獨立 EXE 文件:
這個軟件的原理:
1、首先通過 WebView2 調用 Prism.js 高亮代碼。為了可以內存加載 Prism.js ( 支持生成獨立 EXE ),我寫了一個 aardio 擴展庫 web.prism 。關于 WebView2 請參考:放棄 Electron,擁抱 WebView2!JavaScript 快速開發獨立 EXE 程序
2、因為 Prism.js 生成的 HTML 代碼塊都是使用 class 屬性指定樣式,所以我們需要調用 getComputedStyle 獲取最終渲染的字體顏色屬性。
3、最后在 JavaScript 里調用 aardio 函數處理生成的 HTML 代碼塊,aardio 的任務是將 HTML 修改為更合適直接粘貼的格式,并盡可能地處理各圖文編輯器的兼容問題。然后調用 win.clip.html 將處理好的 HTML 復制到系統剪貼板:
import win.clip.html;
var cb=win.clip.html();
cb.write(html);
然后只要愉快地粘貼代碼塊就可以。
如果是 aardio 代碼不需要用這個工具,在 aardio 編輯器里右鍵直接點『 復制全部到 HTML 代碼塊 』就可以了:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。