|
@@ -8,10 +8,15 @@
|
|
|
<style>
|
|
|
body {
|
|
|
color: #444;
|
|
|
+ background: #eee;
|
|
|
}
|
|
|
a {
|
|
|
color: #08f;
|
|
|
}
|
|
|
+ .colorPicker {
|
|
|
+ display: inline-block;
|
|
|
+ margin: 0 10px
|
|
|
+ }
|
|
|
</style>
|
|
|
</head>
|
|
|
|
|
@@ -20,9 +25,9 @@
|
|
|
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> car materials<br/>
|
|
|
Ferrari 458 Italia model by <a href="https://sketchfab.com/models/57bf6cc56931426e87494f554df1dab6" target="_blank" rel="noopener">vicent091036</a>
|
|
|
<br><br>
|
|
|
- <span>Body: <select id="body-mat"></select></span>
|
|
|
- <span>Details: <select id="rim-mat"></select></span>
|
|
|
- <span>Glass: <select id="glass-mat"></select></span>
|
|
|
+ <span class="colorPicker"><input id="body-color" type="color" value="#660000"></input><br/>Body</span>
|
|
|
+ <span class="colorPicker"><input id="details-color" type="color" value="#ffffff"></input><br/>Details</span>
|
|
|
+ <span class="colorPicker"><input id="glass-color" type="color" value="#ffffff"></input><br/>Glass</span>
|
|
|
</div>
|
|
|
|
|
|
<div id="container"></div>
|
|
@@ -33,89 +38,91 @@
|
|
|
|
|
|
import Stats from './jsm/libs/stats.module.js';
|
|
|
|
|
|
+ import { OrbitControls } from './jsm/controls/OrbitControls.js';
|
|
|
+ import { RoomEnvironment } from './jsm/environments/RoomEnvironment.js';
|
|
|
+
|
|
|
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
|
|
|
import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
|
|
|
|
|
|
- import { RGBELoader } from './jsm/loaders/RGBELoader.js';
|
|
|
-
|
|
|
var camera, scene, renderer;
|
|
|
- var stats, carModel, materialsLib;
|
|
|
-
|
|
|
- var bodyMatSelect = document.getElementById( 'body-mat' );
|
|
|
- var rimMatSelect = document.getElementById( 'rim-mat' );
|
|
|
- var glassMatSelect = document.getElementById( 'glass-mat' );
|
|
|
-
|
|
|
- var carParts = {
|
|
|
- body: [],
|
|
|
- rims: [],
|
|
|
- glass: [],
|
|
|
- };
|
|
|
+ var stats;
|
|
|
|
|
|
var grid, wheels = [];
|
|
|
+ var controls;
|
|
|
|
|
|
function init() {
|
|
|
|
|
|
var container = document.getElementById( 'container' );
|
|
|
|
|
|
- camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 200 );
|
|
|
-
|
|
|
- scene = new THREE.Scene();
|
|
|
- // scene.fog = new THREE.Fog( 0xd7cbb1, 1, 80 );
|
|
|
-
|
|
|
- new RGBELoader()
|
|
|
- .setDataType( THREE.UnsignedByteType )
|
|
|
- .setPath( 'textures/equirectangular/' )
|
|
|
- .load( 'quarry_01_1k.hdr', function ( texture ) {
|
|
|
+ renderer = new THREE.WebGLRenderer( { antialias: true } );
|
|
|
+ renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+ renderer.setAnimationLoop( render );
|
|
|
+ renderer.outputEncoding = THREE.sRGBEncoding;
|
|
|
+ renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
|
|
|
- var envMap = pmremGenerator.fromEquirectangular( texture ).texture;
|
|
|
- pmremGenerator.dispose();
|
|
|
+ window.addEventListener( 'resize', onWindowResize, false );
|
|
|
|
|
|
- scene.background = envMap;
|
|
|
- scene.environment = envMap;
|
|
|
+ stats = new Stats();
|
|
|
+ container.appendChild( stats.dom );
|
|
|
|
|
|
- //
|
|
|
+ //
|
|
|
|
|
|
- initCar();
|
|
|
- initMaterials();
|
|
|
- initMaterialSelectionMenus();
|
|
|
+ camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 100 );
|
|
|
+ camera.position.set( 3, 1.75, - 4 );
|
|
|
|
|
|
- } );
|
|
|
+ controls = new OrbitControls( camera, container );
|
|
|
+ controls.target.set( 0, 0.4, 0 );
|
|
|
+ controls.update();
|
|
|
|
|
|
- var ground = new THREE.Mesh(
|
|
|
- new THREE.PlaneBufferGeometry( 400, 400 ),
|
|
|
- new THREE.MeshBasicMaterial( { color: 0x6e6a62, depthWrite: false } )
|
|
|
- );
|
|
|
- ground.rotation.x = - Math.PI / 2;
|
|
|
- ground.renderOrder = 1;
|
|
|
- scene.add( ground );
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ scene.background = new THREE.Color( 0xeeeeee );
|
|
|
+ scene.environment = new RoomEnvironment( renderer );
|
|
|
+ scene.fog = new THREE.Fog( 0xeeeeee, 10, 50 );
|
|
|
|
|
|
- grid = new THREE.GridHelper( 400, 80, 0x000000, 0x000000 );
|
|
|
+ grid = new THREE.GridHelper( 100, 40, 0x000000, 0x000000 );
|
|
|
grid.material.opacity = 0.1;
|
|
|
grid.material.depthWrite = false;
|
|
|
grid.material.transparent = true;
|
|
|
scene.add( grid );
|
|
|
|
|
|
- renderer = new THREE.WebGLRenderer( { antialias: true } );
|
|
|
- renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
- renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
- container.appendChild( renderer.domElement );
|
|
|
+ // materials
|
|
|
|
|
|
- renderer.outputEncoding = THREE.sRGBEncoding;
|
|
|
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
|
+ var bodyMaterial = new THREE.MeshPhysicalMaterial( {
|
|
|
+ color: 0x660000, metalness: 1.0, roughness: 0.5, clearcoat: 0.02, clearcoatRoughness: 0.01
|
|
|
+ } );
|
|
|
|
|
|
- var pmremGenerator = new THREE.PMREMGenerator( renderer );
|
|
|
- pmremGenerator.compileEquirectangularShader();
|
|
|
+ var detailsMaterial = new THREE.MeshStandardMaterial( {
|
|
|
+ color: 0xffffff, metalness: 1.0, roughness: 0
|
|
|
+ } );
|
|
|
|
|
|
- stats = new Stats();
|
|
|
- container.appendChild( stats.dom );
|
|
|
+ var glassMaterial = new THREE.MeshPhysicalMaterial( {
|
|
|
+ color: 0xffffff, metalness: 0, roughness: 0, transparency: 0.8, transparent: true
|
|
|
+ } );
|
|
|
|
|
|
- window.addEventListener( 'resize', onWindowResize, false );
|
|
|
+ var bodyColorInput = document.getElementById( 'body-color' );
|
|
|
+ bodyColorInput.addEventListener( 'input', function () {
|
|
|
|
|
|
- renderer.setAnimationLoop( render );
|
|
|
+ bodyMaterial.color.set( this.value );
|
|
|
|
|
|
- }
|
|
|
+ } );
|
|
|
+
|
|
|
+ var detailsColorInput = document.getElementById( 'details-color' );
|
|
|
+ detailsColorInput.addEventListener( 'input', function () {
|
|
|
+
|
|
|
+ detailsMaterial.color.set( this.value );
|
|
|
+
|
|
|
+ } );
|
|
|
|
|
|
- function initCar() {
|
|
|
+ var glassColorInput = document.getElementById( 'glass-color' );
|
|
|
+ glassColorInput.addEventListener( 'input', function () {
|
|
|
+
|
|
|
+ glassMaterial.color.set( this.value );
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ // Car
|
|
|
|
|
|
var dracoLoader = new DRACOLoader();
|
|
|
dracoLoader.setDecoderPath( 'js/libs/draco/gltf/' );
|
|
@@ -125,14 +132,31 @@
|
|
|
|
|
|
loader.load( 'models/gltf/ferrari.glb', function ( gltf ) {
|
|
|
|
|
|
- carModel = gltf.scene.children[ 0 ];
|
|
|
+ var carModel = gltf.scene.children[ 0 ];
|
|
|
+
|
|
|
+ carModel.getObjectByName( 'body' ).material = bodyMaterial;
|
|
|
+
|
|
|
+ carModel.getObjectByName( 'rim_fl' ).material = detailsMaterial;
|
|
|
+ carModel.getObjectByName( 'rim_fr' ).material = detailsMaterial;
|
|
|
+ carModel.getObjectByName( 'rim_rr' ).material = detailsMaterial;
|
|
|
+ carModel.getObjectByName( 'rim_rl' ).material = detailsMaterial;
|
|
|
+ carModel.getObjectByName( 'trim' ).material = detailsMaterial;
|
|
|
+
|
|
|
+ carModel.getObjectByName( 'glass' ).material = glassMaterial;
|
|
|
+
|
|
|
+ wheels.push(
|
|
|
+ carModel.getObjectByName( 'wheel_fl' ),
|
|
|
+ carModel.getObjectByName( 'wheel_fr' ),
|
|
|
+ carModel.getObjectByName( 'wheel_rl' ),
|
|
|
+ carModel.getObjectByName( 'wheel_rr' )
|
|
|
+ );
|
|
|
|
|
|
// shadow
|
|
|
var texture = new THREE.TextureLoader().load( 'models/gltf/ferrari_ao.png' );
|
|
|
var shadow = new THREE.Mesh(
|
|
|
new THREE.PlaneBufferGeometry( 0.655 * 4, 1.3 * 4 ),
|
|
|
new THREE.MeshBasicMaterial( {
|
|
|
- map: texture, opacity: 0.7, transparent: true
|
|
|
+ map: texture, opacity: 0.4, transparent: true
|
|
|
} )
|
|
|
);
|
|
|
shadow.rotation.x = - Math.PI / 2;
|
|
@@ -141,126 +165,10 @@
|
|
|
|
|
|
scene.add( carModel );
|
|
|
|
|
|
- // car parts for material selection
|
|
|
- carParts.body.push( carModel.getObjectByName( 'body' ) );
|
|
|
-
|
|
|
- carParts.rims.push(
|
|
|
- carModel.getObjectByName( 'rim_fl' ),
|
|
|
- carModel.getObjectByName( 'rim_fr' ),
|
|
|
- carModel.getObjectByName( 'rim_rr' ),
|
|
|
- carModel.getObjectByName( 'rim_rl' ),
|
|
|
- carModel.getObjectByName( 'trim' ),
|
|
|
- );
|
|
|
-
|
|
|
- carParts.glass.push(
|
|
|
- carModel.getObjectByName( 'glass' ),
|
|
|
- );
|
|
|
-
|
|
|
- wheels.push(
|
|
|
- carModel.getObjectByName( 'wheel_fl' ),
|
|
|
- carModel.getObjectByName( 'wheel_fr' ),
|
|
|
- carModel.getObjectByName( 'wheel_rl' ),
|
|
|
- carModel.getObjectByName( 'wheel_rr' )
|
|
|
- );
|
|
|
-
|
|
|
- updateMaterials();
|
|
|
-
|
|
|
} );
|
|
|
|
|
|
}
|
|
|
|
|
|
- function initMaterials() {
|
|
|
-
|
|
|
- materialsLib = {
|
|
|
-
|
|
|
- main: [
|
|
|
-
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0xff4400, metalness: 1.0, roughness: 0.2, name: 'orange'
|
|
|
- } ),
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0x001166, metalness: 1.0, roughness: 0.2, name: 'blue'
|
|
|
- } ),
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0x990000, metalness: 1.0, roughness: 0.2, name: 'red'
|
|
|
- } ),
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0x000000, metalness: 1.0, roughness: 0.4, name: 'black'
|
|
|
- } ),
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0xffffff, metalness: 0.1, roughness: 0.2, name: 'white'
|
|
|
- } ),
|
|
|
- new THREE.MeshStandardMaterial( {
|
|
|
- color: 0xffffff, metalness: 1.0, roughness: 0.2, name: 'metallic'
|
|
|
- } )
|
|
|
-
|
|
|
- ],
|
|
|
-
|
|
|
- glass: [
|
|
|
-
|
|
|
- new THREE.MeshPhysicalMaterial( {
|
|
|
- color: 0xffffff, metalness: 0, roughness: 0, transparency: 1.0, transparent: true, name: 'clear'
|
|
|
- } ),
|
|
|
- new THREE.MeshPhysicalMaterial( {
|
|
|
- color: 0x000000, metalness: 0, roughness: 0, transparency: 0.7, transparent: true, name: 'smoked'
|
|
|
- } ),
|
|
|
- new THREE.MeshPhysicalMaterial( {
|
|
|
- color: 0x001133, metalness: 0, roughness: 0, transparency: 0.7, transparent: true, name: 'blue'
|
|
|
- } )
|
|
|
-
|
|
|
- ],
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function initMaterialSelectionMenus() {
|
|
|
-
|
|
|
- function addOption( name, menu ) {
|
|
|
-
|
|
|
- var option = document.createElement( 'option' );
|
|
|
- option.text = name;
|
|
|
- option.value = name;
|
|
|
- menu.add( option );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- materialsLib.main.forEach( function ( material ) {
|
|
|
-
|
|
|
- addOption( material.name, bodyMatSelect );
|
|
|
- addOption( material.name, rimMatSelect );
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- materialsLib.glass.forEach( function ( material ) {
|
|
|
-
|
|
|
- addOption( material.name, glassMatSelect );
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- bodyMatSelect.selectedIndex = 2;
|
|
|
- rimMatSelect.selectedIndex = 5;
|
|
|
- glassMatSelect.selectedIndex = 0;
|
|
|
-
|
|
|
- bodyMatSelect.addEventListener( 'change', updateMaterials );
|
|
|
- rimMatSelect.addEventListener( 'change', updateMaterials );
|
|
|
- glassMatSelect.addEventListener( 'change', updateMaterials );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // set materials to the current values of the selection menus
|
|
|
- function updateMaterials() {
|
|
|
-
|
|
|
- var bodyMat = materialsLib.main[ bodyMatSelect.selectedIndex ];
|
|
|
- var rimMat = materialsLib.main[ rimMatSelect.selectedIndex ];
|
|
|
- var glassMat = materialsLib.glass[ glassMatSelect.selectedIndex ];
|
|
|
-
|
|
|
- carParts.body.forEach( part => part.material = bodyMat );
|
|
|
- carParts.rims.forEach( part => part.material = rimMat );
|
|
|
- carParts.glass.forEach( part => part.material = glassMat );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
function onWindowResize() {
|
|
|
|
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
@@ -274,11 +182,6 @@
|
|
|
|
|
|
var time = - performance.now() / 1000;
|
|
|
|
|
|
- camera.position.x = Math.cos( time / 10 ) * 6;
|
|
|
- camera.position.y = 1.5;
|
|
|
- camera.position.z = Math.sin( time / 10 ) * 6;
|
|
|
- camera.lookAt( 0, 0.5, 0 );
|
|
|
-
|
|
|
for ( var i = 0; i < wheels.length; i ++ ) {
|
|
|
|
|
|
wheels[ i ].rotation.x = time * Math.PI;
|