Skip to content

Commit

Permalink
bake lighting, add mobile devices support
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementCariou committed Aug 22, 2021
1 parent 45e8c1f commit 233cdcb
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 118 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"gl-mat4": "^1.2.0",
"gl-vec3": "^1.1.3",
"pointer-lock": "^0.0.4",
"regl": "^1.7.0"
"regl": "^1.7.0",
"stats.js": "^0.17.0"
},
"devDependencies": {
"@babel/core": "^7.15.0",
Expand Down
Binary file added res/floor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/floor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions res/marble.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Run this on shadertoy and do a screenshot to generate the floor texture

// https://www.shadertoy.com/view/4sfGzS
float hash(vec3 p) {
p = fract( p*0.3183099+.1 );
p *= 17.0;
return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
}
float noise( in vec3 x ) {
vec3 i = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
return mix(mix(mix( hash(i+vec3(0,0,0)), hash(i+vec3(1,0,0)),f.x),
mix( hash(i+vec3(0,1,0)), hash(i+vec3(1,1,0)),f.x),f.y),
mix(mix( hash(i+vec3(0,0,1)), hash(i+vec3(1,0,1)),f.x),
mix( hash(i+vec3(0,1,1)), hash(i+vec3(1,1,1)),f.x),f.y),f.z);
}

#define fbm2(g) fbm3(vec3(g, 0.0))
float fbm3(vec3 p) {
float f = 0.0, x;
for(int i = 1; i <= 9; ++i) {
x = exp2(float(i));
f += (noise(p * x) - 0.5) / x;
}
return f;
}

vec3 marble(vec2 p) {
const float N = 1.005; // grid ratio
// filter kernel
vec2 w = max(abs(dFdx(p)), abs(dFdy(p)));
vec2 a = p + 0.5*w;
vec2 b = p - 0.5*w;
vec2 i = (floor(a)+min(fract(a)*N,1.0)-
floor(b)-min(fract(b)*N,1.0))/(N*w);

vec3 pat=mix(vec3(0.82,0.8,0.8)*0.4,vec3(0.82,0.82,0.8)*0.7,1.0-smoothstep(0.4,0.8,0.5+fbm2(floor(p)*2.0+p*1.0+cos(p.yx*2.0)*0.4)))+
vec3(max(0.0,fbm2(p*0.7)*1.0))+vec3(smoothstep(0.2,0.3,fbm2(-p)))*0.2;

float lineWidth = 0.001;
p = mod(p + vec2(0.5), vec2(1.0));
p = smoothstep(p, vec2(0.5+lineWidth), vec2(0.5-lineWidth)) * smoothstep(p, vec2(0.5-lineWidth), vec2(0.5+lineWidth));
return clamp(p.x * p.y, 0.3, 1.0) * pat;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/1024.0;

// Time varying pixel color
vec3 col = marble(uv.xy*8.0);

// Output to screen
fragColor = vec4(col,1.0);
}
Binary file added res/wall.blend
Binary file not shown.
Binary file added res/wall.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/wall.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 40 additions & 28 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,44 @@
'use strict';

var useReflexion = true;
var debug = false;

if (navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i)) {
document.body.innerText = "This project doesn't work properly on mobile devices";
throw new Error("mobile device");
/*document.body.innerText = "This project doesn't work properly on mobile devices";
throw new Error("mobile device");*/
useReflexion = false;
}

const mat4 = require('gl-mat4');

const Stats = require('stats.js');
var stats = new Stats();
stats.showPanel(0);
if(debug){
document.body.appendChild( stats.dom );
}

let regl, map, drawMap, placement, drawPainting, fps;
try {
regl = require('regl')({
extensions: [
//'angle_instanced_arrays',
'OES_element_index_uint',
'OES_standard_derivatives'
],
optionalExtensions: [
//'oes_texture_float',
'EXT_texture_filter_anisotropic'
],
attributes: { alpha : false }
});

map = require('./map')();
drawMap = require('./mesh')(regl, map);
placement = require('./placement')(regl, map);
drawPainting = require('./painting')(regl);
fps = require('./fps')(map);
} catch (e) {
document.body.innerText = "This project doesn't work on certain browsers";
throw e;
}
regl = require('regl')({
extensions: [
//'angle_instanced_arrays',
'OES_element_index_uint',
'OES_standard_derivatives'
],
optionalExtensions: [
//'oes_texture_float',
'EXT_texture_filter_anisotropic'
],
attributes: { alpha : false }
});

