aframe-raytrace-component
Version:
An A-Frame component for placing raytraced surfaces in a scene.
594 lines (414 loc) • 21 kB
HTML
<html>
<head>
<meta charset="utf-8">
<title>A-Frame Raytrace Component - Basic</title>
<meta name="description" content="Basic example for Raytrace component."></meta>
<script src="https://aframe.io/releases/1.0.3/aframe.min.js"></script>
<script src="../../dist/aframe-raytrace-component.min.js"></script>
</head>
<body>
<script id="blob-fs" type="x-shader/x-fragment">
precision mediump float;
uniform float time;
uniform vec3 localCameraPos;
varying vec3 localSurfacePos;
const float blobsize = 0.2;
float smoothBlend( float a, float b, float k ){
float h = clamp(0.5+0.5*(b-a)/k,0.0,1.0);
return mix(b,a,h) - k*h*(1.0-h);
}
void hardAdd(inout float curD, float newD){
curD = min(curD,newD);
}
void smoothAdd(inout float curD, float newD, float blendPower){
curD = smoothBlend( newD, curD, blendPower );
}
float obj_ball(vec3 p, vec3 center, float radius){
return length(p-center)-radius;
}
vec3 blobBallPos(float i){
float v = time/1000.0*2.0 + i*100.0;
return vec3(
sin( v + sin(v*0.8) + sin(v*0.2)*sin(v*2.1) )*blobsize,
sin( v + sin(v*0.6) + sin(v*0.4)*sin(v*2.2) )*blobsize,
sin( v + sin(v*0.4) + sin(v*0.6)*sin(v*2.3) )*blobsize
);
}
float room(vec3 p){
float distance = 9999.9;
hardAdd(distance, obj_ball(p, blobBallPos(0.0), blobsize) );
for(float i=1.0; i<8.0; i+=1.0){
smoothAdd(distance, obj_ball(p, blobBallPos(i), blobsize) , blobsize);
}
return distance;
}
void main() {
vec3 curCameraRayUnit = normalize(localSurfacePos - localCameraPos);
// zero optimization done to step size, max iterations, etc..!
const vec3 e=vec3(0.02,0,0);
const float maxd=40.0; //Max depth
vec3 c,p,N;
float sA,sP;
// march to bg
vec3 color=vec3(1.0,1.0,1.0);
float f=0.0;
float d=0.001;
vec3 surfaceColor;
for(int i=0;i<64;i++){
if ((abs(d) < .001) || (f > maxd)) break;
f+=d;
p=localCameraPos+curCameraRayUnit*f;
d = room(p);
}
float specA=1.0, specP=8.0;
if (f < maxd){
vec3 n = vec3(d-room(p-e.xyy),
d-room(p-e.yxy),
d-room(p-e.yyx));
N = normalize(n);
vec3 L = normalize(vec3(1.0,1.0,1.0)-p);
float diffuse=max(dot(N,L),0.0);
vec3 H = normalize(L-curCameraRayUnit);
float specular = max(dot(H,N),0.0);
color = (diffuse*0.8+0.2)*vec3(1.0,0,1.0) + pow(specular,specP)*specA;
} else {
discard;
}
gl_FragColor = vec4(color,1.0);
}
</script>
<script id="columns-fs" type="x-shader/x-fragment">
precision mediump float;
uniform float time;
uniform vec3 localCameraPos;
varying vec3 localSurfacePos;
float obj_box(vec3 p, vec3 center, vec3 size, float roundness){
vec3 d = abs(p-center)-size;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)) - roundness;
}
float obj_cylinder(vec3 p, vec3 center, vec2 size, float roundness){
vec3 tp = p-center;
vec2 d = abs(vec2(length(tp.xz),tp.y)) - size;
return min(max(d.x,d.y)+roundness,0.0) + length(max(d,0.0))-roundness;
}
float obj_planeX(vec3 p, float planeX){
return p.x-planeX;
}
float obj_planeY(vec3 p, float planeY){
return p.y-planeY;
}
float obj_planeZ(vec3 p, float planeZ){
return p.z-planeZ;
}
float obj_cylForeverZ(vec2 p, float middleY, float radius){
return abs(length(vec2(p.x,p.y-middleY))) - radius;
}
float distSmooth( float a, float b, float k ){
float h = clamp(0.5+0.5*(b-a)/k,0.0,1.0);
return mix(b,a,h) - k*h*(1.0-h);
}
void hardAdd(inout float curD, inout int curMaterial, float newD, int newMaterial){
if (newD < curD) {
curD = newD;
curMaterial = newMaterial;
}
}
void hardSubtract(inout float curD, float newD) {
curD = max( -newD, curD );
}
void smoothAdd(inout float curD, float newD, float blendPower){//blend colors too?
curD = distSmooth( newD, curD, blendPower );
}
void smoothSubtract(inout float curD, float newD, float blendPower){
curD = -distSmooth( newD , -curD , blendPower );
}
const float cylMidZ = -1.5;
float fwdDist = time/1000.0;
float middleMod(float val,float modDist){
return mod(val+modDist*0.5,modDist)-modDist*0.5;
}
float room(vec3 p, out int material){
float distance = 9999.9;
material = 0;
const float pillarGapX = 2.5;
const float pillarGapZ = 0.5;
const float floorTileGap = 0.5;
const float floorTileGrout = 0.07;
const float ceilY = 9.0;
const float mirrorY = 0.5;
vec3 pillarP = vec3(mod(p.x,pillarGapX*2.0),-abs(p.y-mirrorY)+mirrorY,mod(p.z,pillarGapZ*2.0));
// ceiling flat
hardAdd(distance,material,
-obj_planeY(p ,ceilY),
3);
// ceiling groove
hardSubtract(distance,
obj_cylForeverZ(vec2(middleMod(p.x,5.0),p.y),ceilY,2.3));
// base
hardAdd(distance,material,
obj_box(pillarP,vec3(pillarGapX,-1.4,pillarGapZ),vec3(0.4,0.15,0.4),0.0),
1);
// base blend
smoothAdd(distance,
obj_cylinder(pillarP,vec3(pillarGapX,-1.15,pillarGapZ),vec2(0.3,0.1),0.0),
0.11);
// floor
hardAdd(distance,material,
obj_box(vec3(mod(p.x,floorTileGap*2.0),p.y,mod(p.z,floorTileGap*2.0)),vec3(floorTileGap,-1.5-floorTileGap,floorTileGap),vec3(floorTileGap-floorTileGrout),floorTileGrout),
2);
//column
hardAdd(distance,material,
obj_cylinder(pillarP,vec3(pillarGapX,mirrorY,pillarGapZ),vec2(0.25,2.0),0.0),
1);
return distance;
}
void main(){
const vec3 e=vec3(0.00007,0,0);
const float maxd=40.0; //Max depth
vec3 p;
vec3 curCameraRayUnit = normalize(localSurfacePos - localCameraPos);
float f=0.0;
float d=0.01;
int surfaceMaterial = 0;
for(int i=0;i<96;i++){
if ((abs(d) < .001) || (f > maxd)) break;
f+=d;
p=vec3(0,0,-fwdDist)+localCameraPos+curCameraRayUnit*f;
d = room(p,surfaceMaterial);
}
vec3 color;
int dummyMaterial;
if (f < maxd){
vec3 surfaceColor;
float specA, specP;
float difP = 1.0;
vec3 normalCheat = vec3(0.0,0.0,0.0);//generally not advisable in stereo, but it's used very shallowly here
if (surfaceMaterial == 1){
vec3 marbleP = p;
marbleP.x += sin(p.y*20.0)*0.12;
marbleP.z += sin(p.y*22.0)*0.1;
marbleP.y += sin(p.x*25.0)*0.13;
marbleP.y += sin(p.z*23.0)*0.14;
marbleP.y += sin(p.x*1.3)*0.5;
marbleP.y += sin(p.z*1.5)*0.6;
marbleP.x += sin(p.y*150.0)*0.011;
marbleP.z += sin(p.y*162.0)*0.013;
marbleP.y += sin(p.x*145.0)*0.012;
marbleP.y += sin(p.z*153.0)*0.015;
marbleP.x *= 20.0;
marbleP.z *= 20.0;
marbleP.y *= 10.0;
float marbleAmtA = abs(sin(marbleP.x)+sin(marbleP.y)+sin(marbleP.z))/3.0;
marbleAmtA = pow(1.0-marbleAmtA,5.0);
marbleP = p;
marbleP.x += sin(p.y*21.0)*0.12;
marbleP.z += sin(p.y*23.0)*0.1;
marbleP.y += sin(p.x*22.0)*0.13;
marbleP.y += sin(p.z*24.0)*0.14;
marbleP.y += sin(p.x*1.2)*0.5;
marbleP.y += sin(p.z*1.4)*0.6;
marbleP.x += sin(p.y*150.0)*0.011;
marbleP.z += sin(p.y*162.0)*0.013;
marbleP.y += sin(p.x*145.0)*0.012;
marbleP.y += sin(p.z*153.0)*0.015;
marbleP.x *= 22.0;
marbleP.z *= 23.0;
marbleP.y *= 11.0;
float marbleAmtB = abs(sin(marbleP.x)+sin(marbleP.y)+sin(marbleP.z))/3.0;
marbleAmtB = pow(1.0-marbleAmtB,9.0);
marbleAmtB = 1.0-(1.0-marbleAmtB*0.3);
float marbleAmt = marbleAmtA + marbleAmtB;
marbleAmt = clamp(marbleAmt,0.0,1.0);
surfaceColor = mix(vec3(0.0,0.8,0.5),vec3(0.70),marbleAmt);
specA = mix(1.0,0.8,marbleAmt);
specP = mix(16.0,28.0,marbleAmt);
}
if (surfaceMaterial == 2) {
vec3 marbleP = p;
vec3 intensityP = p;
float tileSize = 1.0;
if ( ceil(mod(p.x,tileSize*2.0)/tileSize) == ceil(mod(p.z,tileSize*2.0)/tileSize) ) {
surfaceColor = vec3(0.45,0.0,0.0);
marbleP.x *= -1.0;
intensityP.x *= -1.0;
marbleP.z += 1.0;
intensityP.z += 1.0;
} else {
surfaceColor = vec3(0.75,0.75,0.6);
}
specA = 1.0;
specP = 16.0;
marbleP.x += marbleP.z*0.5;
marbleP.z += marbleP.x*0.4;
marbleP.x += sin(marbleP.x* 3.8)*0.125;
marbleP.z += sin(marbleP.z* 3.6)*0.135;
marbleP.x += sin(marbleP.z* 20.0)*0.025;
marbleP.z += sin(marbleP.x* 25.0)*0.025;
marbleP.x += sin(marbleP.z* 40.0)*0.025;
marbleP.z += sin(marbleP.x* 45.0)*0.025;
marbleP.x += sin(marbleP.z*150.0)*0.01;
marbleP.z += sin(marbleP.x*160.0)*0.011;
marbleP *= 36.0;
intensityP.z -= 10000.0;
intensityP.x += intensityP.z*0.3;
intensityP.z += intensityP.x*0.1;
intensityP.x += sin(intensityP.x*1.2)*0.36;
intensityP.z += sin(intensityP.z*1.3)*0.21;
intensityP.x += sin(intensityP.z*2.2)*0.8;
intensityP.z += sin(intensityP.x*2.3)*0.9;
intensityP *= 6.0;
float intensityAmt = (sin(intensityP.x)*sin(intensityP.z))*0.5+0.5;
intensityAmt = 1.0-pow(1.0-intensityAmt,0.5);
float marbleAmt = (sin(marbleP.x)*sin(marbleP.z))*0.5+0.5;
float marbleGrainAmt = marbleAmt;
marbleGrainAmt = 1.0-((1.0-pow(marbleGrainAmt,1.5))*(1.0-intensityAmt)*1.125);
marbleGrainAmt = 1.0-pow(1.0-marbleGrainAmt,5.0);
surfaceColor *= marbleGrainAmt;
specA *= marbleGrainAmt;
float marbleGashAmt = marbleAmt;
marbleGashAmt *= 0.5 + 18.0*intensityAmt;
marbleGashAmt += pow(intensityAmt,2.5)*18.0;
marbleGashAmt = clamp(marbleGashAmt,0.0,1.0);
float marbleGoldAmt = pow(marbleGashAmt,1.0);
float marbleShadeAmt = pow(marbleGashAmt,16.0);
surfaceColor *= marbleShadeAmt;
specA *= marbleShadeAmt;
vec3 myNormalCheat = vec3(
sin( p.x*200.0 + sin(p.z*100.0)*0.5 + sin(p.z*17.0)*(5.0+sin(p.x*20.0)*4.0) )*0.000015,
0.0,
0.0
);
surfaceColor = mix(vec3(1.0,0.9,0.0),surfaceColor,marbleGoldAmt);
specP = mix(256.0,specP,marbleGoldAmt);
specA = mix(1.0,specA,marbleGoldAmt);
difP = mix(6.0,difP,marbleGoldAmt);
normalCheat = mix(myNormalCheat,normalCheat,marbleGoldAmt);
}
if (surfaceMaterial == 3){
float splinters =
pow(abs( ( sin(p.x*100.0)*0.5 + sin(p.y*100.0)*0.5 ) ), 0.1)
*
(sin(p.z*2.0+sin(p.x*10.0)*4.0+sin(p.x*27.0)*3.0)*0.5+0.5);
float waves = sin(
p.z*10.0 +
sin(p.z*3.0 + sin(p.x*11.0)*0.5 )*1.0 +
sin((p.z + sin(p.z*0.5)*5.5)*0.15 + sin(p.x*0.8)*2.0) * 14.0 +
pow(abs(sin((p.x*1.0 + sin(p.x*3.0)*0.5)*25.0)),0.5) * 0.5
);
float grain = splinters * 0.3 + waves * 0.7;
grain = pow(grain*0.5+0.5,0.25);
surfaceColor = mix(vec3(0.2,0.1,0.1),vec3(0.4,0.2,0.05),grain);
specP = mix(30.0,20.0,grain);
specA = grain;
}
vec3 n = vec3(d-room(p-e.xyy,dummyMaterial),
d-room(p-e.yxy,dummyMaterial),
d-room(p-e.yyx,dummyMaterial));
n += normalCheat;
vec3 N = normalize(n);
vec3 pointLightPos = vec3(0.0,2.0,-4.5-fwdDist);
vec3 L = normalize(pointLightPos-p);
float diffuse=max(dot(N,L),0.0);
vec3 H = normalize(L-curCameraRayUnit);
float specular = max(dot(H,N),0.0);
color = pow(diffuse,difP)*surfaceColor + pow(specular,specP)*specA;
float lightDist = (length(pointLightPos-p)) * 0.04;
lightDist = max(0.0,min(1.0,lightDist));
color *= pow(1.0-lightDist, 2.0);
} else {
color = vec3(0.0,0.0,0.0);
}
gl_FragColor = vec4(color,1.0);
}
</script>
<script id="smoke-fs" type="x-shader/x-fragment">
precision mediump float;
uniform float time;
uniform vec3 localCameraPos;
varying vec3 localSurfacePos;
const float pi2 = 3.14152*2.0;
vec4 field(vec3 p){
vec3 morphedP = vec3(
p.x*20.0 + time/200.0
+ sin(p.z*5.0)*(1.0+sin(time/1100.0)*0.5)*10.0
+ sin(p.y*4.0)*(1.0+sin(time/1300.0)*0.5)*10.0
,
p.y*20.0 + time/300.0
+ sin(p.z*5.0)*(1.0+sin(time/1000.0)*0.5)*10.0
+ sin(p.x*4.0)*(1.0+sin(time/1200.0)*0.5)*10.0
,
p.z*20.0 + time/400.0
+ sin(p.x*5.0)*(1.0+sin(time/1400.0)*0.5)*10.0
+ sin(p.y*4.0)*(1.0+sin(time/1500.0)*0.5)*10.0
);
float alpha = (sin(morphedP.x)*0.5+0.5) * (sin(morphedP.y)*0.5+0.5) * (sin(morphedP.z)*0.5+0.5);
vec3 color = vec3(
sin(morphedP.x),
sin(morphedP.y),
sin(morphedP.z)
);
color = (color*0.5+0.5)*alpha;
return vec4(color,alpha);
}
float fadeCurve(float x){
return 1.0-pow(abs(x)/0.5,2.0);
}
void alphaBlend(inout vec4 baseCol, vec4 newCol){
baseCol = baseCol*(1.0-newCol.a) + newCol;
}
float noise(vec3 p){
return sin(
p.x*12345678.0 + p.y*45678912.0 + p.z*78912345.0 +
sin(p.x+p.y+time/1000.0)*14725836.0 + sin(p.y+p.z+time/1000.0)*25836914.0 + sin(p.z+p.x+time/1000.0)*36914725.0
);
}
void main(){
vec3 rayPos = localSurfacePos;
vec3 rayDir = normalize(localCameraPos-localSurfacePos);//BACKWARDS because we're painting inside & doing painter's algorithm!
vec4 fog = vec4(0.0);
for(int i=0; i<200; i++){
rayPos += rayDir*0.01;
if (max(max(abs(rayPos.x),abs(rayPos.y)),abs(rayPos.z)) > 0.51) break;
float squareFade = fadeCurve(rayPos.x)*fadeCurve(rayPos.y)*fadeCurve(rayPos.z);
vec4 fogSamp = field(rayPos);//+rayDir*0.005*noise(rayPos));
alphaBlend(fog,fogSamp*squareFade);
}
gl_FragColor = fog;
}
</script>
<a-scene stats>
<a-assets>
<img crossorigin="anonymous" id="groundTexture" src="https://cdn.aframe.io/a-painter/images/floor.jpg">
<img crossorigin="anonymous" id="skyTexture" src="https://cdn.aframe.io/a-painter/images/sky.jpg">
</a-assets>
<a-entity position="0 0 -1">
<a-box position="0 1.65 0" scale="0.5 0.5 0.5" raytrace="shader:#blob-fs; backside:true;"></a-box>
<a-cylinder radius="0.03" height="2.7" color="#345" segments-height="1" segments-radial="8"></a-cylinder>
<a-cylinder position="0 1.38 0" radius="0.3" height="0.03" color="#345" segments-height="1" segments-radial="48"></a-cylinder>
</a-entity>
<a-entity position="1 0 0" rotation="0 -90 0">
<a-torus position="0 1.65 0" color="#345" radius="0.5" radius-tubular="0.005" segments-tubular="64" segments-radial="6">
<a-circle radius="0.5" segments="16" raytrace="shader:#columns-fs"></a-circle>
</a-torus>
<a-cylinder position="0 0 0" radius="0.01" height="2.3" color="#345" segments-height="1" segments-radial="6"></a-cylinder>
</a-entity>
<a-entity position="-1 0 0" rotation="0 90 0">
<a-box position="0 1.65 0" scale="0.5 0.5 0.5" raytrace="shader:#smoke-fs; transparent:true; backside:true;"></a-box>
<a-box scale="0.5 2.75 0.5" color="#345"></a-box>
</a-entity>
<a-light type="ambient" color="#445451"></a-light>
<a-light type="point" intensity="2" position="2 4 4"></a-light>
<a-sky height="2048" radius="30" src="#skyTexture" theta-length="90" width="2048" segments-height="5" segments-width="8"></a-sky>
<a-plane src="#groundTexture" rotation="-90 0 0" height="100" width="100"></a-plane>
</a-scene>
<!-- GitHub Corner. -->
<a href="https://github.com/omgitsraven/aframe-raytrace-component" class="github-corner">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#222; color:#fff; position: absolute; top: 0; border: 0; right: 0;">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
</svg>
</a>
<style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
<!-- End GitHub Corner. -->
</body>
</html>