in lucid/misc/io/showing.py [0:0]
def textured_mesh(mesh, texture, background='0xffffff'):
texture_data_url = _image_url(texture, fmt='jpeg', quality=90)
code = Template('''
<input id="unfoldBox" type="checkbox" class="control">Unfold</input>
<input id="shadeBox" type="checkbox" class="control">Shade</input>
<script src="https://cdn.rawgit.com/mrdoob/three.js/r89/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/r89/examples/js/controls/OrbitControls.js"></script>
<script type="x-shader/x-vertex" id="vertexShader">
uniform float viewAspect;
uniform float unfolding_perc;
uniform float shadeFlag;
varying vec2 text_coord;
varying float shading;
void main () {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
vec4 plane_position = vec4((uv.x*2.0-1.0)/viewAspect, (uv.y*2.0-1.0), 0, 1);
gl_Position = mix(gl_Position, plane_position, unfolding_perc);
//not normalized on purpose to simulate the rotation
shading = 1.0;
if (shadeFlag > 0.5) {
vec3 light_vector = mix(normalize(cameraPosition-position), normal, unfolding_perc);
shading = dot(normal, light_vector);
}
text_coord = uv;
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
uniform float unfolding_perc;
varying vec2 text_coord;
varying float shading;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, text_coord);
gl_FragColor.rgb *= shading;
}
</script>
<script>
"use strict";
const el = id => document.getElementById(id);
const unfoldDuration = 1000.0;
var camera, scene, renderer, controls, material;
var unfolded = false;
var unfoldStart = -unfoldDuration*10.0;
init();
animate(0.0);
function init() {
var width = 800, height = 600;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(42, width / height, 0.1, 100);
camera.position.z = 3.3;
scene.add(camera);
controls = new THREE.OrbitControls( camera );
var geometry = new THREE.BufferGeometry();
geometry.addAttribute( 'position', new THREE.BufferAttribute($verts, 3 ) );
geometry.addAttribute( 'uv', new THREE.BufferAttribute($uvs, 2) );
geometry.setIndex(new THREE.BufferAttribute($faces, 1 ));
geometry.computeVertexNormals();
var texture = new THREE.TextureLoader().load('$tex_data_url', update);
material = new THREE.ShaderMaterial( {
uniforms: {
viewAspect: {value: width/height},
unfolding_perc: { value: 0.0 },
shadeFlag: { value: 0.0 },
texture: { type: 't', value: texture },
},
side: THREE.DoubleSide,
vertexShader: el( 'vertexShader' ).textContent,
fragmentShader: el( 'fragmentShader' ).textContent
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
scene.background = new THREE.Color( $background );
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
// render on change only
controls.addEventListener('change', function() {
// fold mesh back if user wants to interact
el('unfoldBox').checked = false;
update();
});
document.querySelectorAll('.control').forEach(e=>{
e.addEventListener('change', update);
});
}
function update() {
requestAnimationFrame(animate);
}
function ease(x) {
x = Math.min(Math.max(x, 0.0), 1.0);
return x*x*(3.0 - 2.0*x);
}
function animate(time) {
var unfoldFlag = el('unfoldBox').checked;
if (unfolded != unfoldFlag) {
unfolded = unfoldFlag;
unfoldStart = time - Math.max(unfoldStart+unfoldDuration-time, 0.0);
}
var unfoldTime = (time-unfoldStart) / unfoldDuration;
if (unfoldTime < 1.0) {
update();
}
var unfoldVal = ease(unfoldTime);
unfoldVal = unfolded ? unfoldVal : 1.0 - unfoldVal;
material.uniforms.unfolding_perc.value = unfoldVal;
material.uniforms.shadeFlag.value = el('shadeBox').checked ? 1.0 : 0.0;
controls.update();
renderer.render(scene, camera);
}
</script>
''').substitute(
verts = array_to_jsbuffer(mesh['position'].ravel()),
uvs = array_to_jsbuffer(mesh['uv'].ravel()),
faces = array_to_jsbuffer(np.uint32(mesh['face'].ravel())),
tex_data_url = texture_data_url,
background = background,
)
_display_html(code)