2016-05-02 12 views
2

Ich mache meine ersten Schritte Codierung. Ich habe einige Kurse im Internet gemacht, dann habe ich mit ein paar Experimenten von 3d.j gespielt und jetzt möchte ich weiter lernen, mit Shadern zu experimentieren.Export von Shadertoy zu Three.js

Ich fand Shaderto.com und es ist wirklich erstaunlich! Es gibt viele verschiedene Experimente mit unglaublichen Effekten. Ich versuche einen dieser Shader in Three.js zu verwenden, ist aber nicht so einfach.

Die Shader sind bereits geschrieben, es ist wahr. Aber ich weiß nicht, was ich damit anfangen soll, ich weiß nicht, wie ich es benutzen kann.

Weil es nicht nur den Code kopieren und einfügen. Es gibt eine Beziehung, in die ich schreiben muss, um einige dieser erstaunlichen Effekte auf eine Three.js-Geometrie anzuwenden. Ich muss Uniformen benutzen, und ich weiß nicht, wie ich herausfinden kann, welche Uniformen ich benutzen kann und wie ich sie benutzen kann.

Ich begann zu sehen, die Tutorials in Shadertoy und einige Artikel im Internet und es sieht aus wie etwas wirklich abstrakt. Ich denke, dass ich viel Mathematik studieren sollte, bevor ich anfing, diese Sprache zu verstehen.

Haben Sie eine Empfehlung zu starten?

Vielleicht ist etwas einfacher als ich denke und ich kann nur kopieren, einfügen und experimentieren mit dem Code auf meinem HTML-Dokument?

+0

Ich habe ein paar Shadertoy Shadern arbeiten in three.js. Insbesondere der [Matrix-Shader] (http://blog.2pha.com/demos/threejs/shaders/matrix.html). Ein Blick darauf kann Ihnen helfen – 2pha

Antwort

6

Shadertoy ist ein relativ komplexes Programm. Es hat Audio-Input in Shadern, Video-Input in Shadern, Audio-Datengenerierung von Shadern, verschiedene Arten von Texturen, einschließlich 2D und Cubemaps. Die Unterstützung all dieser Funktionen ist keine kleine Arbeit.

Das sagte ein basischer Shader kann ziemlich einfach verwendet werden, siehe Beispiel unten. Aber Shadertoy Shader sind nicht wirklich dazu gedacht, als Material auf Meshes in Three.js verwendet zu werden.

Wenn Sie verstehen, warum wollen und wie WebGL Werke http://webglfundamentals.org

const vs = ` 
 
attribute vec4 position; 
 
void main() \t { 
 
    gl_Position = position; 
 
} 
 
`; 
 
const userShader = ` 
 
// FROM: https://www.shadertoy.com/view/4sdXDl 
 
//spikey 
 
#define SHAPE length(z.yz) 
 
//normal 
 
//#define SHAPE length(z.xyz) 
 
//bizarro 
 
//#define SHAPE length(z.yz-z.xx) 
 
//etc... 
 
#define HIGH_QUAL 
 
#ifdef HIGH_QUAL 
 
#define MARCH_STEPS 199 
 
#else 
 
#define MARCH_STEPS 99 
 
#endif 
 
float k=7.0+3.0*sin(iGlobalTime*0.15); 
 
vec3 mcol=vec3(0.0); 
 
void AbsBox(inout vec4 z){//abs box by kali 
 
z.xyz=abs(z.xyz+1.0)-1.0; 
 
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0); 
 
} 
 
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee 
 
float r = length(z.xyz); 
 
float zo = asin(z.z/r) * k + iGlobalTime*0.15; 
 
float zi = atan(z.y, z.x) * 7.0; 
 
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c; 
 
} 
 
float DE(vec3 p){ 
 
    vec4 c = vec4(p,1.0),z = c; 
 
    Bulb(z,c); 
 
    float r0=(length(z.xyz)-1.15)/z.w; 
 
    z.xyz-=1.0; 
 
    for(int i=0;i<7;i++)AbsBox(z); 
 
    float r=SHAPE; 
 
    mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w)); 
 
    return 0.5 * max((r-1.0)/z.w,-r0); 
 
} 
 

 
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code 
 
    float d=0.4*dot(rd,L)+0.6; 
 
    //return vec3(d); 
 
    rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y); 
 
    rd=abs(rd); 
 
    float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.) 
 
    +.3*pow(1.-rd.y,12.)*(1.6-y); 
 
    return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun) 
 
    *((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y)); 
 
} 
 
float rnd; 
 
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);} 
 

 
float ShadAO(in vec3 ro, in vec3 rd){ 
 
float t=0.0,s=1.0,d,mn=0.01; 
 
for(int i=0;i<12;i++){ 
 
    d=max(DE(ro+rd*t)*1.5,mn); 
 
    s=min(s,d/t+t*0.5); 
 
    t+=d; 
 
} 
 
return s; 
 
} 
 
vec3 scene(vec3 ro, vec3 rd){ 
 
    vec3 L=normalize(vec3(0.4,0.025,0.5)); 
 
    vec3 bcol=sky(rd,L); 
 
    vec4 col=vec4(0.0);//color accumulator 
 
    float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x; 
 
    for(int i=0;i<MARCH_STEPS;i++){ 
 
    d=DE(ro); 
 
    if(d<px*t){ 
 
     float dif=clamp(1.0-d/od,0.2,1.0); 
 
     vec3 scol=mcol*dif*(1.3-0.3*t); 
 
#ifdef HIGH_QUAL 
 
     \t vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L)); 
 
     scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0); 
 
#endif 
 
     float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0); 
 
     col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha; 
 
     if(col.w>0.9)break; 
 
    } 
 
    t+=d;ro+=rd*d;od=d; 
 
    if(t>6.0)break; 
 
    } 
 
    col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0)); 
 
    return col.rgb; 
 
} 
 
mat3 lookat(vec3 fw){ 
 
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw); 
 
} 
 
void mainImage(out vec4 fragColor, in vec2 fragCoord) { 
 
    randomize(fragCoord); 
 
    float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7); 
 
    vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x; 
 
    vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r); 
 
    vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0)); 
 
    //rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd); 
 
    fragColor=vec4(scene(ro,rd)*2.0,1.0); 
 
} 
 
`; 
 

 
// FROM shadertoy.com 
 
const shadertoyBoilerplate = ` 
 
#extension GL_OES_standard_derivatives : enable 
 
//#extension GL_EXT_shader_texture_lod : enable 
 
#ifdef GL_ES 
 
precision highp float; 
 
#endif 
 
uniform vec3  iResolution; 
 
uniform float  iGlobalTime; 
 
uniform float  iChannelTime[4]; 
 
uniform vec4  iMouse; 
 
uniform vec4  iDate; 
 
uniform float  iSampleRate; 
 
uniform vec3  iChannelResolution[4]; 
 
uniform int  iFrame; 
 
uniform float  iTimeDelta; 
 
uniform float  iFrameRate; 
 
struct Channel 
 
{ 
 
    vec3 resolution; 
 
    float time; 
 
}; 
 
uniform Channel iChannel[4]; 
 
uniform sampler2D iChannel0; 
 
uniform sampler2D iChannel1; 
 
uniform sampler2D iChannel2; 
 
uniform sampler2D iChannel3; 
 
void mainImage(out vec4 c, in vec2 f); 
 

 
${userShader} 
 

 
void main(void){ 
 
    vec4 color = vec4(0.0,0.0,0.0,1.0); 
 
    mainImage(color, gl_FragCoord.xy); 
 
    color.w = 1.0; 
 
    gl_FragColor = color; 
 
} 
 
`; 
 

 
const $ = document.querySelector.bind(document); 
 

 
const camera = new THREE.Camera(); 
 
camera.position.z = 1; 
 

 
const scene = new THREE.Scene(); 
 

 
const geometry = new THREE.BufferGeometry(); 
 
const vertices = new Float32Array([ 
 
    -1, -1, 
 
    1, -1, 
 
    -1, 1, 
 
    -1, 1, 
 
    1, -1, 
 
    1, 1, 
 
]); 
 
geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 2)); 
 

 
const uniforms = { 
 
    iGlobalTime: { type: "f", value: 1.0 }, 
 
    iResolution: { type: "v3", value: new THREE.Vector3() }, 
 
}; 
 

 
const material = new THREE.RawShaderMaterial({ 
 
    uniforms: uniforms, 
 
    vertexShader: vs, 
 
    fragmentShader: shadertoyBoilerplate, 
 
}); 
 

 
var mesh = new THREE.Mesh(geometry, material); 
 
scene.add(mesh); 
 

 
var renderer = new THREE.WebGLRenderer(); 
 
document.body.appendChild(renderer.domElement); 
 

 
resize(true); 
 
