<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="https://raw.githack.com/mrmola/arrow_assets/main/three.js"></script>
<script type="text/javascript" src="https://raw.githack.com/mrmola/arrow_assets/main/OBJLoader.js"></script>
<script type="text/javascript" src="https://raw.githack.com/mrmola/arrow_assets/main/MTLLoader.js"></script>
<script type="text/javascript" src="https://unpkg.com/three@0.117.0/examples/js/controls/FlyControls.js"></script>
<meta name="viewport" content="width=device-width">
<style>body {
background-color: black;
margin: 0px;
}
div#interface {
position:absolute;
width: 100%;
z-index:100;
}
div#interface {
position:absolute;
width: 100%;
z-index:100;
}
</style>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div style="position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; visibility: visible;" id="viewport"> </div>
</body>
</html>
var renderer = new THREE.WebGLRenderer({ antialias: true, alpha:true, preserveDrawingBuffer:true });
var ambientLight = new THREE.AmbientLight(0x999999);
renderer.setSize( window.innerWidth, window.innerHeight );
let gl = renderer.context;
let camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
renderer.autoClear = false;
renderer.autoClearColor = false;
renderer.autoClearDepth = false;
renderer.autoClearStencil = false;
renderer.context.getExtension("EXT_frag_depth");
gl.getExtension("WEBGL_depth_texture");
var ext = gl.getExtension('WEBGL_draw_buffers');
document.getElementById("viewport").appendChild( renderer.domElement );
controls = new THREE.FlyControls( camera, renderer.domElement );
controls.movementSpeed = 10;
controls.domElement = renderer.domElement;
controls.rollSpeed = Math.PI / 6;
controls.autoForward = false;
controls.dragToLook = true;
var ctx = renderer.domElement.getContext('2d');
var scene = new THREE.Scene;
const dividingChar = "•";
scene.add(ambientLight);
ambientLight.layers.enable(5);
camera.position.set( 0, 0, 10 );
scene.add( camera );
camera.lookAt(0,0,0)
camera.rotation.order = "YXZ";
this.updateRotationVector = function () {
this.rotationVector.y = ( - this.moveState.yawRight + this.moveState.yawLeft );
this.rotationVector.z = ( - this.moveState.rollRight + this.moveState.rollLeft );
};
let colorBuffer = new THREE.WebGLRenderTarget( renderer.context.canvas.width, renderer.context.canvas.width, {stencilBuffer:false, depthBuffer:true,
magFilter: THREE.LinearFilter,
minFilter: THREE.LinearFilter,
anisotropy: 0,
generateMipmaps: false});
let normalBuffer = new THREE.WebGLRenderTarget( renderer.context.canvas.width, renderer.context.canvas.width, {stencilBuffer:false, depthBuffer:true,
magFilter: THREE.LinearFilter,
minFilter: THREE.LinearFilter,
anisotropy: 0,
generateMipmaps: false});
const vertexDensity = 0.05;
const brushTexture = new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/mrmola/arrow_assets/main/brush_stroke.png' );
brushTexture.magFilter = THREE.NearestFilter;
brushTexture.minFilter = THREE.NearestFilter;
let pointMaterial = new THREE.RawShaderMaterial( {
uniforms: {
iResolution: { get value(){ return new THREE.Vector2(renderer.context.canvas.width, renderer.context.canvas.height) }},
//strokeTexture is what is sampled from when checking the brush shape size thing
u_strokeTexture: { value:brushTexture },
u_color: { value: colorBuffer.texture },
u_normal: { value: normalBuffer.texture },
//pointSize is the size of the point
pointSize: {value:1/vertexDensity}
},
//the arrow shaders
vertexShader: `
precision mediump float; precision mediump int;
const float strokeSize = 256.;
attribute vec2 position;
uniform float pointSize;
uniform sampler2D u_normal;
uniform vec2 iResolution;
//the stroke position on the stroke texture texture
varying vec2 strokePosition;
//the stroke's rotation
varying vec2 strokeRotation;
//the strokes dimensions
varying vec2 strokeDimensions;
//the color
varying vec3 v_color;
float unmapVector(float vector) {
return (vector*2.)-1.;
}
vec2 unmapVector(vec2 vector) {
return (vector*2.)-vec2(1.);
}
vec3 unmapVector(vec3 vector) {
return (vector*2.)-vec3(1.);
}
vec4 unmapVector(vec4 vector) {
return (vector*2.)-vec4(1.);
}
void main() {
vec2 endPosition = position;
vec4 osize = texture2D(u_normal, endPosition.xy);
vec4 tempOsize = unmapVector(osize);
strokeRotation = normalize(vec2(tempOsize.y, tempOsize.x));
gl_Position = vec4((endPosition.xy)*2.-vec2(1,1), 0., 1.);
strokePosition = vec2(1,1);
strokeDimensions = vec2(0.75,0.5);
mat2 rotationMatrix = mat2(
strokeRotation.x,-strokeRotation.y,
strokeRotation.y,strokeRotation.x
);
mat2 scaleMatrix = mat2(
strokeDimensions.x, 0,
0, strokeDimensions.y
);
vec2 pointA = vec2(1, -1);
vec2 pointB = vec2(1, 1);
pointA = abs(pointSize*scaleMatrix*rotationMatrix*pointA);
pointB = abs(pointSize*scaleMatrix*rotationMatrix*pointB);
gl_PointSize = max(pointA.x, pointB.x);
gl_PointSize = max(gl_PointSize, pointB.y);
gl_PointSize = max(gl_PointSize, pointA.y);
gl_PointSize = max(gl_PointSize, pointSize);
}`,
fragmentShader: `
#extension GL_EXT_frag_depth : enable
#define TEST 8
precision mediump float;
precision mediump int;
//do not change
const float strokeSize = 256.;
uniform sampler2D u_strokeTexture;
uniform sampler2D u_normal;
uniform sampler2D u_color;
uniform vec2 iResolution;
varying vec2 strokeRotation;
varying vec2 strokeDimensions;
varying vec2 strokePosition;
varying vec3 v_color;
void main(){
float singleStrokeSize = strokeSize/4.;
mat2 rotationMatrix = mat2(
strokeRotation.x,-strokeRotation.y,
strokeRotation.y,strokeRotation.x
);
mat2 scaleMatrix = mat2(
strokeDimensions.x*2., 0,
0, strokeDimensions.y*2.
);
vec2 basedCoords = gl_PointCoord-vec2(0.5,0.5);
vec2 offset = (scaleMatrix*rotationMatrix*basedCoords+vec2(0.5,0.5))*singleStrokeSize;
vec4 strokeSample = texture2D(u_strokeTexture,(strokePosition*singleStrokeSize+offset)/strokeSize);
//yes, i know i can replace this if statement with a mix thing. I haven't optimized
if(
(strokeSample.r == strokeSample.g && strokeSample.g == strokeSample.b) ||
(offset.x > singleStrokeSize || offset.x < 0. || offset.y < 0. || offset.y > singleStrokeSize)
) {
gl_FragDepthEXT = 100.;
vec4 color = texture2D(u_color, gl_FragCoord.xy/iResolution);
gl_FragColor = color;
} else {
gl_FragColor = texture2D(u_normal, gl_FragCoord.xy/iResolution);
}
}`
} );
let orientationMaterial= new THREE.MeshPhongMaterial();
orientationMaterial.extensions = {
derivatives: true
};
orientationMaterial.onBeforeCompile = function(shader) {
shader.uniforms.iResolution = { get value(){ return new THREE.Vector2(renderer.context.canvas.width, renderer.context.canvas.height) }};
shader.uniforms.viewNormal = {get value() {
let rot = vec2(camera.rotation.x,camera.rotation.y);
return vec3(
Math.cos(rot.x)*Math.cos(additionalAngle+rot.y),
Math.sin(-rot.x),
Math.cos(rot.x)*Math.sin(additionalAngle+rot.y)
).normalize();
}};
let tfs = shader.fragmentShader;
let tvs = shader.vertexShader;
tvs = tvs.split('\n');
tfs = tfs.split('\n');
tfs.splice(0,0, `uniform vec3 viewNormal;`);
//the orientation map output
tfs.splice(tfs.length-1, 0, `
gl_FragColor = vec4(normalize(vec2(
dFdx(vUv.y),
dFdy(vUv.y)
)
)/2.+0.5,0,0);
`);
//changes go here.
tvs = tvs.join('\n');
tfs = tfs.join('\n');
console.log(tfs);
shader.fragmentShader = tfs;
shader.vertexShader = tvs;
}
let strokeMesh = new THREE.Points(new THREE.BufferGeometry(), pointMaterial);
strokeMesh.layers.enable(4);
strokeMesh.layers.disable(0);
strokeMesh.layers.disable(1);
makePointArray(new THREE.Vector2(renderer.context.canvas.width, renderer.context.canvas.height));
/** Fix the stroke array so that it does the thing
*
* @param {Vector2} newSize Size of the screen in pixels
*/
function makePointArray(newSize) {
let pointGeometry = new THREE.BufferGeometry();
const positions = new Float32Array( Math.ceil(2*(Math.ceil(newSize.x*vertexDensity+1)*Math.ceil(newSize.y*vertexDensity)))); // 3 vertices per point
let bp = 0;//base position
for(let i = 0; i < newSize.x*vertexDensity+1; i++) {
for(let j = 0; j < newSize.y*vertexDensity; j++) {
positions[bp] = i/(newSize.x*vertexDensity);
positions[bp+1] = j/(newSize.y*vertexDensity);
bp+=2;
}
}
pointGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 2 ) );
//positions.length/2 will always be a whole number
const strokeIDs = new Int8Array(positions.length/2);
for(let i = 0; i < positions.length/2; i++) {
strokeIDs[i] = Math.floor(Math.random()*16);
}
const strokeDepth = new Float32Array(positions.length/2);
for(let i = 0; i < positions.length/2; i++) {
strokeDepth[i] = Math.random();
}
let oldGeometry = strokeMesh.geometry;
strokeMesh.geometry = pointGeometry;
oldGeometry.dispose();
}
scene.add(strokeMesh);
let clock = new THREE.Clock();
var render = function(b) {
camera.rotation.z = 0;
const delta = clock.getDelta();
controls.update(delta);
renderer.clear(true, true, true);
camera.layers.enable(0);
renderer.setRenderTarget(colorBuffer);
renderer.clear(true, true, true);
renderer.render(scene, camera);
renderer.setRenderTarget(normalBuffer);
scene.overrideMaterial = orientationMaterial;
renderer.clear(true, true, true);
renderer.render(scene, camera);
scene.overrideMaterial = null;
camera.layers.disable(0);
camera.layers.enable(4);
renderer.setRenderTarget(null);
renderer.render(scene, camera);
camera.layers.disable(4);
requestAnimationFrame( render );
};
var mtlLoader = new THREE.MTLLoader();
mtlLoader.path = "https://raw.githubusercontent.com/mrmola/arrow_assets/main/";
let model = null;
mtlLoader.load("obj.mtl", function(e) {
console.log("we got him x4");
let OBJLoader = new THREE.OBJLoader();
OBJLoader.setMaterials(e);
OBJLoader.path = "https://raw.githubusercontent.com/mrmola/arrow_assets/main/";
e.preload();
OBJLoader.load("obj.obj",function(obj) {
console.log("we got him x5");
let deleteMe = obj;
model = deleteMe.children[0];
deleteMe.children.forEach(element => {
scene.add(element);
orientationMaterial.map = element.material.map;
console.log(element);
render(true);
console.log(model);
});
})
}, function(e){
console.log("problem");
console.log(e);
}, function(e){
console.log("ERROR: ", e);
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.