I'm using a three VideoTexture in my R3F App. Unfortunatly its not gamma corrected so my video seems washed out. I tried setting the encoding to sRGBEncoding for my texture, but that doesn't seem to do anything. Also there is nothing about encoding in the three docs of videotexture.
How can i set RGBEncoding on VideoTextures?
thanks in advance.
Here is my texture:
import {
MeshStandardMaterial,
VideoTexture,
sRGBEncoding,
} from "three";
const textureVid = document.createElement("video");
textureVid.src = "assets/video/test.mp4";
textureVid.play();
const videoTexture = new VideoTexture(textureVid);
videoTexture.encoding = sRGBEncoding;
const matTVScreen = new MeshStandardMaterial({
color: 0x000000,
map: videoTexture,
});
So basically my code was right. I had to delete my Browser cache to see these changes.
Related
I try to import a Ready Player Me GLB avatar into a Matterport scene (in ThreeJS).
It works but the avatar is very flat (left picture) compared to the rendering into RPM (right picture) or basic GLTF Viewer. I don't understand what I missed ? Pseudo code :
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load('https://api.readyplayer.me/v1/avatars/63580183b445da7aa57b9ce3.glb',
(gltf) => {
this.mesh = gltf.scene;
const light = new THREE.AmbientLight( 0xFFFFFF, 1 );
light.castShadow = true
this.mesh.add( light );
...
}, undefined);
On the WebGL part I have access to Matterport renderer :
(renderer, THREE, effectComposer) => {
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
}
Is it related to Antialias ? Or a paramter or lighting that flatten hair and hands ? Or is it related to texture ?
Thanks !
EDIT 11/12/2022:
Thanks to #Mugen87, I find how to use the EquirectangularShader from GLTFLoader sample. This code works with Matterport context.
let pmremGenerator = new THREE.PMREMGenerator( this.context.renderer );
pmremGenerator.compileEquirectangularShader();
let envMap = pmremGenerator.fromScene( new THREE.RoomEnvironment() ).texture;
this.context.scene.environment = envMap;
Instead of using a single instance of AmbientLight, apply a more advanced type of environmental lighting to your scene. Especially if you already enabled tone mapping, consider to use a HDR environment map. The basic GLTFLoader example of three.js is a good code template. The most important part is:
new RGBELoader()
.load( 'textures/equirectangular/royal_esplanade_1k.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
// more scene setup
} );
Applying an environment map to Scene.environment ensures all PBR materials in the scene are going to use it.
I'm pretty new to three.js and I tried for hours to create a skybox/skydome for a better visual feeling to my world (in this case space). Googled, checked tutorials, asked here on StackOverflow. And nothing worked, or I got a silly and dumb answer here on SO. Question is simple: how to make a skybox/dome?
This is how you do a skydome in threejs.
var skyGeo = new THREE.SphereGeometry(100000, 25, 25);
First the geometry. I wanted it big and made it big
var loader = new THREE.TextureLoader(),
texture = loader.load( "images/space.jpg" );
Loads the texture of your background space. One thing here is that you need it to run through a server to be able to load the texture. I use wamp or brackets preview.
Create the material for the skybox here
var material = new THREE.MeshPhongMaterial({
map: texture,
});
Set everything together and add it to the scene here.
var sky = new THREE.Mesh(skyGeo, material);
sky.material.side = THREE.BackSide;
scene.add(sky);
This might not be the best solution for this, but it´s easy specially for a beginner in threejs. Easy to understand and create.
This is how you can load image as texture and apply that on innerside of a sphere geometry to emulate skydome.
Complete solution with error callback for future reference
//SKY
var loader = new THREE.TextureLoader();
loader.load(
"./assets/universe.png",
this.onLoad,
this.onProgress,
this.onError
);
onLoad = texture => {
var objGeometry = new THREE.SphereBufferGeometry(30, 60, 60);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
objMaterial.side = THREE.BackSide;
this.earthMesh = new THREE.Mesh(objGeometry, objMaterial);
scene.add(this.earthMesh);
//start animation
this.start();
};
onProgress = xhr => {
console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
};
// Function called when download errors
onError = error => {
console.log("An error happened" + error);
};
I'm just getting started with webgl and was trying to make an animation based on a spritesheet. I've found an example and changed the spritesheet to my own. However even though I removed the white background, saved it as a transparant png, the animation still shows up with a white background.
This is the example I used:
http://stemkoski.github.io/Three.js/Texture-Animation.html
Is there any way how I can get rid off the white background?
Thanks in advance.
EDIT:
var runnerTexture = new THREE.ImageUtils.loadTexture( 'images/run.png' );
annie = new TextureAnimator( runnerTexture, 10, 1, 10, 75 ); // texture, #horiz, #vert, #total, duration.
var runnerMaterial = new THREE.MeshBasicMaterial( { map: runnerTexture, side:THREE.DoubleSide } );
var runnerGeometry = new THREE.PlaneGeometry(50, 50, 1, 1);
var runner = new THREE.Mesh(runnerGeometry, runnerMaterial);
runner.position.set(-150,25,0);
scene.add(runner);
To support PNGs with an alpha-channel, you have to modify the MeshBasicMaterial accordingly: There is an attribute 'transparent' which you could set to 'true'.
Try using the following line instead:
var runnerMaterial = new THREE.MeshBasicMaterial( { map: runnerTexture, side:THREE.DoubleSide, transparent: true } );
See also the reference from Material:
.transparent
Defines whether this material is transparent. This has an effect on
rendering as transparent objects need special treatment and are
rendered after non-transparent objects. For a working example of this
behaviour, check the WebGLRenderer code. When set to true, the extent
to which the material is transparent is controlled by setting opacity.
I am trying to create a simple rectangle with a .mp4 video as texture. As per three.js documentation(http://threejs.org/docs/#Reference/Textures/Texture) this should be straight forward.
When I am putting link of video, all I am getting is a black colored box with no texture on it. I have tested code by replacing video with a jpg image and it works fine. Can someone please explain me what I am doing wrong.
I have already seen the examples in which video is played by first linking it to a video element and then copy the frames on a canvas. I want to try the direct way as mentioned in the three.js documentation.
Think of video as a sequence of images. So to "play" this video on your 3D object - you'll have to pass every single frame of that sequence to your material and then update that material.
Good place to start is here: https://github.com/mrdoob/three.js/wiki/Updates
And here: http://stemkoski.github.io/Three.js/Video.html
Step 1:
Add a video to your HTML and "hide" it:
<video id="video" playsinline webkit-playsinline muted loop autoplay width="320" height="240" src="some-video.mp4" style="display: none;"></video>
Step 2:
//Get your video element:
const video = document.getElementById('video');
//Create your video texture:
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial( {map: videoTexture, side: THREE.FrontSide, toneMapped: false} );
//Create screen
const screen = new THREE.PlaneGeometry(1, 1);
const videoScreen = new THREE.Mesh(screen, videoMaterial);
scene.add(videoScreen);
In addition to Haos' answer, I needed to set videoTexture.needsUpdate = true; and videoMaterial.needsUpdate = true;. Also I've played the video on onloadeddata.
//Get your video element:
const video = document.getElementById("video");
video.onloadeddata = function () {
video.play();
};
//Create your video texture:
const videoTexture = new THREE.VideoTexture(video);
videoTexture.needsUpdate = true;
const videoMaterial = new THREE.MeshBasicMaterial({
map: videoTexture,
side: THREE.FrontSide,
toneMapped: false,
});
videoMaterial.needsUpdate = true;
//Create screen
const screen = new THREE.PlaneGeometry(10, 10);
const videoScreen = new THREE.Mesh(screen, videoMaterial);
scene.add(videoScreen);
I have a house model in my game, and I have some materials for the house geometry. There is a material for the wall of the house, and I have a texture-map-image to show the bricks.
var mat = new THREE.MeshPhongMaterial( {
ambient: 0x969696,
map: THREE.ImageUtils.loadTexture( 'textures/G/G0.jpg' ),
overdraw: true,combine: THREE.MultiplyOperation
} );
In this way above, the texture map appears like GL_CLAMP I want it to show like GL_REPEAT.
What should I do?
If you can not see the images check this.
I have posted a full working example at:
http://stemkoski.github.com/Three.js/Texture-Repeat.html
The relevant part of the code example is:
// for example, texture repeated twice in each direction
var lavaTexture = THREE.ImageUtils.loadTexture( 'images/lava.jpg' );
lavaTexture.wrapS = lavaTexture.wrapT = THREE.RepeatWrapping;
lavaTexture.repeat.set( 2, 2 );
var lavaMaterial = new THREE.MeshBasicMaterial( { map: lavaTexture } );
var lavaBall = new THREE.Mesh( THREE.GeometryUtils.clone(sphereGeom), lavaMaterial );
scene.add( lavaBall );
It's called THREE.RepeatWrapping there. The loadTexture defaults to THREE.ClampToEdgeWrapping (see ctor function from previous link). Don't know if you can use the callback (because this in JS is a bit weird (looks like it points to the created Image, not the created Texture)). Signature:
loadTexture: function ( path, mapping, callback ) {
Better you just name the texture locally and set the wrap modes manually:
var t = THREE.ImageUtils.loadTexture( 'textures/G/G0.jpg' );
t.wrapS = t.wrapT = THREE.RepeatWrapping;
Looks like you're not going far with threejs without looking at the actual code...
Image must be 8x8, 16x16, 32x32, 128x128, 256x256, 512x512 etc.
And all be working.
=)