render mii and shader with mii-unsecure glTF and three.js
by arian_
HTML
<!-- UI for inputting the model URL and controlling rotation -->
<div id="uiContainer" class="resizable">
<button id="showUiButton" class="floating" type="button" style="display: none;">Show UI</button>
<div id="ui" class="floating">
<form id="modelForm">
<div class="controls">
<label for="modelUrl">glTF Model URL:</label>
<!--<label for="shaderSelector">Select Shader:</label>-->
<select id="shaderSelector">
<option value="FFLShaderMaterial" selected>FFLShaderMaterial</option>
<option value="LUTShaderMaterial">LUTShaderMaterial</option>
</select>
<button id="hideUiButton" type="button">Hide UI</button>
</div>
<input type="text" id="modelUrl" value="https://mii-unsecure.ariankordi.net/miis/image.glb?nnid=JasmineChlora">
<small class="hint">Hint: To find this, go to <a href="https://mii-unsecure.ariankordi.net" target="_blank">my Mii renderer site</a>, copy your Mii's image URL, then replace "image.png" with "image.glb" and paste it into here.</small>
<button id="loadModelButton" type="submit">Load Model</button>
</form>
<div class="controls">
<div id="lightDirectionControl">
<details>
<summary>Light Direction Control</summary>
<label for="lightDirX">Light Direction X:</label>
<input type="range" id="lightDirX" min="-1" max="1" step="0.01" value="-0.453">
<label for="lightDirY">Light Direction Y:</label>
<input type="range" id="lightDirY" min="-1" max="1" step="0.01" value="0.423">
<label for="lightDirZ">Light Direction Z:</label>
<input type="range" id="lightDirZ" min="-1" max="1" step="0.01" value="0.785">
<button id="resetLightButton">Reset...
CSS
body { margin: 0; overflow: hidden; }
canvas { display: block; }
.floating {
position: absolute;
top: 10px;
left: 10px;
}
#ui {
background: rgba(255,255,255,0.8);
padding: 10px;
border-radius: 4px;
font-family: Arial, sans-serif;
z-index: 1;
overflow: hidden; /* Ensure content remains within the boundaries */
resize: both;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); /* Optional shadow for better visibility */
}
#ui input, #ui button, #ui label {
display: block;
margin: 5px 0;
}
#modelUrl {
width: 100%; /* Ensure input field takes up available width within the constrained size */
}
/* Flexbox layout for aligning buttons */
.controls {
display: flex;
justify-content: space-between;
align-items: center;
}
.hint {
color: gray;
display: block;
margin-top: 5px;
font-size: 12px;
max-width: 430px; /* Constrain the width of the hint text */
word-wrap: break-word; /* Ensure long text wraps inside the constrained width */
}
JavaScript
// @ts-check
// import * as THREE from 'three';
// import * as FFLShaderMaterial from './FFLShaderMaterial.js';
// import * as LUTShaderMaterial from './LUTShaderMaterial.js';
/* eslint @stylistic/indent: ['error', 2] -- Define indent rules. */
/* NOTglobals FFLShaderMaterial LUTShaderMaterial -- Global dependencies. */
/** @type {Object<string, function(new: THREE.Material, ...*): THREE.Material>} */
const shaders = { FFLShaderMaterial, LUTShaderMaterial };
// // ---------------------------------------------------------------------
// // Active Shader Class Handling
// // ---------------------------------------------------------------------
/** The name of the active shader class, initialized to the first. */
let activeShaderClassName = Object.keys(shaders)[0];
/**
* Applies the current shader material to the mesh.
* @param {THREE.Mesh} mesh - The mesh to apply the shader material to.
* @param {{modulateType: number, modulateMode: number, modulateColor: Array<number>}} userData -
* The userData from the glTF.
* @param {THREE.MeshBasicMaterial & {_side: THREE.Side|undefined}} originalMaterial -
* The original material of the mesh.
*/
function applyShaderMaterial(mesh, userData, originalMaterial) {
const ShaderClass = shaders[activeShaderClassName];
if (!ShaderClass) {
console.error(`Shader class ${activeShaderClassName} not found.`);
return;
}
/** Color bound to the material. Defaults to red if missing. */
const modulateColor = Array.isArray(userData.modulateColor)
? new THREE.Color(userData.modulateColor[0],
userData.modulateColor[1], userData.modulateColor[2])
: new THREE.Color(1, 0, 0);
// Create the shader material
const shaderMaterial = new ShaderClass({
// _side = original side from LUTShaderMaterial, must be set first
side: (originalMaterial._side !== undefined) ? originalMaterial._side : originalMaterial.side,
modulateMode: userData.modulateMode,
modulateType: userData.modulateType, //...