E
Last active
May 16, 2017 12:35
-
-
Save sfpgmr/e1917c9f13455b4af39226c8835094ca to your computer and use it in GitHub Desktop.
ExtrudeGeometry&TextureMapping
This file contains 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
typings | |
node_modules | |
.vscode | |
temp |
This file contains 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
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>ExtrudeGeometryの検証</title> | |
<script type="text/javascript" src="./three.js"></script> | |
<script type="text/javascript" src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> | |
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.min.js"></script> | |
<script type="text/javascript" src="./main.js"></script> | |
<style> | |
body {margin:0;padding:0;overflow:hidden;} | |
#container { | |
position: relative; | |
} | |
#loading { | |
left:25vw; | |
top:50vh; | |
width:50vw; | |
position: absolute; | |
background: white; | |
color:black; | |
opacity: 0.5; | |
margin:auto; | |
text-align: center; | |
font-size:3vw; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="container"> | |
<div id="loading">Please wait while loading ...</div> | |
</div> | |
</body> | |
</html> |
This file contains 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" | |
var renderer, project, scene, camera, controls, buildingsTextures = []; | |
const MAX_TEX_NUM = 16; // 4 x 4 = 16 cell | |
const TEX_DIV = 4;// UV座標の分割数 | |
const TEX_DIV_R = 1 / TEX_DIV;// UV座標の分割数の逆数 | |
class BoundingUVGenerator { | |
constructor() { | |
} | |
// THREE.ExtrudeGeometryの前に呼び出す | |
setShape({ | |
extrudedShape, // 押し出すShape | |
extrudedOptions// THREE.ExtrudeGeometryのオプション | |
}) { | |
// texIndexTop = MAX_TEX_NUM - texIndexTop - 1; | |
// texIndexSide = MAX_TEX_NUM - texIndexSide - 1; | |
this.extrudedShape = extrudedShape; | |
this.bb = new THREE.Box2(); | |
// this.texIndexTopV = Math.floor(texIndexTop / TEX_DIV) * TEX_DIV_R; | |
// this.texIndexTopU = (texIndexTop % TEX_DIV) * TEX_DIV_R; | |
// this.texIndexSideV = Math.floor(texIndexSide / TEX_DIV) * TEX_DIV_R; | |
// this.texIndexSideU = (texIndexSide % TEX_DIV) * TEX_DIV_R; | |
this.bb.setFromPoints(this.extrudedShape.extractAllPoints().shape); | |
this.extrudedOptions = extrudedOptions; | |
} | |
generateTopUV(geometry, vertices, indexA, indexB, indexC) { | |
const ax = vertices[indexA * 3], | |
ay = vertices[indexA * 3 + 1], | |
bx = vertices[indexB * 3], | |
by = vertices[indexB * 3 + 1], | |
cx = vertices[indexC * 3], | |
cy = vertices[indexC * 3 + 1], | |
bb = this.bb,//extrudedShape.getBoundingBox(), | |
bbx = (bb.max.x - bb.min.x), | |
bby = (bb.max.y - bb.min.y); | |
return [ | |
new THREE.Vector2((ax - bb.min.x) / bbx, (1.0 - (ay - bb.min.y) / bby)), | |
new THREE.Vector2((bx - bb.min.x) / bbx, (1.0 - (by - bb.min.y) / bby)), | |
new THREE.Vector2((cx - bb.min.x) / bbx, (1.0 - (cy - bb.min.y) / bby)) | |
]; | |
} | |
generateSideWallUV(geometry, vertices, indexA, indexB, indexC, indexD) { | |
const ax = vertices[indexA * 3], | |
ay = vertices[indexA * 3 + 1], | |
az = vertices[indexA * 3 + 2], | |
bx = vertices[indexB * 3], | |
by = vertices[indexB * 3 + 1], | |
bz = vertices[indexB * 3 + 2], | |
cx = vertices[indexC * 3], | |
cy = vertices[indexC * 3 + 1], | |
cz = vertices[indexC * 3 + 2], | |
dx = vertices[indexD * 3], | |
dy = vertices[indexD * 3 + 1], | |
dz = vertices[indexD * 3 + 2]; | |
const amt = this.extrudedOptions.amount, | |
bb = this.bb,//extrudedShape.getBoundingBox(), | |
bbx = (bb.max.x - bb.min.x), | |
bby = (bb.max.y - bb.min.y); | |
if (Math.abs(ay - by) < 0.01) { | |
return [ | |
new THREE.Vector2(ax / bbx, 1.0 - az / amt), | |
new THREE.Vector2(bx / bbx, 1.0 - bz / amt), | |
new THREE.Vector2(cx / bbx, 1.0 - cz / amt), | |
new THREE.Vector2(dx / bbx, 1.0 - dz / amt) | |
]; | |
} else { | |
return [ | |
new THREE.Vector2((ay / bby), 1.0 - az / amt), | |
new THREE.Vector2((by / bby), 1.0 - bz / amt), | |
new THREE.Vector2((cy / bby), 1.0 - cz / amt), | |
new THREE.Vector2((dy / bby), 1.0 - dz / amt) | |
]; | |
} | |
} | |
}; | |
const vertexShader = | |
`#define PHONG | |
varying vec3 vViewPosition; | |
#ifndef FLAT_SHADED | |
varying vec3 vNormal; | |
#endif | |
#include <common> | |
#include <uv_pars_vertex> | |
#include <uv2_pars_vertex> | |
#include <displacementmap_pars_vertex> | |
#include <envmap_pars_vertex> | |
#include <color_pars_vertex> | |
#include <fog_pars_vertex> | |
#include <morphtarget_pars_vertex> | |
#include <skinning_pars_vertex> | |
#include <shadowmap_pars_vertex> | |
#include <logdepthbuf_pars_vertex> | |
#include <clipping_planes_pars_vertex> | |
attribute float texIndex; | |
attribute float amount; | |
varying float vTexIndex; | |
varying float vAmount; | |
varying vec3 vNormalView; | |
void main() { | |
#include <uv_vertex> | |
#include <uv2_vertex> | |
#include <color_vertex> | |
#include <beginnormal_vertex> | |
#include <morphnormal_vertex> | |
#include <skinbase_vertex> | |
#include <skinnormal_vertex> | |
#include <defaultnormal_vertex> | |
#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED | |
vNormal = normalize( transformedNormal ); | |
#endif | |
#include <begin_vertex> | |
#include <displacementmap_vertex> | |
#include <morphtarget_vertex> | |
#include <skinning_vertex> | |
#include <project_vertex> | |
#include <logdepthbuf_vertex> | |
#include <clipping_planes_vertex> | |
vViewPosition = - mvPosition.xyz; | |
#include <worldpos_vertex> | |
#include <envmap_vertex> | |
#include <shadowmap_vertex> | |
#include <fog_vertex> | |
vTexIndex = texIndex; | |
vAmount = amount; | |
vNormalView = normal; | |
} | |
`; | |
const fragmentShader = | |
`#define PHONG | |
uniform vec3 diffuse; | |
uniform vec3 emissive; | |
uniform vec3 specular; | |
uniform float shininess; | |
uniform float opacity; | |
#include <common> | |
#include <packing> | |
#include <dithering_pars_fragment> | |
#include <color_pars_fragment> | |
#include <uv_pars_fragment> | |
#include <uv2_pars_fragment> | |
#include <map_pars_fragment> | |
#include <alphamap_pars_fragment> | |
#include <aomap_pars_fragment> | |
#include <lightmap_pars_fragment> | |
#include <emissivemap_pars_fragment> | |
#include <envmap_pars_fragment> | |
#include <gradientmap_pars_fragment> | |
#include <fog_pars_fragment> | |
#include <bsdfs> | |
#include <lights_pars> | |
#include <lights_phong_pars_fragment> | |
#include <shadowmap_pars_fragment> | |
#include <bumpmap_pars_fragment> | |
#include <normalmap_pars_fragment> | |
#include <specularmap_pars_fragment> | |
#include <logdepthbuf_pars_fragment> | |
#include <clipping_planes_pars_fragment> | |
varying float vTexIndex; | |
varying float vAmount; | |
varying vec3 vNormalView; | |
void main() { | |
#include <clipping_planes_fragment> | |
vec4 diffuseColor = vec4( diffuse, opacity ); | |
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); | |
vec3 totalEmissiveRadiance = emissive; | |
#include <logdepthbuf_fragment> | |
//#include <map_fragment> | |
//float ycomp = dot(vec3(0.,0.,1.),vNormalView); | |
float texIdx; | |
if(vNormalView.z != 0.0){ | |
texIdx = MAX_TEX_NUM - vTexIndex - 8.0 - 1.0; | |
} else { | |
texIdx = MAX_TEX_NUM - vTexIndex - 1.0; | |
} | |
vec2 uv; | |
uv.y = floor(texIdx / TEX_DIV) * TEX_DIV_R; | |
uv.x = mod(texIdx,TEX_DIV ) * TEX_DIV_R ; | |
vec2 vuv; | |
if(vNormalView.z == 0.0){ | |
vuv = vec2(vUv.x * TEX_DIV_R,mod(vUv.y , 1.0 / vAmount) * vAmount * TEX_DIV_R / 8.0); | |
} else { | |
vuv = vUv * TEX_DIV_R; | |
} | |
vec4 texelColor = texture2D(map, vuv + uv); | |
//vec4 texelColor = texture2D( map, vUv ); | |
texelColor = mapTexelToLinear( texelColor ); | |
diffuseColor *= texelColor; | |
#include <color_fragment> | |
#include <alphamap_fragment> | |
#include <alphatest_fragment> | |
#include <specularmap_fragment> | |
#include <normal_flip> | |
#include <normal_fragment> | |
#include <emissivemap_fragment> | |
// accumulation | |
#include <lights_phong_fragment> | |
#include <lights_template> | |
// modulation | |
#include <aomap_fragment> | |
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; | |
#include <envmap_fragment> | |
gl_FragColor = vec4( outgoingLight, diffuseColor.a ); | |
#include <tonemapping_fragment> | |
#include <encodings_fragment> | |
#include <fog_fragment> | |
#include <premultiplied_alpha_fragment> | |
#include <dithering_fragment> | |
} | |
`; | |
// ` | |
// //varying vec2 vUv; | |
// varying float vTexIndex; | |
// varying float vAmount; | |
// //uniform sampler2D map; | |
// void main(){ | |
// float texIdx = MAX_TEX_NUM - vTexIndex - 1.0; | |
// vec2 uv; | |
// uv.y = floor(texIdx / TEX_DIV) * TEX_DIV_R; | |
// uv.x = mod(texIdx,TEX_DIV ) * TEX_DIV_R ; | |
// vec2 vuv; | |
// if(vTexIndex < 4.0){ | |
// vuv = vec2(vUv.x * TEX_DIV_R,mod(vUv.y , 1.0 / vAmount) * vAmount * TEX_DIV_R / 8.0); | |
// } else { | |
// vuv = vUv * TEX_DIV_R; | |
// } | |
// gl_FragColor = texture2D(map, vuv + uv); | |
// } | |
// `; | |
function toFloatString(number) { | |
const v = number.toString(); | |
return v.match(/\./) ? v : v + '.0'; | |
} | |
document.addEventListener('DOMContentLoaded', function () { | |
scene = new THREE.Scene(); | |
renderer = new THREE.WebGLRenderer(); | |
renderer.setClearColor(0xa0a0d0); | |
renderer.setPixelRatio(window.devicePixelRatio); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
//renderer.shadowMapEnabled = true; | |
document.getElementById('container').appendChild(renderer.domElement); | |
let light = new THREE.DirectionalLight(0xffffff, 1); | |
light.position.set(100, 100, -100); | |
//light.castShadow = true; | |
scene.add(light); | |
let light1 = new THREE.DirectionalLight(0xffffff, 0.7); | |
light1.position.set(-100, -1000, -100); | |
scene.add(light1); | |
//scene.fog = new THREE.FogExp2(0xc0c0c0, 0.00015); | |
let am = new THREE.AmbientLight(0xffffff, 0.6); | |
scene.add(am); | |
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 40000); | |
camera.position.set(0, 0, 50); | |
scene.add(camera); | |
let pr = Promise.resolve(0); | |
let texloader = new THREE.TextureLoader(); | |
let textures = [ | |
'./texture.jpg' | |
]; | |
textures.forEach((url) => { | |
pr = pr.then(() => new Promise((resolve, reject) => { | |
texloader.load(url, (tex) => { | |
tex.wrapS = THREE.RepeatWrapping; | |
tex.wrapT = THREE.RepeatWrapping; | |
// tex.repeat.set(5, 5); | |
buildingsTextures.push(tex); | |
resolve(); | |
}); | |
})); | |
}); | |
pr.then(() => { | |
const mesh = new THREE.Object3D(); | |
mesh.add(new THREE.LineSegments( | |
new THREE.Geometry(), | |
new THREE.LineBasicMaterial({ | |
color: 0xffffff, | |
transparent: true, | |
opacity: 0.5 | |
}) | |
)); | |
const baseShader = THREE.ShaderLib['phong']; | |
const mat = new THREE.ShaderMaterial({ | |
uniforms:THREE.UniformsUtils.clone(baseShader.uniforms), | |
defines: { | |
MAX_TEX_NUM: toFloatString(MAX_TEX_NUM), | |
TEX_DIV: toFloatString(TEX_DIV), | |
TEX_DIV_R: toFloatString(TEX_DIV_R), | |
USE_MAP:'' | |
}, | |
lights:true, | |
vertexShader: vertexShader, | |
fragmentShader: fragmentShader | |
}); | |
mat.uniforms.emissive.value = new THREE.Color(0x000000); | |
mat.uniforms.ambientLightColor.value = new THREE.Color(0x303030); | |
mat.uniforms.map.value = buildingsTextures[0]; | |
mesh.add(new THREE.Mesh( | |
new THREE.Geometry(), | |
mat | |
)); | |
const gui = new dat.GUI(); | |
const uvGenerator = new BoundingUVGenerator(); | |
const data = { | |
steps: 1, | |
amount: 16, | |
bevelEnabled: false, | |
bevelThickness: 1, | |
bevelSize: 1, | |
bevelSegments: 1, | |
texNo: 0, | |
UVGenerator: uvGenerator | |
}; | |
const length = 12, width = 8; | |
const shape = new THREE.Shape(); | |
shape.moveTo(0, 0); | |
shape.lineTo(0, width); | |
shape.lineTo(length, width); | |
shape.lineTo(length, 0); | |
shape.lineTo(0, 0); | |
function updateGroupGeometry(mesh, geometry) { | |
mesh.children[0].geometry.dispose(); | |
mesh.children[1].geometry.dispose(); | |
mesh.children[0].geometry = new THREE.WireframeGeometry(geometry); | |
mesh.children[1].geometry = geometry; | |
geometry.computeFaceNormals(); | |
geometry.computeVertexNormals(true); | |
const texIndexs = new Float32Array(geometry.attributes.position.count); | |
const amounts = new Float32Array(geometry.attributes.position.count); | |
for (let i = 0, e = geometry.attributes.position.count; i < e; ++i) { | |
texIndexs[i] = data.texNo; | |
amounts[i] = data.amount; | |
} | |
geometry.addAttribute('texIndex', new THREE.BufferAttribute(texIndexs, 1)); | |
geometry.addAttribute('amount', new THREE.BufferAttribute(amounts, 1)); | |
} | |
function generateGeometry() { | |
updateGroupGeometry(mesh, | |
new THREE.ExtrudeBufferGeometry(shape, data) | |
); | |
render(); | |
} | |
//const folder = gui.addFolder('THREE.ExtrudeBufferGeometry'); | |
gui.add(data, 'texNo', 0, 3).step(1).onChange(generateGeometry); | |
gui.add(data, 'steps', 1, 100).step(1).onChange(generateGeometry); | |
gui.add(data, 'amount', 1, 100).step(1).onChange(generateGeometry); | |
gui.add(data, 'bevelEnabled').onChange(generateGeometry); | |
gui.add(data, 'bevelThickness', 1, 5).step(1).onChange(generateGeometry); | |
gui.add(data, 'bevelSize', 1, 5).step(1).onChange(generateGeometry); | |
gui.add(data, 'bevelSegments', 1, 5).step(1).onChange(generateGeometry); | |
uvGenerator.setShape({ extrudedShape: shape, extrudedOptions: data, texIndexSide: 0 }); | |
generateGeometry(); | |
mesh.rotation.x = Math.PI / 2; | |
scene.add(mesh); | |
gui.open(); | |
d3.select('#loading').style('display', 'none'); | |
// マウスでぐりぐりできるようにする | |
controls = new THREE.OrbitControls(camera); | |
controls.addEventListener('change', render); | |
render(); | |
}).catch((e) => { | |
console.log('error' + e.stack); | |
}); | |
window.addEventListener('resize', () => { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
render(); | |
}); | |
}); | |
// レンダリング処理 | |
function render() { | |
// controls.update(); | |
renderer.render(scene, camera); // レンダリング | |
// requestAnimationFrame(render); // ループ処理 | |
} | |
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment