ThreeJS videoTexture linear workflow - three.js

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

Ready Player Me Avatar texture/lightning rendering in ThreeJS and Matterport

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 new to threejs, how to create a sky dome

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);
};

Transparant spritesheet animation for webgl

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.

Using Video as texture with Three.js

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);

How to repeat the texture map like GL_REPEAT?

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.
=)

Resources