How to load texture with transparent background and make it movable? - three.js

smile on shirt has black background
smile with transparent true
GOAL: I would like users to be able to add images/colors with buttons
PROBLEM: but the png image texture(smiley face) loaded with textureLoader() has black background and lines crossing the image. :frowning:
MINOR PROBLEM:
(1) Are there any ways to match the background color of the image and the obj/gltf(shirt) that I load?
Here are my codes.
const colorSelection = {
"pink": "#ff2d55",
"purple": "#5856d6",
"blue": "#007aff",
"orange": "#ff9500",
}
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({ antialias: true });
const loader = new THREE.OBJLoader();
const myCanvas = document.getElementById("container");
const controls = new THREE.OrbitControls(camera, renderer.domElement);
const axisHelper = new THREE.AxisHelper(5);
const hlight = new THREE.AmbientLight (0x404040);
const directionalLight = new THREE.DirectionalLight(0xffffff,0.4);
const geometry = new THREE.SphereGeometry(50,50,50);
const texture = new THREE.TextureLoader().load("assets/smile2.png");
const newMat = new THREE.MeshPhongMaterial({ map: texture });
myCanvas.appendChild( renderer.domElement );
renderer.setSize( 800, 800 );
renderer.setClearColor ("darkgrey", 1);
camera.position.set(200,300,200);
controls.addEventListener("change", animate);
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
// SCENES and LIGHTING
scene.add(axisHelper);
scene.add(hlight);
scene.add(directionalLight);
directionalLight.position.set(0,1155,325);
directionalLight.castShadow = true;
function changeTextureColor(color) {
loader.load("assets/standard-t-shirt/source/tshirt.obj", function(obj) {
obj.scale.set(0.4,0.4,0.4)
obj.position.set(0,-500,0)
obj.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material.emissive = new THREE.Color(colorSelection[color])
console.log(child.material)
}
})
console.log(obj.children)
obj.children[0].material = newMat
scene.add(obj)
})
}
document.querySelectorAll("button").forEach(colorBtn => colorBtn.addEventListener("click", function () {
console.log(this.id)
const userColor = this.id;
changeTextureColor(userColor);
}))
Thanks so much for reading!

You need the transparent: true setting when creating your material, like so:
const newMat = new THREE.MeshPhongMaterial({ map: texture, transparent: true });

Related

The DOM element created by CSS3DObject cannot be obscured by the GL plane

I found that it seems to be solved by setting the blending attribute of material, but it still cannot be solved after trying.
Incorrect occlusion
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader.js"
import {
CSS3DRenderer,
CSS3DObject
} from "three/examples/jsm/renderers/CSS3DRenderer.js"
import dat from "dat.gui"
function initThree() {
const scene = new THREE.Scene();
const scene2 = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
50,
window.innerWidth / window.innerHeight,
0.1,
10000
);
camera.position.set(0, 0, 2500);
scene.add(camera);
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector('#webgl').appendChild(renderer.domElement);
const labelRenderer = new CSS3DRenderer()
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
scene.add(new THREE.AxesHelper(1000))
const controls = new OrbitControls(camera, labelRenderer.domElement);
controls.enableDamping = true;
const clock = new THREE.Clock()
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
});
return {
scene,
scene2,
camera,
renderer,
labelRenderer,
controls,
clock,
}
}
const gltfLoader = new GLTFLoader()
const textureLoader = new THREE.TextureLoader()
const gui = new dat.GUI()
const {
scene,
scene2,
camera,
renderer,
labelRenderer,
controls,
clock
} = initThree();
const ambientLight = new THREE.AmbientLight("#ffffff", 1)
scene.add(ambientLight)
const position = new THREE.Vector3(0, 900, 300);
const rotation = new THREE.Euler(0, 0, 0);
const container = document.createElement('div');
container.style.width = '1000px';
container.style.height = '1000px';
container.style.opacity = '1';
container.style.background = '#1d2e2f';
const iframe = document.createElement('iframe');
iframe.src = "http://csyedu.top"
iframe.style.width = "1000px"
iframe.style.height = "1000px"
iframe.style.padding = 10 + 'px';
iframe.style.boxSizing = 'border-box';
iframe.style.opacity = '1';
container.appendChild(iframe);
const object = new CSS3DObject(container);
// copy monitor position and rotation
object.position.copy(position);
object.rotation.copy(rotation);
// Add to CSS scene
scene2.add(object);
// Create GL plane
const material = new THREE.MeshLambertMaterial();
material.side = THREE.DoubleSide;
material.opacity = 0;
material.transparent = true;
// NoBlending allows the GL plane to occlude the CSS plane
material.blending = THREE.NoBlending;
// Create plane geometry
const geometry = new THREE.PlaneGeometry(1000, 1000);
// Create the GL plane mesh
const mesh = new THREE.Mesh(geometry, material);
// Copy the position, rotation and scale of the CSS plane to the GL plane
mesh.position.copy(object.position);
mesh.rotation.copy(object.rotation);
mesh.scale.copy(object.scale);
// Add to gl scene
scene.add(mesh);
gltfLoader.load("./models/computer_setup.glb", model => {
const texture = textureLoader.load("./models/baked_computer.jpg");
texture.flipY = false;
texture.encoding = THREE.sRGBEncoding;
const material = new THREE.MeshBasicMaterial({
map: texture,
});
model.scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.scale.set(900, 900, 900);
child.material.map = texture;
child.material = material;
}
});
scene.add(model.scene)
})
function render() {
const elapsedTime = clock.getElapsedTime();
controls.update();
renderer.render(scene, camera);
labelRenderer.render(scene2, camera)
requestAnimationFrame(render);
}
render();
The effect I want is that the 3D mesh can correctly occlude the CSS3DObject.
I runned over the same problem, I'm trying your code and works good on my project, I think you have a styling problem.
I have separated the WebGL and CSS3DRenderer on the html.
<body>
<div id="css"></div>
<div id="webgl"></div>
</body>
#css,
#webgl
{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
If I only put the #css on absolute this is the result
If I put both in absolute it works fine.
I wish that'll help

Threejs: How to add a model to a canvas?

I need your help. I'm trying to add my model to a canvas I've added to the html-document. But the following code doesn't work:
function main() {
const container = document.querySelector( "#machine-model" );
let height = container.offsetHeight; // Offset height = element + padding + border + scrollbar
let width = container.offsetWidth;
const fov = 75;
const aspect = width / height;
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.x = 8.3;
camera.position.y = 11.7;
camera.position.z = -8;
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xFFFFFF ); // changes background color from black to white
const ambiLight = new THREE.AmbientLight( 0xFFFFFF, 0.5 );
scene.add( ambiLight );
const spotLight = new THREE.SpotLight( 0xFFFFFF, 0.6 );
spotLight.position.set( 13.6, 20.1, -13.9 );
spotLight.castShadow = true;
scene.add( spotLight );
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load( "model/M-62300-00-811-0_002.glb", function( gltf ) {
const model = gltf.scene;
model.rotateX( -Math.PI/2 );
console.log( model );
scene.add( model );
});
const renderer = new THREE.WebGLRenderer( { canvas: container, antialias: true, alpha: true } ); // alpha = true -> alpha = 0
renderer.setSize( width, height );
function render() {
renderer.render( scene, camera );
requestAnimationFrame( render );
}
requestAnimationFrame( render );
};
main();
Here's a link to working JSFiddle demo
If I add the id of my canvas to the canvas parameter of the renderer, I don't need to do it with appendChild, right?
Based on your fiddle, the canvas seems to be passed successfully. The problem instead seems to be your far distance, which you set to 5, even though you place your camera quite far away from the origin.
Try instead with a larger far value, say 1000.

How to use Orbit Controls and getting the errors in the orbital control

When i am using OrbitControls there is an error that is shown -- Uncaught TypeError: THREE.OrbitControls is not a constructor this is the error that i am getting after running in the firefox
Heading
enter code here
const canvas = document.querySelector('.webgl')
console.log(canvas)
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
// Sizes
const sizes = {
width: 1280,
height: 720
}
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xff0000);
// Cube
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: "#00FF00" })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
// Camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
camera.position.z = 3;
scene.add(camera)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enabledamping = true;
controls.update();
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera)
}
animate();
renderer.setSize(sizes.width, sizes.height)

three.js animating ball on a plane

