import {glx, initPhongUni, updatePhongUni} from './glx.glsl';
/**Render prism extruded from xz polygon, with texture on roof and leteral faces.
* @see glx.boxLayers for a try to shade building floor without the floor texture.
* @param {object=} vparas Visual.paras
* @param {opbject=} vparas.tile tile texture parameters, see test for examples
* @member xglsl.texPrism
* @function
* */
export function texPrism(vparas = {}) {
var ptile = vparas.tile || {};
var layrs = ptile.layers || 1; // with a roof layer
var vtiles = ptile.change ? ' vtiles / float(cx + 1) ' : ' vtiles ';
var boxsize = ptile.box ? `+ vec2( float(${ptile.box[0]}), float(${ptile.box[1]}) )` : '';
// var vUv = vparas.uvScale ? ` (mod(uv * vec2(float(${vparas.uvScale[0]}), float(${vparas.uvScale[1]})), vec2(1.) )) ` : '(uv)';
var uv_vert = vparas.uvScale ? `(uv * vec2(float(${vparas.uvScale[0]}), float(${vparas.uvScale[1]})))` : '(uv)';
const w = ptile.edgeWeight || vparas.edgeWeight;
const edgeWeight = w !== undefined ?
`(float(${w}))` : '(3.4)';
const roofAlpha = `(float(${vparas.whiteAlphas ? vparas.whiteAlphas[0] : 0.7}))`;
const sideAlpha = `(float(${vparas.whiteAlphas ? vparas.whiteAlphas[1] : 0.9}))`;
// const floorAlpha = `(float(${vparas.whiteAlphas ? vparas.whiteAlphas[2] : 0.95}))`
// shadow
var receiveShadow = vparas.dirShadow;
const n_dirLight = '1';
// DESIGN MEMO: sampler2D arry can't work, neither colorArray?
// vxzWeight: the xz plane's color weight (possibility of roof)
return { fragmentShader: `
#define WEIGHT ${edgeWeight}
uniform vec4 u_hue;
uniform sampler2D u_tex0, u_tex1, u_tex2, u_tex3, u_tex4, u_tex5, u_tex6, u_tex7;
uniform sampler2D u_tex[3]; // [roof, lateral, floor]
uniform float now;
uniform float u_lightIntensity;
varying vec2 vUv;
varying vec4 vColor;
varying float va;
varying vec3 P;
varying vec4 cent[${layrs}];
varying vec2 vsize;
varying vec2 vtiles;
varying float vxzWeight;
${glx.box2}
${glx.intenseAlpha}
${glx.fractuv}
${glx.rayPlaneInsec}
${!receiveShadow ? '' : glx.shadow.frag}
float tessellate2( vec2 xz, vec2 c0, vec2 rectSize ) {
vec2 d = xz - c0;
vec2 modxz = mod ( d / rectSize, 2. );
return modxz.x > 1. && modxz.y > 1. || modxz.x < 1. && modxz.y < 1. ?
1. : 1000.;
}
// rasterize functions
// get xz plane box distance color
float boxY(vec3 e, vec3 P, vec3 c0, vec2 size, vec2 tiles, float w) {
vec4 p0d = rayPlaneInsec( e, normalize(P - e), c0, vec3(0., 1., 0.) );
if (p0d.w > 0.) {
float tes = tessellate2( p0d.xz, c0.xz, size * 0.5 / tiles );
float box = box2( p0d.xz - c0.xz, size * 0.5, 0.5 );
box = 1.0/box * w * (1. - va);
tes = 0.4/tes * (1. - va) * ( 1. - abs( sin(now * 0.0005) ) );
return abs(box) * tes + abs(box) * 0.02;
}
else return 0.;
}
vec4 texY(vec3 e, vec3 P, vec3 c0, vec2 size, vec2 tiles, vec2 boader) {
vec4 p0d = rayPlaneInsec( e, normalize(P - e), c0, vec3(0., 1., 0.) );
if (p0d.w > 0.) {
float box = box2( p0d.xz - c0.xz, size * 0.5, 0.5 );
box = 1.0/box * boader.s * (1. - va);
return texture2D( u_tex0, (.5 - (p0d.xz - c0.xz) / size) );
}
else return vec4(0.);
}
vec4 mainImage( in vec2 fragCoord ) {
float col = 0.;
// floors
for (int cx = 0; cx < ${layrs}; cx++)
col += boxY(cameraPosition, P, cent[cx].xyz, vsize, ${vtiles} * 0.5, WEIGHT);
vec4 col4 = u_hue * col;
// upward base (roof)
if (vxzWeight > 0.9) {
col4 = mix(col4,
texY(cameraPosition, P, cent[${layrs} - 1].xyz, vsize, vtiles * 0.5, vec2(WEIGHT)),
${roofAlpha});
}
return col4;
}
void main() {
gl_FragColor += mainImage(gl_FragCoord.xy);
if (vxzWeight <= 0.9) {
gl_FragColor = mix(gl_FragColor, texture2D(u_tex1, fractuv(vUv)),
${sideAlpha});
}
// gl_FragColor = mix( vColor, gl_FragColor, intenseAlpha(u_lightIntensity) );
gl_FragColor.xyz *= u_lightIntensity;
${!receiveShadow ? '' : 'gl_FragColor.xyz *= shadow();'}
gl_FragColor = mix( gl_FragColor, vColor, intenseAlpha(u_lightIntensity) );
}`,
// FIXME this is a bug, vColor can't got from vertex.
// a_box - xz: floor size, y: floor height ( layer's offset )
// a_loc - prism center in model, y: height
vertexShader: `
uniform vec3 wpos;
uniform float u_shininess;
uniform vec4 u_color; // diffuse color
uniform vec3 u_ambientColor;
uniform vec3 u_specularColor;
uniform vec3 u_lightColor;
uniform vec3 u_lightPos;
uniform float u_lightIntensity;
${glx.u_alpha}
uniform mat4 directionalShadowMatrix[ ${n_dirLight} ];
attribute vec3 a_box;
attribute vec2 a_tiles; // x-div, z-div
attribute vec3 a_loc;
varying vec2 vUv;
varying vec4 vColor;
varying float va;
varying vec3 P;
varying vec4 cent[${layrs}];
varying vec2 vsize;
varying vec2 vtiles;
varying float vxzWeight;
${glx.phongLight}
${glx.buildingAlpha}
${!receiveShadow ? '' : glx.shadow.setShadowCoords(1)}
void main() {
vUv = ${uv_vert};
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
vsize = a_box.xz ${boxsize};
vtiles = a_tiles; // + vec2(1, 1);
P = (worldPosition).xyz;
va = buildingAlpha(cameraPosition, P, normal);
vxzWeight = dot(vec3(0., 1., 0.), normal);
for (int i = 0; i < ${layrs} - 1; i++){
float h = a_box.y / float(${layrs});
if (h == 0.) h = 10.;
vec3 loc = vec3(a_loc.x, 0, a_loc.z) + vec3(0., h * float(i) * 0.5, 0.);
cent[i] = modelMatrix * vec4(loc, 1.);
}
cent[${layrs} - 1] = modelMatrix * vec4(a_loc[0], a_box[1], a_loc[2], 1.); // roof
gl_Position = projectionMatrix * viewMatrix * worldPosition;
vColor = phongLight(normal, u_lightPos, cameraPosition, worldPosition.xyz,
u_ambientColor.xyz, u_color.xyz, u_specularColor.xyz, u_shininess
) * u_lightIntensity;
${!receiveShadow ? '' : 'setShadowCoords(directionalShadowMatrix, worldPosition)'};
} `
// FIXME this is a bug, vColor can't got from vertex.
}
}
texPrism.initUniform = initPhongUni;
texPrism.updateUniform = updatePhongUni;
// color alpha hilighted at corner
function texPrism_alpha_corner(vparas) {
var ptile = vparas.tile || {};
var layrs = ptile.layers || 3;
var vtiles = ptile.change ? ' vtiles / float(cx + 1) ' : ' vtiles ';
return { fragmentShader: `
#define WEIGHT 3.4
uniform vec4 u_hue,
uniform sampler2D u_basetex;
uniform sampler2D u_lateraltex;
uniform float now;
varying vec3 P;
varying vec4 cent[${layrs}];
varying float va;
varying vec2 vsize;
varying vec2 vtiles;
${glx.box2}
${glx.rayPlaneInsec}
// filter p with base texture
float baseTex(vec2 p, vec2 box, float r) {
float d = box2(p, box, r);
if (d <= 0.) {
vec2 modxz = mod ( p, box * 0.5 / vtiles );
return d * (texture2D ( u_basetex, modxz / box )).a;
}
else return 0.0;
}
float tessellate2( vec2 xz, vec2 c0, vec2 rectSize ) {
vec2 d = xz - c0;
vec2 modxz = mod ( d / rectSize, 2. );
return modxz.x > 1. && modxz.y > 1. || modxz.x < 1. && modxz.y < 1. ?
1. : 1000.;
}
// rasterize functions
// get xz plane box distance color
float boxY(vec3 e, vec3 P, vec3 c0, vec2 size, vec2 tiles, float w) {
vec4 p0d = rayPlaneInsec( e, normalize(P - e), c0, vec3(0., 1., 0.) );
if (p0d.w > 0.) {
float tes = tessellate2( p0d.xz, c0.xz, size * 0.5 / tiles );
float d = baseTex( p0d.xz, size * 0.5, 5. );
d = 1.0/d * w * (1. - va);
tes = 0.4/tes * (1. - va) * ( 1. - abs( sin(now * 0.001) ) );
return abs(d) * tes + abs(d) * 0.02;
}
else return 0.;
}
vec4 mainImage( in vec2 fragCoord ) {
float col = boxY(cameraPosition, P, cent[0].xyz, vec2(280., 92.), vec2(6., 3.), WEIGHT);
// return vec4(0., col * 0.2, 0.8, col);
return u_hue * col;
}
void main() {
gl_FragColor += mainImage(gl_FragCoord.xy);
gl_FragColor.a += va;
}`,
vertexShader: `
uniform vec3 wpos;
attribute vec3 a_box;
attribute vec2 a_tiles;
attribute vec3 a_prevert;
varying vec3 P;
varying vec4 cent[${layrs}];
varying float va;
varying vec2 boxsize;
varying vec2 vtiles;
${glx.buildingAlpha}
void main() {
// gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
P = worldPosition.xyz;
vec4 _p = modelMatrix * vec4(a_prevert, 1.0);
vec3 n = cross(P - _p.xyz, normal);
va = buildingAlpha(cameraPosition, P, normal);
vtiles = a_tiles + vec2(3, 1.5);
for (int i = 0; i < ${layrs}; i++){
// cent[i] = modelMatrix * vec4(wpos + offsets[i], 1.);
// cent[i] = modelMatrix * vec4(0.);
float h = a_box.y / float(${layrs});
if (h == 0.) h = 10.;
cent[i] = modelMatrix * vec4(0., h * float(i) - a_box.y * 0.5, 0., 1.);
}
gl_Position = projectionMatrix * viewMatrix * worldPosition;
} `
}
}
// works for line but hard to find segments, see
// https://homepage.univie.ac.at/Franz.Vesely/notes/hard_sticks/hst/hst.html
function texPrism_line_dist(vparas) {
var layrs = vparas.layars || 3;
return { fragmentShader: `
#define WEIGHT 0.4
uniform sampler2D u_tex;
varying vec2 vUv;
varying vec3 P;
varying vec3 P0;
varying vec3 P1;
varying vec3 P2;
varying vec3 P3;
varying vec4 cent[${layrs}];
// https://math.stackexchange.com/questions/2213165/find-shortest-distance-between-lines-in-3d
// 𝐧 = 𝐞1 × 𝐞2 = (−20, −11, −26)
// rasterize functions
float line(vec3 e, vec3 P, vec3 p0, vec3 p1, float w) {
vec3 e2 = p1 - p0;
vec3 e1 = P - e;
vec3 n = normalize(cross(e1, e2));
float dist = dot(n, e - p0);
dist = 1.0/dist * WEIGHT * w;
// return min(dist * dist, 1.0);
return abs(dist);
}
vec4 mainImage( in vec2 fragCoord ) {
float line_width = 0.4;
float col = line(cameraPosition, P, P0, P1, line_width);
col += line(cameraPosition, P, P2, P3, line_width);
return vec4(col);
}
void main() {
gl_FragColor += mainImage(gl_FragCoord.xy);
gl_FragColor.g += 0.7;
gl_FragColor.a += 0.2;
}`,
vertexShader: `
uniform vec3 wpos;
uniform vec3 offsets[${layrs}];
uniform vec3 orbScale;
attribute vec3 a_tan;
attribute vec3 a_pos;
varying vec2 vUv;
varying vec3 P;
varying vec3 P0;
varying vec3 P1;
varying vec3 P2;
varying vec3 P3;
varying vec3 vscale;
varying vec4 cent[${layrs}];
void main() {
// vUv = uv;
// gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
P = worldPosition.xyz;
vscale = orbScale;
for (int i = 0; i < ${layrs}; i++){
// cent[i] = modelMatrix * vec4(wpos + offsets[i], 1.);
cent[i] = worldPosition;
}
gl_Position = projectionMatrix * viewMatrix * worldPosition;
vec4 v4 = modelMatrix * vec4( vec3(-150., 0., -50.), 1.0 );
P0 = v4.xyz;
v4 = modelMatrix * vec4( vec3(150., 0., -50.), 1.0 );
P1 = v4.xyz;
v4 = modelMatrix * vec4( vec3(0., 150., 50.), 1.0 );
P2 = v4.xyz;
v4 = modelMatrix * vec4( vec3(0., -150., 50.), 1.0 );
P3 = v4.xyz;
v4 = projectionMatrix * modelViewMatrix * vec4(uv.s, uv.t, 0., 1.0);
vUv = v4.xy; // / v4.z;
} `
}
}