render(0); 
 

 
function resize(force) { 
 
    var canvas = renderer.domElement; 
 
    var dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow 
 
    var width = canvas.clientWidth * dpr; 
 
    var height = canvas.clientHeight * dpr; 
 
    if (force || width != canvas.width || height != canvas.height) { 
 
    renderer.setSize(width, height, false); 
 
    uniforms.iResolution.value.x = renderer.domElement.width; 
 
    uniforms.iResolution.value.y = renderer.domElement.height; 
 
    } 
 
} 
 

 
function render(time) { 
 
    resize(); 
 
    uniforms.iGlobalTime.value = time * 0.001; 
 
    renderer.render(scene, camera); 
 
    requestAnimationFrame(render); 
 
}
canvas { 
 
    border: 1px solid black; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>

Der obige Code von shadertoy sehen gibt gl_FragCoord als Eingabe für den Shader des Benutzers, der die Pixel-Koordinate des Pixels in die Leinwand gezeichnet werden. Für ein Modell können wir stattdessen UV-Koordinaten übergeben, wir müssen nur eine Auflösung wählen, um sie zu multiplizieren, da die UV-Koordinaten normalerweise von 0 bis 1 gehen und die Shaderty-Shader 0 bis canvas.width und 0 bis Canvas erwarten .Height

Beispiel:

const vs = ` 
 
varying vec2 vUv; 
 

 
void main() 
 
{ 
 
    vUv = uv; 
 
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); 
 
    gl_Position = projectionMatrix * mvPosition; 
 
} 
 
`; 
 
const userShader = ` 
 
// FROM: https://www.shadertoy.com/view/4sdXDl 
 
//spikey 
 
#define SHAPE length(z.yz) 
 
//normal 
 
//#define SHAPE length(z.xyz) 
 
//bizarro 
 
//#define SHAPE length(z.yz-z.xx) 
 
//etc... 
 
#define HIGH_QUAL 
 
#ifdef HIGH_QUAL 
 
#define MARCH_STEPS 199 
 
#else 
 
#define MARCH_STEPS 99 
 
#endif 
 
float k=7.0+3.0*sin(iGlobalTime*0.15); 
 
vec3 mcol=vec3(0.0); 
 
void AbsBox(inout vec4 z){//abs box by kali 
 
z.xyz=abs(z.xyz+1.0)-1.0; 
 
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0); 
 
} 
 
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee 
 
float r = length(z.xyz); 
 
float zo = asin(z.z/r) * k + iGlobalTime*0.15; 
 
float zi = atan(z.y, z.x) * 7.0; 
 
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c; 
 
} 
 
float DE(vec3 p){ 
 
    vec4 c = vec4(p,1.0),z = c; 
 
    Bulb(z,c); 
 
    float r0=(length(z.xyz)-1.15)/z.w; 
 
    z.xyz-=1.0; 
 
    for(int i=0;i<7;i++)AbsBox(z); 
 
    float r=SHAPE; 
 
    mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w)); 
 
    return 0.5 * max((r-1.0)/z.w,-r0); 
 
} 
 

 
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code 
 
    float d=0.4*dot(rd,L)+0.6; 
 
    //return vec3(d); 
 
    rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y); 
 
    rd=abs(rd); 
 
    float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.) 
 
    +.3*pow(1.-rd.y,12.)*(1.6-y); 
 
    return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun) 
 
    *((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y)); 
 
} 
 
float rnd; 
 
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);} 
 

 
float ShadAO(in vec3 ro, in vec3 rd){ 
 
float t=0.0,s=1.0,d,mn=0.01; 
 
for(int i=0;i<12;i++){ 
 
    d=max(DE(ro+rd*t)*1.5,mn); 
 
    s=min(s,d/t+t*0.5); 
 
    t+=d; 
 
} 
 
return s; 
 
} 
 
vec3 scene(vec3 ro, vec3 rd){ 
 
    vec3 L=normalize(vec3(0.4,0.025,0.5)); 
 
    vec3 bcol=sky(rd,L); 
 
    vec4 col=vec4(0.0);//color accumulator 
 
    float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x; 
 
    for(int i=0;i<MARCH_STEPS;i++){ 
 
    d=DE(ro); 
 
    if(d<px*t){ 
 
     float dif=clamp(1.0-d/od,0.2,1.0); 
 
     vec3 scol=mcol*dif*(1.3-0.3*t); 
 
#ifdef HIGH_QUAL 
 
     \t vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L)); 
 
     scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0); 
 
#endif 
 
     float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0); 
 
     col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha; 
 
     if(col.w>0.9)break; 
 
    } 
 
    t+=d;ro+=rd*d;od=d; 
 
    if(t>6.0)break; 
 
    } 
 
    col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0)); 
 
    return col.rgb; 
 
} 
 
mat3 lookat(vec3 fw){ 
 
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw); 
 
} 
 
void mainImage(out vec4 fragColor, in vec2 fragCoord) { 
 
    randomize(fragCoord); 
 
    float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7); 
 
    vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x; 
 
    vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r); 
 
    vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0)); 
 
    //rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd); 
 
    fragColor=vec4(scene(ro,rd)*2.0,1.0); 
 
} 
 
`; 
 

 
// FROM shadertoy.com 
 
const shadertoyBoilerplate = ` 
 
#extension GL_OES_standard_derivatives : enable 
 
//#extension GL_EXT_shader_texture_lod : enable 
 
#ifdef GL_ES 
 
precision highp float; 
 
#endif 
 
uniform vec3  iResolution; 
 
uniform float  iGlobalTime; 
 
uniform float  iChannelTime[4]; 
 
uniform vec4  iMouse; 
 
uniform vec4  iDate; 
 
uniform float  iSampleRate; 
 
uniform vec3  iChannelResolution[4]; 
 
uniform int  iFrame; 
 
uniform float  iTimeDelta; 
 
uniform float  iFrameRate; 
 
struct Channel 
 
{ 
 
    vec3 resolution; 
 
    float time; 
 
}; 
 
uniform Channel iChannel[4]; 
 
uniform sampler2D iChannel0; 
 
uniform sampler2D iChannel1; 
 
uniform sampler2D iChannel2; 
 
uniform sampler2D iChannel3; 
 

 
varying vec2 vUv; 
 

 
void mainImage(out vec4 c, in vec2 f); 
 

 
${userShader} 
 

 
void main(void){ 
 
    vec4 color = vec4(0.0,0.0,0.0,1.0); 
 
    mainImage(color, vUv * iResolution.xy); 
 
    color.w = 1.0; 
 
    gl_FragColor = color; 
 
} 
 
`; 
 

 
const $ = document.querySelector.bind(document); 
 

 
const fieldOfView = 45; 
 
const zNear = .1; 
 
const zFar = 100; 
 
const camera = new THREE.PerspectiveCamera(fieldOfView, 1, zNear, zFar); 
 
camera.position.z = 3; 
 

 
const scene = new THREE.Scene(); 
 

 
const geometry = new THREE.BoxGeometry(1, 1, 1); 
 

 
const uniforms = { 
 
    iGlobalTime: { type: "f", value: 1.0 }, 
 
    iResolution: { type: "v3", value: new THREE.Vector3() }, 
 
}; 
 

 
// choose a resolution to pass to the shader 
 
uniforms.iResolution.value.x = 100; 
 
uniforms.iResolution.value.y = 100; 
 

 
const material = new THREE.ShaderMaterial({ 
 
    uniforms: uniforms, 
 
    vertexShader: vs, 
 
    fragmentShader: shadertoyBoilerplate, 
 
}); 
 

 
const mesh = new THREE.Mesh(geometry, material); 
 
scene.add(mesh); 
 

 
var renderer = new THREE.WebGLRenderer(); 
 
document.body.appendChild(renderer.domElement); 
 

 
resize(true); 
 
render(0); 
 

 
function resize(force) { 
 
    const canvas = renderer.domElement; 
 
    const dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow 
 
    const width = canvas.clientWidth * dpr; 
 
    const height = canvas.clientHeight * dpr; 
 
    if (force || width != canvas.width || height != canvas.height) { 
 
    renderer.setSize(width, height, false); 
 
    camera.aspect = width/height; 
 
    camera.updateProjectionMatrix(); 
 
    } 
 
} 
 

 
function render(time) { 
 
    time *= 0.001; // seconds 
 
    
 
    resize(); 
 
    
 
    uniforms.iGlobalTime.value = time; 
 
    mesh.rotation.x = time * 0.5; 
 
    mesh.rotation.y = time * 0.6; 
 
    
 
    renderer.render(scene, camera); 
 
    requestAnimationFrame(render); 
 
}
body { margin: 0; } 
 
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>

anzumerken, dass shadertoy Shadern werden im allgemeinen nicht als Materialien verwendet werden, entworfen. Sie sind nicht effizient, eher eher eine lustige Aktivität von "wie cool ein Bild ist, das ich nur mit der Zeit und der Pixelposition als Eingabe machen kann". Aufgrund der, dass, während die Ergebnisse können erstaunlich sind sie oft 10x oder 100x oder sogar 1000-fach langsamer als herkömmliche Techniken für Materialien (mit Texturen)

für die Vergleichs Beispiel this amazing shader, die eine ganze Stadt zieht aber zumindest auf meinem Rechner läuft es an 10-18 fps in einem kleinen Fenster und 1 fps im Vollbildmodus.VS zum Beispiel Grand Theft Auto 5, die auch eine ganze Stadt zeigt, schafft es aber mit 30-60fps zu laufen, wenn sie auf dem gleichen Computer im Vollbildmodus läuft.

Es gibt eine Menge Spaß zu haben und viele interessante Techniken auf shadertoy.com zu lernen, die in Ihren Shadern nützlich sein könnten, aber verwechseln Sie nicht, was es für "Produktionstechniken" gibt. Es heißt aus einem Grund shaderTOY

+0

Dies ist eine amzing Antwort + Fraktal. Vielen Dank :) – rubmz