Please i need help on three.js animation. trying to animate the ball randomly on the plane before stoping at specific or selected location on the plane. my code below please any help will be appreciates.
1: https://i.stack.imgur.com/3kXhW.png
Please i need help on three.js animation. trying to animate the ball randomly on the plane before stoping at specific or selected location on the plane. my code below please any help will be appreciates.
.
. .
import { OrbitControls } from "./libs/three128/OrbitControls.js";
import { GUI } from "./dat.gui.module.js";
class Game {
constructor() {
const container = document.createElement("div");
document.body.appendChild(container);
this.step = 0;
this.speed = 0.01;
this.camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.camera.position.set(-10, 150, 150);
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xaaaaaa);
const ambient = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 0.3);
this.scene.add(ambient);
const light = new THREE.DirectionalLight();
light.position.set(0.2, 1, 1);
this.scene.add(light);
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(this.renderer.domElement);
//Replace Box with Circle, Cone, Cylinder, Dodecahedron, Icosahedron, Octahedron, Plane, Sphere, Tetrahedron, Torus or TorusKnot
const planeGeometry = new THREE.BoxBufferGeometry(200, 200, 3);
const planeMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
side: THREE.DoubleSide,
});
this.plane = new THREE.Mesh(planeGeometry, planeMaterial);
this.scene.add(this.plane);
const ballGeometry = new THREE.SphereGeometry(8, 100, 100);
const ballMaterial = new THREE.MeshStandardMaterial({
color: 0x0000ff,
wireframe: false,
});
this.ball = new THREE.Mesh(ballGeometry, ballMaterial);
this.scene.add(this.ball);
const controls = new OrbitControls(this.camera, this.renderer.domElement);
this.gridHelper = new THREE.GridHelper(200);
this.scene.add(this.gridHelper);
this.input();
this.renderer.setAnimationLoop(this.render.bind(this));
window.addEventListener("resize", this.resize.bind(this));
}
input() {
const gui = new GUI();
let ball = this.ball;
let plane = this.plane;
ball.position.set(0, 9.5, 0);
const options = {
ballColor: ball.material.color.getHex(),
planeColor: plane.material.color.getHex(),
positionX: ball.position.x,
positionZ: ball.position.z,
wireframe: false,
};
gui
.add(options, "positionX", -100, 100)
.name("X-coodinate")
.onChange(function (value) {
ball.position.x = value;
console.log(value);
});
gui
.add(options, "positionZ", -100, 100)
.name("Y-coodinate")
.onChange(function (value) {
ball.position.z = value;
console.log(value);
});
gui
.addColor(options, "ballColor")
.name("Ball-Color")
.onChange(function (value) {
ball.material.color.set(value);
});
gui
.addColor(options, "planeColor")
.name("Plane-Color")
.onChange(function (value) {
plane.material.color.set(value);
});
// gui.add(ball.material, "wireframe").name("Wireframe");
}
resize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
render() {
this.plane.rotation.x = -0.5 * Math.PI;
this.renderer.render(this.scene, this.camera);
}
}
export { Game };
project picture.

Render transparent bottle in threejs

I have created bottle in blender. If i test it on threejs editor it is giving right results.
But when I render it on my site it is giving
This as output. I am but new to threejs
import './style.css'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const updateAllMaterials = () =>
{
scene.traverse((child) =>
{
if(child instanceof THREE.Mesh)
{
child.material.envMap = environmentMap
child.material.transparent = true
child.material.opacity = 0.1
child.material.envMapIntensity = 5
const material = new THREE.MeshPhysicalMaterial( {
transmission: 1, // use material.transmission for glass materials
opacity: 0.2,
color:"blue",
transparent: true
} );
child.material = material
}
})
}
// Canvas
const canvas = document.querySelector('canvas.webgl')
const gltfLoader = new GLTFLoader()
gltfLoader.load('/models/wine5.glb',(bottle)=>{
bottle.scene.scale.set(0.5,0.45,0.5)
bottle.scene.rotation.set(-0.5,1,0.3)
bottle.scene.position.set(-1,-1.5,2)
updateAllMaterials()
scene.add(bottle.scene)
})
// Scene
const scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );
const directionalLights = new THREE.PointLight('#fff',4)
directionalLights.position.set(-0.4,2,5)
scene.add(directionalLights)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
scene.add(camera)
// ENV MAPS
const singleTextureLoader = new THREE.TextureLoader()
singleTextureLoader.load('/BG/tree.jpg',(img)=>{
scene.background = img
})
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.physicallyCorrectLights = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 1
renderer.depth = false
Your updateAllMaterials() is traversing an empty scene, thus not applying the material to anything. Just swap the calls like this:
scene.add(bottle.scene)
updateAllMaterials()
Also, inside the updateAllMaterials() function, you are changing some parameters of the child's material, and then you overwrite the material itself, losing all the changes.
It should be something like this:
const material = new THREE.MeshPhysicalMaterial({
transmission: 1,
opacity: 0.2,
color:"blue",
transparent: true,
envMap: environmentMap,
transparent: true,
opacity: 0.1,
envMapIntensity: 5
});
child.material = material

Resources