แสดง Shaders Fragment GLSL เป็นพื้นหลังของเว็บไซต์ รองรับ Shadertoy Shaders, Multipass-Ping-Pong Offscreen Buffers, ลูปตอบรับ, พื้นผิวจุดลอยตัว ไม่ว่าจะด้วย WebGL 1 หรือ 2 จะพยายามทำงานทุกที่ที่เป็นไปได้ทางเทคนิค
เว็บไซต์/การสาธิต: ? https://xemantic.github.io/shader-web-background?
??? หากต้องการถามคำถามไปที่ Xemantic Discord Server ☕ ???
ฉันออกแบบห้องสมุดนี้เพื่อใช้เศษชิ้นส่วนที่ซับซ้อนเป็นส่วนหนึ่งของกระบวนการออกแบบเว็บและการพัฒนาของฉัน นี่คือเครื่องมือที่ในที่สุดก็ช่วยให้ฉันยอมรับเว็บเบราว์เซอร์เป็นสภาพแวดล้อมการเข้ารหัสที่สร้างสรรค์ หากคุณคุ้นเคยกับ GLSL ก็อาจช่วยให้คุณเผยแพร่ผลงานของคุณบนเว็บได้เช่นกัน หากคุณมาจากพื้นหลังการพัฒนาเว็บคุณอาจต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Shaders ก่อนเช่นจาก Book of Shaders ฉันหวังว่าตัวอย่างที่นำเสนอในเอกสารนี้เป็นการอธิบายตนเอง หากคุณพบว่ามีประโยชน์แล้ว
❤ผู้สนับสนุน XEMantic บน gitHub หรือ https://www.buymeacoffee.com/kazik
Kazik (Morisil) Pogoda
https://xemantic.com/
สารบัญ
texture ?tl; dr:
<!DOCTYPE html >
< html lang =" en " >
< head >
< meta charset =" utf-8 " >
< title > Minimal shader </ title >
< meta name =" viewport " content =" width=device-width, initial-scale=1 " >
< meta http-equiv =" X-UA-Compatible " content =" IE=edge " >
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script >
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
uniform float iTime ;
void main ( ) {
gl_FragColor = vec4 (
mod ( gl_FragCoord . x / 256. , 1. ) ,
mod ( ( gl_FragCoord . x + gl_FragCoord . y - iTime * 40. ) / 256. , 1. ) ,
mod ( gl_FragCoord . y / 256. , 1. ) ,
1.
) ;
}
</ script >
< script >
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ;
</ script >
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style >
</ head >
< body >
< h1 > shader-web-background minimal example </ h1 >
</ body >
</ html >หากคุณต้องการเรียนรู้จากตัวอย่างนี่คือรายการการสาธิตที่แสดงด้วยซอร์สโค้ดไฮไลต์ของพวกเขา:
https://xemantic.github.io/shader-web-background/#demo
มีหลายวิธีในการปรับห้องสมุดนี้ตามความต้องการของคุณ:
หากคุณต้องการให้ Shaders ของคุณเริ่มการเรนเดอร์ก่อนที่จะโหลดทรัพยากรอื่น ๆ ให้ไปหาวิธีนี้ เพียงแค่ใช้เนื้อหาของ:
https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js
และใส่เป็น <script> ใน <head> ของไฟล์ HTML ของคุณ
ดูตัวอย่างน้อยที่สุดสำหรับการอ้างอิง (เวอร์ชันสด)
เพิ่มรหัสนี้ลงใน <head> ของ HTML ของคุณ:
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script > ในอนาคตฉันจะเผยแพร่ shader-web-background ไปยัง NPM สำหรับตอนนี้คุณสามารถดาวน์โหลดการแจกจ่ายขนาดเล็กล่าสุดพร้อมกับแผนที่แหล่งที่มาและแหล่งที่มา
คุณจะต้องมี shader อย่างน้อยหนึ่งชิ้นที่กำหนดเช่นนี้:
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
void main ( ) {
// ...
}
</ script > ใส่ไว้ใน <head> ของ HTML ของคุณ type ควรเป็น x-shader/x-fragment และแอตทริบิวต์ id นั้นเป็นไปตามอำเภอใจ
id ที่ไม่ซ้ำกันกับแต่ละเฉดของคุณหากคุณกำหนดให้มากขึ้น
< script >
shaderWebBackground.shade( {
shaders : {
image : { }
}
} );
</ script >image ชื่อ Shader ควรตรงกับแอตทริบิวต์ ID Source Source id
ขั้นตอนนี้ไม่จำเป็น แต่การเพิ่มมันจะปรับปรุงประสบการณ์สำหรับผู้ใช้จำนวนเล็กน้อยที่ยังไม่สามารถเรียกใช้ shaders บนอุปกรณ์ของพวกเขาได้
กำหนดสไตล์ CSS ทางเลือกเช่นภาพหน้าจอคงที่ของเฟรม Shader ของคุณ:
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style > คลาส CSS ของ shader-web-background-fallback ถูกนำไปใช้กับรูทเอกสาร HTML และผืนผ้าใบ
shader-web-background-fallback แต่มันอาจไม่ทำงานกับเบราว์เซอร์บางตัว ตัวจัดการข้อผิดพลาดที่กำหนดเองอาจจำเป็นสำหรับความเข้ากันได้ข้าม
ดูส่วนข้อผิดพลาดในการจัดการสำหรับรายละเอียด
ดู API ของ Shader-Web-Background เต็มรูปแบบ
วัตถุการกำหนดค่าที่ส่งผ่านไปยังการเรียก shaderwebbackground.shade (config) ในตัวอย่างด้านบนจะส่งผลให้ไปป์ไลน์การเรนเดอร์น้อยที่สุดซึ่งประกอบด้วย image ชิ้นส่วนหนึ่งชื่อ องค์ประกอบคงที่ <canvas id="shader-web-background"> องค์ประกอบที่ครอบคลุมวิวพอร์ตทั้งหมดจะถูกเพิ่มลงในหน้าด้วย z-index: -9999 เพื่อแสดงหลังองค์ประกอบหน้าอื่น ๆ
หมายเหตุ: องค์ประกอบ <canvas> เริ่มต้นจะถูกแนบกับเอกสาร <body> เฉพาะเมื่อต้นไม้ DOM ทั้งหมดถูกสร้างขึ้น นอกจากนี้การเรนเดอร์เฟรม shader ที่แท้จริงจะไม่เกิดขึ้นจนกว่าหน้าจะโหลดเต็มแม้ว่าจะมีการรวบรวม shaders ทันที
เครื่องแบบให้ข้อมูลจากโลกนอก GPU การอธิบายกลไกนี้อยู่นอกขอบเขตของเอกสารนี้ ฉันตัดสินใจที่จะไม่สร้างสิ่งที่เป็นนามธรรมเหนือส่วนนี้ของ WebGL เพราะมันค่อนข้างรัดกุมอยู่แล้ว ดูเอกสารประกอบ WebGlrenderingContext.uniform
สมมติว่าคุณต้องการให้ค่าเวลาที่วัดได้ในไม่กี่วินาทีนับตั้งแต่ช่วงเวลาที่หน้าถูกโหลด ก่อนกำหนดเครื่องแบบใน image Shader:
uniform float iTime; ชื่อ iTime นั้นเป็นไปโดยพลการ แต่ควรตรงกับสิ่งที่คุณระบุในการกำหนดค่า:
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ; (gl, loc) => gl.uniform1f(loc, performance.now() / 1000) ฟังก์ชั่นจะถูกเรียกใช้ก่อนที่จะแสดงผลแต่ละเฟรม shader หากคุณไม่คุ้นเคยกับฟังก์ชั่นลูกศร JavaScript มันจะเทียบเท่ากับ:
function ( gl , loc ) {
gl . uniform1f ( loc , performance . now ( ) / 1000 )
} ตรวจสอบเอกสารของฟังก์ชั่นประสิทธิภาพ JavaScript มาตรฐานตอนนี้ () ซึ่งส่งคืนจำนวนมิลลิวินาทีนับตั้งแต่โหลดหน้า การหารด้วย 1000 จะส่งผลให้ค่าลอยตัววัดในไม่กี่วินาที
สรุป: คุณสามารถใช้กลไกนี้เพื่อปรับ API ใด ๆ เป็นอินพุตของ Shaders ของคุณ ตรวจสอบการสาธิตโครงการสำหรับตัวอย่างวิธีการรวมอินพุตเช่น:
การประกาศชุด "พื้นผิว" ใช้ประเภท sampler2D :
uniform sampler2D iWebCam; ชื่อเครื่องแบบนั้นเป็นไปตามอำเภอใจ ตัวอย่างเช่น Shadertoy เป็นพื้นผิวที่มีผลผูกพันภายใต้ชื่อ iChannel0 , iChannel1 ฯลฯ และนี่คืออนุสัญญาที่ใช้เป็นส่วนใหญ่ในเอกสารนี้
เครื่องแบบดังกล่าวสามารถตั้งค่าได้ด้วย:
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
ctx . iWebCam = initializeTexture ( ctx . gl ) ;
} ,
shaders : {
image : {
uniforms : {
iWebCam : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iWebCam ) ;
}
}
}
} ) ;พื้นผิว ที่ส่งผ่านเป็นอาร์กิวเมนต์ที่สองไปยัง CTX.Texture สามารถเป็นอินสแตนซ์ของ WebGLEXTURE หรืออ้างอิงถึงบัฟเฟอร์ของ shader อื่นในท่อ ตรวจสอบส่วนตัวอย่างการกำหนดค่าที่ซับซ้อนและ API - บริบท: บัฟเฟอร์
ดูส่วนการเพิ่มพื้นผิวสำหรับรายละเอียดเกี่ยวกับวิธีการโหลดพื้นผิวจากภาพ
Shaders ทั้งหมดยกเว้นอันสุดท้ายในท่อจะมีพื้นผิวที่เกี่ยวข้องเพื่อแสดงผล โดยค่าเริ่มต้นพื้นผิวเหล่านี้จะเริ่มต้นเป็น RGBA HALF_FLOAT (16 บิต) จุดลอยตัวที่มีการแก้ไขเชิงเส้นและถูกยึดติดกับขอบ การเริ่มต้นพื้นผิวสามารถปรับแต่งได้ ดู API - Shader: เอกสารประกอบสำหรับรายละเอียด
นี่คือตัวอย่างที่ครอบคลุมของวัตถุการกำหนดค่าที่มีความคิดเห็น มันใช้การประชุม Shadertoy สำหรับการตั้งชื่อบัฟเฟอร์และเครื่องแบบ แต่โปรดทราบว่าการตั้งชื่อนั้นเป็นไปตามอำเภอใจและอาจปรับให้เข้ากับความต้องการของโครงการของคุณ
// mouse coordinates taken from from the mousemove event expressed in "CSS pixels"
var mouseX ;
var mouseY ;
document . addEventListener ( "mousemove" , ( event ) => {
mouseX = event . clientX ;
mouseY = event . clientY ;
} ) ;
shaderWebBackground . shade ( {
// supplied canvas to use for shading
canvas : document . getElementById ( "my-canvas" ) ,
// called only once before the first run
onInit : ( ctx ) => {
// we can center the mouse even before any "mousemove" event occurs
// note, we are
mouseX = ctx . cssWidth / 2 ;
mouseY = ctx . cssHeight / 2 ;
// for convenience you can store your attributes on context
ctx . iFrame = 0 ;
} ,
onResize : ( width , height , ctx ) => {
ctx . iMinDimension = Math . min ( width , height ) ;
} ,
onBeforeFrame : ( ctx ) => {
ctx . shaderMouseX = ctx . toShaderX ( mouseX ) ;
ctx . shaderMouseY = ctx . toShaderY ( mouseY ) ;
} ,
shaders : {
// the first buffer to be rendered in the pipeline
BufferA : {
// uniform setters, attribute names should match with those defined in the shader
uniforms : {
// uniform value calculated in place
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 ) ,
// uniform values taken from context
iFrame : ( gl , loc ) => gl . uniform1i ( loc , ctx . iFrame ) ,
iMinDimension : ( gl , loc , ctx ) => gl . uniform1f ( loc , ctx . iMinDimension ) ,
iResolution : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . width , ctx . height ) ,
iMouse : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . shaderMouseX , ctx . shaderMouseY ) ,
// inputing the previous output of itself - feedback loop
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
// ... more uniforms
}
} ,
// ... more shaders
BufferD : {
// optional custom initializer of buffer's texture
texture : ( gl , ctx ) => {
// initializing floating-point texture in custom way for WebGL 1 and 2
ctx . initHalfFloatRGBATexture ( ctx . width , ctx . height ) ;
// standard WebGL texture parameters
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . REPEAT ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . REPEAT ) ;
} ,
uniforms : {
iChanel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
// ... more uniforms
}
} ,
// the last shader will render to screen
Image : {
uniforms : {
iChanel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferD )
// ... more uniforms
}
}
} ,
onAfterFrame : ( ctx ) => {
ctx . iFrame ++ ;
} ,
// custom error handler
onError : ( error , canvas ) => {
canvas . remove ( ) ;
console . error ( error ) ;
document . documentElement . classList . add ( "my-fallback" ) ;
}
} ) ; API มีจุดประสงค์เพื่ออธิบายตนเอง ตรวจสอบข้อมูลจำเพาะ API สำหรับรายละเอียด มีหลายเฉดที่กำหนดไว้ในตัวอย่างด้านบน พวกเขาจะได้รับการประมวลผลตามลำดับที่เรียกว่า Multipass ใน Shadertoy Premenclature Shaders สุดท้ายที่กำหนดจะแสดงผลบนหน้าจอ เอาต์พุตของ shaders ก่อนหน้านี้รวมถึงลูปข้อเสนอแนะของเฟรมก่อนหน้าที่แสดงโดย shader เดียวกันสามารถส่งผ่านไปยังเครื่องแบบได้อย่างง่ายดาย
มีการตรวจสอบความถูกต้องหลายครั้งในการกำหนดค่าที่ให้มาเพื่อหลีกเลี่ยงปัญหาที่พบบ่อยซึ่งมักจะยากต่อการดีบัก SRC/Test/HTML/ข้อผิดพลาด/โฟลเดอร์มีกรณีทดสอบข้อผิดพลาดทั้งหมดซึ่งสามารถตรวจสอบได้ในการสาธิตการจัดการข้อผิดพลาดแบบสด
ข้อผิดพลาดและคำเตือนทั้งหมดจะปรากฏบนคอนโซล
ดู:
// mouse coordinates taken from from the mousemove event
var mouseX ;
var mouseY ;
document . addEventListener ( "mousemove" , ( event ) => {
mouseX = event . clientX ;
mouseY = event . clientY ;
} ) ;
// mouse coordinates relative to the shader, you can also store them on the context
var shaderMouseX ;
var shaderMouseY ;
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
// screen center
mouseX = ctx . cssWidth / 2 ;
mouseY = ctx . cssHeight / 2 ;
} ,
onBeforeFrame : ( ctx ) => {
shaderMouseX = ctx . toShaderX ( mouseX ) ;
shaderMouseY = ctx . toShaderY ( mouseY ) ;
} ,
shaders : {
image : {
uniforms : {
iMouse : ( gl , loc ) => gl . uniform2f ( loc , shaderMouseX , shaderMouseY )
}
}
}
} ) ; หมายเหตุ: พิกัดเมาส์เริ่มต้นมีให้ในฟังก์ชั่น onInit เนื่องจากเหตุการณ์ mousemove ครั้งแรกสามารถเกิดขึ้นได้นานหลังจากที่ Shader เริ่มต้นขึ้น พิกัด Shader เริ่มต้นที่มุมล่างซ้ายของผืนผ้าใบและอยู่ในแนวเดียวกันกับกลางพิกเซล - (0.5, 0.5)
API อ้างอิง:
การสาธิต:
python -m http.server 8000 ถ้ามันไม่ทำงานกับ Ubuntu ล่าสุดของคุณมากกว่าเรียกใช้ sudo apt install python-is-python3 ก่อน
ดูพื้นผิว: Blue Marble to Flat Earth Mapping Demo
พื้นผิวสามารถตั้งค่าในลักษณะเดียวกับบัฟเฟอร์ถูกตั้งค่าเป็นเครื่องแบบ แต่ก่อนอื่นเราต้องโหลด ตัวอย่างเช่นโดยการกำหนดสัญญาที่กำหนดเองซึ่งสามารถนำกลับมาใช้ใหม่ได้:
const loadImage = ( src ) => new Promise ( ( resolve , reject ) => {
let img = new Image ( ) ;
img . onload = ( ) => resolve ( img ) ;
img . onerror = ( ) => {
reject ( new Error ( "Failed to load image from: " + src ) ) ;
}
img . src = src ;
} ) ; ฟังก์ชั่น onInit ค่อนข้างสะดวกสำหรับการโทร loadPicture :
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
loadImage ( "texture.jpg" )
. then ( image => {
const gl = ctx . gl ;
const texture = gl . createTexture ( ) ;
gl . bindTexture ( gl . TEXTURE_2D , texture ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . CLAMP_TO_EDGE ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . CLAMP_TO_EDGE ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . LINEAR ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . LINEAR ) ;
gl . texImage2D ( gl . TEXTURE_2D , 0 , gl . RGBA , gl . RGBA , gl . UNSIGNED_BYTE , image ) ;
gl . bindTexture ( gl . TEXTURE_2D , null ) ;
ctx . iTexture = texture ;
} ) ;
} ,
shaders : {
image : {
uniforms : {
iTexture : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iTexture )
}
}
}
} ) ; ห้องสมุดนี้สามารถใช้รหัส Shadertoy ด้วยความพยายามน้อยที่สุด - การห่อหุ้มแบบง่าย ๆ :
< script type =" x-shader/x-fragment " id =" Image " >
precision highp float ;
uniform vec2 iResolution ;
uniform float iTime ;
// ... other needed uniforms
// -- Paste your Shadertoy code here:
// ...
// -- End of Shadertoy code
void main ( ) {
mainImage ( gl_FragColor , gl_FragCoord . xy ) ;
}
</ script > แอตทริบิวต์ id ของ <script> ถูกตั้งค่าเพื่อสะท้อนแท็บ Shadertoy ที่เรียกว่า Image shaders ส่วนใหญ่จะใช้อย่างน้อย 2 เครื่องแบบเหล่านี้และเป็นเรื่องง่ายที่จะให้ค่าของพวกเขาในการกำหนดค่า:
shaderWebBackground . shade ( {
shaders : {
Image : {
uniforms : {
iResolution : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . width , ctx . height ) ,
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 ) ,
}
}
}
} ) ;การสาธิต Shadertoy:
ไม่มีวิธีแก้ปัญหาอัตโนมัติสำหรับสิ่งนั้น คุณจะต้องคัดลอกส่วน Common ลงในเฉดสีของคุณโดยตรงเหนือรหัส Shadertoy อื่น ๆ
texture ? ในพื้นผิวของ Shadertoy สามารถเข้าถึงได้ด้วยฟังก์ชั่น texture ในขณะที่อยู่ใน WebGL 1 มันคือ texture2D นี่คือวิธีแก้ปัญหาง่าย ๆ ที่จะเพิ่มก่อนรหัสต้นฉบับ:
#define texture texture2D ใน Shadertoy แต่ละช่อง "ช่อง" การผูกพื้นผิวสามารถมีพารามิเตอร์ตัวอย่างแยกต่างหากเช่นการแก้ไขหรือการห่อ ฟังก์ชั่นนี้ไม่สามารถพอร์ตได้อย่างง่ายดายไปยัง WebGL 1 แต่ shaders ส่วนใหญ่ที่ถ่ายทอดบนคุณสมบัติเหล่านี้สามารถปรับได้ด้วยวิธีแก้ปัญหาที่ใช้รหัส ตัวอย่างเช่นหากควรทำพื้นผิวซ้ำแล้วสิ่งนี้อาจเป็นการแทนที่ฟังก์ชั่นการใช้งานของฟังก์ชัน texture ใน shader ที่กำหนด:
vec4 repeatedTexture( in sampler2D channel, in vec2 uv) {
return texture2D (channel, mod (uv, 1 .));
}ดูเพิ่มเติมที่ API - Shader: พื้นผิว
คุณสามารถตั้งชื่อ shaders ของคุณตามชื่อบัฟเฟอร์ Shadertoy:
BufferABufferBBufferCBufferDImageจากนั้นให้สายเข้าด้วยกัน:
<!DOCTYPE html >
< html lang =" en " >
< head >
< title > Multipass Shadertoy shader </ title >
< script type =" x-shader/x-fragment " id =" BufferA " >
precision highp float ;
uniform sampler2D iChannel0 ;
// ... the code of BufferA tab with the uniforms and wrapping as above
</ script >
< script type =" x-shader/x-fragment " id =" Image " >
precision highp float ;
uniform sampler2D iChannel0 ;
// ... the code of Image tab with the uniforms and wrapping as above
</ script >
< script >
// ... your prefer method of loading shader-web-background as described above
</ script >
< script >
shaderWebBackground . shade ( {
shaders : {
BufferA : {
uniforms : {
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
}
} ,
Image : {
uniforms : {
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
}
}
}
} ) ;
</ script >
</ head >
< body >
</ body >
</ html > เป็นไปได้ที่จะเปลี่ยน vertex shader เริ่มต้นสำหรับแต่ละ shader ชิ้นส่วนโดยให้สคริปต์ต่อไปนี้ใน <head> :
< script type = "x-shader/x-vertex" id = "shaderIdVertex" >
attribute vec2 V;
varying vec2 uv;
void main() {
gl_Position = vec4 ( V , 0 , 1 ) ;
}
</ script >
< script type = "x-shader/x-fragment" id = "shaderId" >
// ...
varying vec2 uv ;
// ...
< / script > หมายเหตุ: type สคริปต์ถูกตั้งค่าเป็น x-shader/x-vertex และแอตทริบิวต์ id จะถูกเตรียมไว้ล่วงหน้าด้วยคำต่อท้าย Vertex แอตทริบิวต์จุดสุดยอดควรมีชื่อว่า V
หมายเหตุ: สามารถระบุ varying vec2 uv กันได้ระหว่างจุดสุดยอดและเศษชิ้นส่วน (ไม่เพิ่มโดยค่าเริ่มต้น)
git clone https://github.com/xemantic/shader-web-background.git
cd shader-web-background
./gradlew compileJsมันจะกระตุ้นคอมไพเลอร์ปิด Google ซึ่งจะตรวจสอบแหล่งข้อมูลโดยใช้ข้อมูลประเภทและ transpile เป็นไฟล์ JavaScript ที่ย่อมา
โครงการนี้ได้รับการพัฒนาโดยใช้แนวคิด Intellij พร้อมปลั๊กอิน Google-Java-Format องค์ประกอบที่เห็นได้ชัดเจนที่สุดของสไตล์นี้คือ 2 ช่องว่างแทนที่จะเป็น 4 สำหรับแท็บการเรนเดอร์
ทั้ง:
<section id="projects-using-shader-web-background">หรือส่งลิงค์พร้อมคำอธิบาย