Created
April 1, 2023 08:55
-
-
Save asc0910/bde4e01e364e2de7bd3badd940b8ff12 to your computer and use it in GitHub Desktop.
mapping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url("https://webglfundamentals.org/webgl/resources/webgl-tutorials.css"); | |
body { | |
margin: 0; | |
} | |
#canvas { | |
width: 3000px; | |
height: 3000px; | |
display: block; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<canvas id="canvas"></canvas> | |
<!-- vertex shader --> | |
<script src="https://www.lactame.com/lib/image-js/0.21.2/image.min.js"></script> | |
<script id="vertex-shader-2d" type="x-shader/x-vertex"> | |
attribute vec2 a_position; | |
attribute vec2 a_texCoord; | |
uniform vec2 u_resolution; | |
varying vec2 v_texCoord; | |
void main() { | |
// convert the rectangle from pixels to 0.0 to 1.0 | |
vec2 zeroToOne = a_position / u_resolution; | |
// convert from 0->1 to 0->2 | |
vec2 zeroToTwo = zeroToOne * 2.0; | |
// convert from 0->2 to -1->+1 (clipspace) | |
vec2 clipSpace = zeroToTwo - 1.0; | |
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); | |
// pass the texCoord to the fragment shader | |
// The GPU will interpolate this value between points. | |
v_texCoord = a_texCoord; | |
} | |
</script> | |
<!-- fragment shader --> | |
<script id="fragment-shader-2d" type="x-shader/x-fragment"> | |
precision highp float; | |
// our textures | |
uniform sampler2D artwork; | |
uniform sampler2D uv; | |
uniform sampler2D base; | |
uniform sampler2D gloss; | |
uniform sampler2D mask; | |
uniform sampler2D background; | |
uniform float width; | |
uniform float height; | |
uniform float glossFactor; | |
// the texCoords passed in from the vertex shader. | |
varying vec2 v_texCoord; | |
vec4 getColor(vec2 p, float dx, float dy) { | |
vec2 coord = vec2(p.x + dx / width, p.y + dy / height); | |
vec4 color1 = texture2D(uv, coord); | |
float u = (floor(color1.r * 255.0) * 256.0 + floor(color1.g * 255.0)) / 65536.0; | |
float v = (floor(color1.b * 255.0) * 256.0 + floor(color1.a * 255.0)) / 65536.0; | |
float eps = 0.00001; | |
vec4 result; | |
if (abs(u) > eps && abs(v) > eps) | |
return texture2D(artwork, vec2(u, v)); | |
else | |
return vec4(0, 0, 0, -1); | |
} | |
highp vec4 blend(vec4 a, vec4 b) { | |
if (a.a <= 0.0 && b.a <= 0.0) { | |
return (a * a.a + b * (1.0 - a.a) * b.a); | |
} | |
float ta = a.a + b.a - a.a * b.a; | |
vec4 ret = (a * a.a + b * (1.0 - a.a) * b.a) / ta; | |
ret.a = ta; | |
return ret; | |
} | |
void main() { | |
vec2 coord = vec2(v_texCoord.x, v_texCoord.y); | |
vec4 result = getColor(coord, 0.0, 0.0); | |
if (result.a < 0.0) { | |
result = vec4(0, 0, 0, 0); | |
float cnt = 0.0; | |
for (float dx = -1.0; dx < 2.0; dx += 1.0) { | |
for (float dy = -1.0; dy < 2.0; dy += 1.0) { | |
vec4 color = getColor(coord, dx, dy); | |
if (color.a > 0.0) { | |
cnt += 1.0; | |
result += color; | |
} | |
} | |
} | |
if (cnt > 0.0) { | |
result = result / cnt; | |
} | |
} | |
vec4 glossu = texture2D(gloss, coord); | |
float masku = texture2D(mask, coord).a; | |
if (masku <= 0.5) { | |
float cnt = 0.0; | |
float sum = 0.0; | |
for (float dx = -2.0; dx < 3.0; dx += 1.0) { | |
for (float dy = -2.0; dy < 3.0; dy += 1.0) { | |
vec4 d = texture2D(mask, vec2(v_texCoord.x + dx / width, v_texCoord.y + dy / height)); | |
if (d.a > 0.0) { | |
cnt += 1.0; | |
sum += 1.0; | |
} | |
} | |
} | |
if (cnt >= 4.0) { | |
masku = 1.0; | |
} else if (cnt > 0.0) { | |
masku = sum / cnt; | |
} | |
} | |
result = result * masku; | |
vec4 baseu = texture2D(base, coord); | |
float glossv = glossu.r; | |
float glossa = glossu.a; | |
result = result * baseu; | |
if (glossa >= 0.0) { | |
float a = result.a; | |
result = result + vec4(glossv, glossv, glossv, 1) - result * glossv; | |
result.a = a; | |
} | |
result = blend(result, baseu); | |
gl_FragColor = result; | |
} | |
</script> | |
<script id="fragment-shader-2d-blur" type="x-shader/x-fragment"> | |
precision highp float; | |
// our textures | |
uniform sampler2D inputa; | |
uniform sampler2D zdepth; | |
uniform float width; | |
uniform float height; | |
uniform float focus; | |
uniform float strength; | |
// the texCoords passed in from the vertex shader. | |
varying vec2 v_texCoord; | |
vec4 getColor(vec2 p, float dx, float dy) { | |
vec2 coord = vec2(p.x + dx / width, p.y + dy / height); | |
return texture2D(inputa, coord); | |
} | |
void main() { | |
vec4 result = getColor(v_texCoord, 0.0, 0.0); | |
float zdepthu = texture2D(zdepth, v_texCoord).r; | |
float Size = abs((focus - zdepthu)) * strength - 0.5; | |
float weight = 1.0; | |
if (Size > 0.0) { | |
float sigma = Size; | |
for (float dx = -10.0; dx <= 10.0; dx += 1.0) { | |
for (float dy = -10.0; dy <= 10.0; dy += 1.0) { | |
float w = 1.0 / sqrt(6.28 * sigma * sigma) * exp(- (dx * dx + dy * dy) / (2.0 * sigma * sigma)); | |
result += w * getColor(v_texCoord, dx, dy); | |
weight += w; | |
} | |
} | |
result /= weight; | |
} | |
gl_FragColor = result; | |
} | |
</script> | |
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script> | |
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script> | |
<script src="https://www.lactame.com/lib/image-js/0.21.2/image.min.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
const assets = { | |
artwork: 'https://res.cloudinary.com/casestry-com/image/upload/v1677097709/test/Custom_iwytor.png', | |
base: 'https://res.cloudinary.com/casestry-com/image/upload/v1680338078/test3/base_cfkxxf.png', | |
gloss: 'https://res.cloudinary.com/casestry-com/image/upload/v1680338078/test3/gloss_sv8a3d.png', | |
mask: 'https://res.cloudinary.com/casestry-com/image/upload/v1680338077/test3/mask_vedkjc.png', | |
uv: 'https://res.cloudinary.com/casestry-com/image/upload/v1680338078/test3/uv_qhioig.png', | |
zdepth: 'https://res.cloudinary.com/casestry-com/image/upload/v1677092667/test/zdepth_vnhyk4.png', | |
} | |
const focus = 1.0 | |
const strength = 8; | |
async function loadImage(url) { | |
return new Promise((resolve) => { | |
var image = new Image(); | |
requestCORSIfNotSameOrigin(image, url) | |
image.src = url; | |
image.onload = () => { | |
resolve(image) | |
}; | |
}) | |
} | |
async function loadImage64(url) { | |
const image = await IJS.Image.load(url); | |
const data = new Uint8Array(image.height * image.width * 4); | |
for (let i = 0; i < image.height * image.width; i += 1) { | |
data[i * 4] = Math.floor(image.data[i * 4] / 256); | |
data[i * 4 + 1] = image.data[i * 4] % 256; | |
data[i * 4 + 2] = Math.floor(image.data[i * 4 + 1] / 256); | |
data[i * 4 + 3] = image.data[i * 4 + 1] % 256; | |
} | |
const newImage = new IJS.Image(image.width, image.height, data, { kind: 'RGBA' }); | |
return newImage.getCanvas(); | |
} | |
async function loadImage64_1(url) { | |
const image = await IJS.Image.load(url); | |
const canvas = document.createElement('canvas'); | |
canvas.width = image.width; | |
canvas.height = image.height; | |
const ctx = canvas.getContext('2d'); | |
const imgData = ctx.createImageData(image.width, image.height); | |
for (let i = 0; i < image.height * image.width; i += 1) { | |
imgData.data[i * 4] = Math.floor(image.data[i * image.channels] / 256); | |
imgData.data[i * 4 + 1] = image.data[i * image.channels] % 256; | |
imgData.data[i * 4 + 2] = Math.floor(image.data[i * image.channels + 1] / 256); | |
imgData.data[i * 4 + 3] = image.data[i * image.channels + 1] % 256; | |
} | |
return imgData; | |
} | |
const a5Width = 1748; | |
const a5Height = 2480; | |
async function main() { | |
const artwork = await loadImage(assets.artwork) | |
const base = await loadImage(assets.base); | |
const uv = await loadImage64_1(assets.uv); | |
const gloss = await loadImage(assets.gloss); | |
const mask = await loadImage(assets.mask); | |
const zdepth = await loadImage(assets.zdepth); | |
const canvas = render([artwork, base, uv, gloss, mask]) | |
// blur([canvas, zdepth]) | |
} | |
var documentCanvas = document.querySelector('#canvas'); | |
function blur(images) { | |
var canvas = documentCanvas; | |
canvas.width = images[1].width; | |
canvas.height = images[1].height; | |
var gl = canvas.getContext("webgl"); | |
if (!gl) { | |
return; | |
} | |
// setup GLSL program | |
var program = twgl.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d-blur"]); | |
gl.useProgram(program); | |
// look up where the vertex data needs to go. | |
var positionLocation = gl.getAttribLocation(program, "a_position"); | |
var texcoordLocation = gl.getAttribLocation(program, "a_texCoord"); | |
// Create a buffer to put three 2d clip space points in | |
var positionBuffer = gl.createBuffer(); | |
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Set a rectangle the same size as the image. | |
setRectangle(gl, 0, 0, canvas.width, canvas.height); | |
// provide texture coordinates for the rectangle. | |
var texcoordBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
0.0, 0.0, | |
1.0, 0.0, | |
0.0, 1.0, | |
0.0, 1.0, | |
1.0, 0.0, | |
1.0, 1.0, | |
]), gl.STATIC_DRAW); | |
// create 2 textures | |
var textures = []; | |
for (var ii = 0; ii < 2; ++ii) { | |
var texture = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
// Set the parameters so we can render any size image. | |
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); | |
// Upload the image into the texture. | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, images[ii]); | |
// add the texture to the array of textures. | |
textures.push(texture); | |
} | |
// lookup uniforms | |
var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); | |
// lookup the sampler locations. | |
var inputLocation = gl.getUniformLocation(program, "inputa"); | |
var zdepthLocation = gl.getUniformLocation(program, "zdepth"); | |
var widthLocation = gl.getUniformLocation(program, "width"); | |
var heightLocation = gl.getUniformLocation(program, "height"); | |
var focusLocation = gl.getUniformLocation(program, "focus"); | |
var strengthLocation = gl.getUniformLocation(program, "strength"); | |
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); | |
// Clear the canvas | |
gl.clearColor(0, 0, 0, 0); | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
// Tell it to use our program (pair of shaders) | |
gl.useProgram(program); | |
// Turn on the position attribute | |
gl.enableVertexAttribArray(positionLocation); | |
// Bind the position buffer. | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER) | |
var size = 2; // 2 components per iteration | |
var type = gl.FLOAT; // the data is 32bit floats | |
var normalize = false; // don't normalize the data | |
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0; // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
positionLocation, size, type, normalize, stride, offset); | |
// Turn on the texcoord attribute | |
gl.enableVertexAttribArray(texcoordLocation); | |
// bind the texcoord buffer. | |
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); | |
// Tell the texcoord attribute how to get data out of texcoordBuffer (ARRAY_BUFFER) | |
var size = 2; // 2 components per iteration | |
var type = gl.FLOAT; // the data is 32bit floats | |
var normalize = false; // don't normalize the data | |
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0; // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
texcoordLocation, size, type, normalize, stride, offset); | |
// set the resolution | |
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height); | |
// set which texture units to render with. | |
gl.uniform1i(inputLocation, 0); // texture unit 0 | |
gl.uniform1i(zdepthLocation, 1); // texture unit 1 | |
gl.uniform1f(widthLocation, gl.canvas.width); | |
gl.uniform1f(heightLocation, gl.canvas.height); | |
gl.uniform1f(focusLocation, focus); | |
gl.uniform1f(strengthLocation, strength); | |
// Set each texture unit to use a particular texture. | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, textures[0]); | |
gl.activeTexture(gl.TEXTURE1); | |
gl.bindTexture(gl.TEXTURE_2D, textures[1]); | |
// Draw the rectangle. | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
return canvas; | |
} | |
function render(images) { | |
var starttime = Date.now(); | |
// Get A WebGL context | |
/** @type {HTMLCanvasElement} */ | |
var canvas = document.getElementById("canvas"); | |
canvas.width = images[1].width; | |
canvas.height = images[1].height; | |
var gl = canvas.getContext("webgl"); | |
if (!gl) { | |
return; | |
} | |
// setup GLSL program | |
var program = twgl.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]); | |
gl.useProgram(program); | |
// look up where the vertex data needs to go. | |
var positionLocation = gl.getAttribLocation(program, "a_position"); | |
var texcoordLocation = gl.getAttribLocation(program, "a_texCoord"); | |
// Create a buffer to put three 2d clip space points in | |
var positionBuffer = gl.createBuffer(); | |
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Set a rectangle the same size as the image. | |
setRectangle(gl, 0, 0, canvas.width, canvas.height); | |
// provide texture coordinates for the rectangle. | |
var texcoordBuffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
0.0, 0.0, | |
1.0, 0.0, | |
0.0, 1.0, | |
0.0, 1.0, | |
1.0, 0.0, | |
1.0, 1.0, | |
]), gl.STATIC_DRAW); | |
// create 2 textures | |
var textures = []; | |
for (var ii = 0; ii < 5; ++ii) { | |
var texture = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
// Set the parameters so we can render any size image. | |
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); | |
// Upload the image into the texture. | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, images[ii]); | |
// add the texture to the array of textures. | |
textures.push(texture); | |
} | |
// lookup uniforms | |
var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); | |
// lookup the sampler locations. | |
var artworkLocation = gl.getUniformLocation(program, "artwork"); | |
var baseLocation = gl.getUniformLocation(program, "base"); | |
var uvLocation = gl.getUniformLocation(program, "uv"); | |
var glossLocation = gl.getUniformLocation(program, "gloss"); | |
var maskLocation = gl.getUniformLocation(program, "mask"); | |
var widthLocation = gl.getUniformLocation(program, "width"); | |
var heightLocation = gl.getUniformLocation(program, "height"); | |
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); | |
// Clear the canvas | |
gl.clearColor(0, 0, 0, 0); | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
// Tell it to use our program (pair of shaders) | |
gl.useProgram(program); | |
// Turn on the position attribute | |
gl.enableVertexAttribArray(positionLocation); | |
// Bind the position buffer. | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER) | |
var size = 2; // 2 components per iteration | |
var type = gl.FLOAT; // the data is 32bit floats | |
var normalize = false; // don't normalize the data | |
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0; // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
positionLocation, size, type, normalize, stride, offset); | |
// Turn on the texcoord attribute | |
gl.enableVertexAttribArray(texcoordLocation); | |
// bind the texcoord buffer. | |
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); | |
// Tell the texcoord attribute how to get data out of texcoordBuffer (ARRAY_BUFFER) | |
var size = 2; // 2 components per iteration | |
var type = gl.FLOAT; // the data is 32bit floats | |
var normalize = false; // don't normalize the data | |
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0; // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
texcoordLocation, size, type, normalize, stride, offset); | |
// set the resolution | |
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height); | |
// set which texture units to render with. | |
gl.uniform1i(artworkLocation, 0); // texture unit 0 | |
gl.uniform1i(baseLocation, 1); // texture unit 1 | |
gl.uniform1i(uvLocation, 2); // texture unit 2 | |
gl.uniform1i(glossLocation, 3); // texture unit 3 | |
gl.uniform1i(maskLocation, 4); // texture unit 4 | |
gl.uniform1f(widthLocation, gl.canvas.width); // texture unit 3 | |
gl.uniform1f(heightLocation, gl.canvas.height); // texture unit 4 | |
// Set each texture unit to use a particular texture. | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, textures[0]); | |
gl.activeTexture(gl.TEXTURE1); | |
gl.bindTexture(gl.TEXTURE_2D, textures[1]); | |
gl.activeTexture(gl.TEXTURE2); | |
gl.bindTexture(gl.TEXTURE_2D, textures[2]); | |
gl.activeTexture(gl.TEXTURE3); | |
gl.bindTexture(gl.TEXTURE_2D, textures[3]); | |
// Draw the rectangle. | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
console.log('Elapsed: ', Date.now() - starttime); | |
return canvas; | |
} | |
function setRectangle(gl, x, y, width, height) { | |
var x1 = x; | |
var x2 = x + width; | |
var y1 = y; | |
var y2 = y + height; | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
x1, y1, | |
x2, y1, | |
x1, y2, | |
x1, y2, | |
x2, y1, | |
x2, y2, | |
]), gl.STATIC_DRAW); | |
} | |
main(); | |
// This is needed if the images are not on the same domain | |
// NOTE: The server providing the images must give CORS permissions | |
// in order to be able to use the image with WebGL. Most sites | |
// do NOT give permission. | |
// See: https://webglfundamentals.org/webgl/lessons/webgl-cors-permission.html | |
function requestCORSIfNotSameOrigin(img, url) { | |
if ((new URL(url, window.location.href)).origin !== window.location.origin) { | |
img.crossOrigin = ""; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"name":"mapping","settings":{},"filenames":["index.html","index.css","index.js"]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment