// Initialize embed api const p3d = new P3dEmbedApi(document.getElementById('p3d-embed'), { onclick: interpolate }); // Don't reset camera on double click if user is clicking on the model p3d.setAllowCameraReset('if-outside'); // Disable camera re-centering behavior p3d.setAllowCameraRecenter(false); // Declare target materials to interpolate between const targetMaterials = [ // Gold { props: { metalness: 1, roughness: 0.25, baseColorFactor: 0.5, }, color: { r: 255 / 255, g: 195 / 255, b: 85 / 255, }, }, // Plastic { props: { metalness: 0, roughness: 0.1, baseColorFactor: 0.5, }, color: { r: 0 / 255, g: 61 / 255, b: 253 / 255, }, }, // Rough { props: { metalness: 0, roughness: 1, baseColorFactor: 0.5, }, color: { r: 143 / 255, g: 128 / 255, b: 101 / 255, }, }, // Copper { props: { metalness: 1, roughness: 0.3, baseColorFactor: 0.5, }, color: { r: 243 / 255, g: 162 / 255, b: 137 / 255, }, }, // Ice { props: { metalness: 0, roughness: 0.0, baseColorFactor: 0.95, }, color: { r: 239 / 255, g: 251 / 255, b: 255 / 255, }, }, // Silver { props: { metalness: 1, roughness: 0.0, baseColorFactor: 0.5, }, color: { r: 247 / 255, g: 244 / 255, b: 233 / 255, }, }, ]; // Use Tween.js to interpolate between materials let tween = null; let colorTween = null; const interpolationTime = 1000; // 1s // Do interpolation when clicked on model let materialIndex = -1; function interpolate(click) { // Make sure click was on model and we have a material if (!click.material) { return; } // Toggle to next targetMaterial materialIndex++; if (materialIndex >= targetMaterials.length) { materialIndex = 0; } const materialTarget = targetMaterials[materialIndex]; // Cancel any existing tween animations if (tween && colorTween) { tween.stop(); colorTween.stop(); } // Interpolate material properties const material = click.material; tween = new TWEEN.Tween(material).to(materialTarget.props, interpolationTime).easing(TWEEN.Easing.Quadratic.Out).start(); // Interpolate baseColor as separate RGB values const rgb = material.hexColorToRGB(material.baseColor); const rgbProps = { r: rgb[0], g: rgb[1], b: rgb[2] }; colorTween = new TWEEN.Tween(rgbProps) .to(materialTarget.color, interpolationTime) .easing(TWEEN.Easing.Quadratic.Out) .onUpdate(() => { // Refresh RGB back to the p3d model material.baseColor = [rgbProps.r, rgbProps.g, rgbProps.b]; }) .start(); // Playback the "shake" animation of the model p3d.listAnimations().then((animations) => { animations.forEach((animation) => { // Start animation from the beginning animation.time = 0; // Play one loop animation.loops = 1; animation.speed = 1; // Start animation playback if not already animation.isPlaying = true; }); }); } // Start Tween.js animation loop function animate(time) { requestAnimationFrame(animate); TWEEN.update(time); } requestAnimationFrame(animate);
<script src="https://cfstatic.p3d.in/embed-api/v2/p3d-embed-api.js"></script> <script src="https://unpkg.com/@tweenjs/[email protected]/dist/tween.umd.js"></script> <iframe src="https://p3d.in/e/YRPIl+api+load+controls,variants,hotspots-hidden+spin" border="0" frameborder="0" height="100%" width="100%" allowtransparency="true" id="p3d-embed"></iframe> <div class="info-box-container"> <span class="info-box"> Click on the model to switch between materials! </span> </div>
#p3d-embed { position: absolute; height: 98%; width: 98%; border: none; margin: 0px; padding: 0px; } .info-box-container { position: absolute; top: 1em; left: 0; height: auto; width: 100%; z-index: 500; user-select: none; } .info-box { position: absolute; left: 50%; transform: translate(-50%, 0); background: rgba(0,0,0,.4); border-radius: .25rem; font-size: 1.0rem; color: #fff; padding: .25rem .5rem; text-align: center; white-space: nowrap; }