map = require('./map')();
const mesh = require('./mesh');
drawMap = mesh(regl, map, useReflexion);
placement = require('./placement')(regl, map);
drawPainting = require('./painting')(regl);
fps = require('./fps')(map);

const fovY = Math.PI / 3;
const proj = [];
Expand Down Expand Up @@ -65,6 +73,7 @@ regl.frame(({
viewportWidth,
viewportHeight
}) => {
stats.begin();
const fovx = 2 * Math.atan(Math.tan(fovY * 0.5) * viewportWidth / viewportHeight);
fps.tick({
time
Expand All @@ -75,11 +84,14 @@ regl.frame(({
depth: 1
});
context(() => {
reflexion(() => {
drawMap();
drawPainting(placement.batch());
});
if(useReflexion) {
reflexion(() => {
drawMap();
drawPainting(placement.batch());
});
}
drawMap();
drawPainting(placement.batch());
});
stats.end();
});
118 changes: 33 additions & 85 deletions src/mesh.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,26 @@
'use strict';

module.exports = (regl, data) => {
const loadTexture = async (texture, url) => {
const result = await fetch(url);
const blob = await result.blob();
const data = await createImageBitmap(blob);
texture({data,
wrapS: 'repeat',
wrapT: 'repeat'
});
};

module.exports = (regl, data, useReflexion) => {
const wallTexture = regl.texture();
const floorTexture = regl.texture();
loadTexture(wallTexture, "res/wall.jpg");
loadTexture(floorTexture, "res/floor.jpg");
return regl({
frag: `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
precision lowp float;
varying vec3 v_pos, v_relativepos, v_normal;
// https://www.shadertoy.com/view/4sfGzS
float hash(vec3 p) {
p = fract( p*0.3183099+.1 );
p *= 17.0;
return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
}
float noise( in vec3 x ) {
vec3 i = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
return mix(mix(mix( hash(i+vec3(0,0,0)), hash(i+vec3(1,0,0)),f.x),
mix( hash(i+vec3(0,1,0)), hash(i+vec3(1,1,0)),f.x),f.y),
mix(mix( hash(i+vec3(0,0,1)), hash(i+vec3(1,0,1)),f.x),
mix( hash(i+vec3(0,1,1)), hash(i+vec3(1,1,1)),f.x),f.y),f.z);
}
#define fbm2(g) fbm3(vec3(g, 0.0))
float fbm3(vec3 p) {
float f = 0.0, x;
for(int i = 1; i <= 9; ++i) {
x = exp2(float(i));
f += (noise(p * x) - 0.5) / x;
}
return f;
}
// https://iquilezles.org/www/articles/filterableprocedurals/filterableprocedurals.htm
vec3 marble(vec2 p) {
const float N = 1.005; // grid ratio
// filter kernel
vec2 w = max(abs(dFdx(p)), abs(dFdy(p)));
vec2 a = p + 0.5*w;
vec2 b = p - 0.5*w;
vec2 i = (floor(a)+min(fract(a)*N,1.0)-
floor(b)-min(fract(b)*N,1.0))/(N*w);
vec3 pat=mix(vec3(1.0,1.0,0.8)*0.4,vec3(1.0,1.0,0.8)*0.7,1.0-smoothstep(0.4,0.8,0.5+fbm2(floor(p)*2.0+p*1.0+cos(p.yx*2.0)*0.4)))+
vec3(max(0.0,fbm2(p*0.7)*1.0))+vec3(smoothstep(0.2,0.3,fbm2(-p)))*0.2;
return (i.x*i.y*2.0-1.0) * pat;
}
float border(float y) {
const float h = 0.04;
const float N = 1.0 + h;
y = y / 8.0 - h / 2.0;
// filter kernel
float w = max(abs(dFdx(y)), abs(dFdy(y)));
float a = y + 0.5*w;
float b = y - 0.5*w;
float i = (floor(a)+min(fract(a)*N,1.0)-
floor(b)-min(fract(b)*N,1.0))/(N*w);
return i;
}
uniform sampler2D wallTexture;
uniform sampler2D floorTexture;
vec3 hue2rgb(float h) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
Expand All @@ -69,38 +29,21 @@ module.exports = (regl, data) => {
}
void main() {
vec3 totalLight = vec3(0.1);
float pattern = 0.05*noise(2.0*v_pos*vec3(40.0,10.0,40.0))
*noise(2.0*v_pos*vec3(10.0,40.0,10.0))+0.95;
for(float x = 0.0; x < 2.0; x++){
for(float z = 0.0; z < 2.0; z++){
vec3 fragPos = mod(v_pos+vec3(4.0,0.0,4.0),8.0);
vec3 lightPos = vec3(x*8.0, 2.0, z*8.0);
vec3 p = floor((v_pos+lightPos-vec3(4.0,0.0,4.0))/8.0);
vec3 col = vec3(pattern * (0.1*mod(p.x,2.0)+0.9)); //border separation contrast
vec3 lightDir = lightPos - fragPos;
float d = length(lightDir);
float att = mix(0.2*d*d, 5.0 + 3.0*d, abs(v_normal.y));
float diff = max(dot(v_normal, normalize(lightDir)), 0.0);
totalLight += diff * col / att;
}
}
totalLight = mix(totalLight, vec3(0.19 * pattern), step(0.5,-v_normal.y));
totalLight *= hue2rgb(0.5 + (v_pos.x + v_pos.z) / 160.0); //color variation
vec3 totalLight = texture2D(wallTexture, vec2(v_pos.x + v_pos.z, 7.0-v_pos.y)/8.0).rgb;
float dist = length(v_relativepos);
totalLight = mix(totalLight, vec3(90.0,92.0,95.0)/255.0, step(6.99, v_pos.y));
totalLight *= mix(0.7, 1.0, smoothstep(0.1, 0.12, v_pos.y));
totalLight *= abs(v_normal.x)/64.0 + 1.0;
if(v_normal.y > 0.0) {
totalLight *= mix(vec3(1.3), vec3(1.9), marble(v_pos.xz + vec2(0.5)));
} else if(v_normal.y == 0.0) {
totalLight *= mix(0.6, 1.0, border(v_pos.y));
totalLight = 0.47+0.1*texture2D(floorTexture, v_pos.xz / 8.0).rgb;
}
float dist = length(v_relativepos);
totalLight *= smoothstep(130.,0.,dist); // fog
totalLight *= (0.5 + 0.5*hue2rgb(0.5 + (v_pos.x + v_pos.z) / 160.0)); //color variation
float alpha = .98+smoothstep(150.,0.,dist)-v_normal.y; // reflexion
totalLight = pow(totalLight, vec3(1.0/2.2));
gl_FragColor = vec4(totalLight, alpha);
gl_FragColor = vec4(totalLight, ${useReflexion ? "alpha" : "1.0"});
}`,

vert: `
precision mediump float;
precision highp float;
uniform mat4 proj, view;
attribute vec3 position, normal;
varying vec3 v_pos, v_relativepos, v_normal;
Expand All @@ -119,12 +62,17 @@ module.exports = (regl, data) => {
normal: data.normal
},

blend: {
blend: useReflexion ? {
enable: true,
func: {
src: 'src alpha',
dst: 'one minus src alpha'
},
} : {},

uniforms: {
wallTexture,
floorTexture
},

elements: new Uint32Array(data.elements)
Expand Down
9 changes: 6 additions & 3 deletions src/painting.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = (regl) => {
const painting =
regl({
frag: `
precision mediump float;
precision lowp float;
uniform sampler2D tex;
varying vec3 uv;
Expand Down Expand Up @@ -38,7 +38,7 @@ module.exports = (regl) => {
gl_FragColor = mix(vec4(0.,0.,0.,shadowAlpha), vec4(col,1.), paintingMask);
}`,
vert: `
precision mediump float;
precision highp float;
uniform mat4 proj, view, model;
uniform float yScale;
attribute vec3 pos;
Expand Down Expand Up @@ -73,7 +73,10 @@ module.exports = (regl) => {
1, 0, 5, 4, 5, 0, //Contour
3, 1, 7, 5, 7, 1,
0, 2, 4, 6, 4, 2,
8, 9, 10, 11, 10, 9, //Shadow
8, 9, 4, 5, 4, 9, //Shadow
9, 11, 5, 7, 5, 11,
11, 10, 7, 6, 7, 10,
10, 8, 6, 4, 6, 8,
],

uniforms: {
Expand Down
2 changes: 1 addition & 1 deletion src/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ module.exports = {
gl_FragColor = vec4(0,0,0, c);
}`,
vert: `
precision mediump float;
precision highp float;
uniform mat4 proj, view, model;
uniform float yScale;
attribute vec2 pos;
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3975,6 +3975,11 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"

stats.js@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/stats.js/-/stats.js-0.17.0.tgz#b1c3dc46d94498b578b7fd3985b81ace7131cc7d"
integrity sha1-scPcRtlEmLV4t/05hbgaznExzH0=

"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
Expand Down

0 comments on commit 233cdcb

Please sign in to comment.