Three.js Object3D custom vertex shader - three.js

I have a bunch of Object3d in the scene comprised of different meshes, e.g:
const object3d = new Object3D();
const bodyMaterial = new MeshLambertMaterial();
const bezelMaterial = new MeshBasicMaterial({ color: "0xffffff" });
const mesh = new Mesh(MeshFactory.mesh1, [ bodyMaterial, bezelMaterial ]);
const textLabel = TextFactory.createText("mesh1");
object3d.add(mesh, textLabel);
I'd like to move the position of the object3d on each frame,
currently doing that on the CPU:
render() {
object3D.position = calcPosition(); // new Vector3
}
This is slow since I have hundreds of Object3d objects and each one should move separately.
So I'd like to write a vertex shader that moves the xyz on each frame but,
how do I write a shader for Object3D? (change position for all of it's meshes)?

Sounds like you might be going about things the wrong way...
But..
Here is a basic example of vertex displacement in a shader in three.js.
Rotation is done in the render loop, but offset values are sent to the vertex shader.
var camera, scene, renderer, mesh, material;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
// Create scene.
scene = new THREE.Scene();
// Create material
var uniforms = {
xOffset: { type: "f", value: 0.0 },
yOffset: { type: "f", value: 0.0 },
zOffset: { type: "f", value: 0.0 }
};
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial(
{
uniforms : uniforms,
vertexShader : vertexShader,
fragmentShader : fragmentShader
});
// Create cube and add to scene.
var geometry = new THREE.BoxGeometry(200, 200, 200);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
// set up gui.
var gui = new dat.GUI();
gui.add(uniforms.xOffset, 'value', -500, 500).name('X Offset');
gui.add(uniforms.yOffset, 'value', -500, 500).name('Y Offset');;
gui.add(uniforms.zOffset, 'value', -500, 500).name('Z Offset');;
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
<script src="https://rawgit.com/mrdoob/three.js/r89/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/dataarts/dat.gui/v0.6.2/build/dat.gui.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
uniform float xOffset;
uniform float yOffset;
uniform float zOffset;
void main( void ) {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position + vec3(xOffset, yOffset, zOffset),1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>

Related

How to change uniform values of custom shader in three.js?

I've created a custom shader that shows assigned values of vertices with contour mapping.Here is the fiddle example of my shader.
<html lang="en">
<head>
<title>Face Contour Example</title>
</head>
<body>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="http://threejs.org/examples/js/modifiers/SubdivisionModifier.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<script type="x-shader/x-vertex" id="vertexShader">
varying vec3 vColor;
void main(){
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
varying vec3 vColor;
uniform vec3 uVec3Array[ 6 ];
void main(){
float r=vColor.r;
int numberOfColor=6;
float step=1.0/float(numberOfColor);
int index = int(r/step);
for(int i=0;i<6;i++){
if(i==index){
vec3 fragColor= uVec3Array[i];
gl_FragColor=vec4(fragColor,1.0);
}
}
// gl_FragColor=vec4(vColor,0);
}
</script>
<script type="text/javascript">
var camera, scene, renderer, mesh, material, controls;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 3;
// Create scene.
scene = new THREE.Scene();
var palette1={
"uVec3Array" : {
type: "v3v",
value: [
new THREE.Vector3( 0,0,1.0),
new THREE.Vector3( 66/255, 238/255, 244/255 ),
new THREE.Vector3( 0,1,0 ),
new THREE.Vector3( 1,1,0 ),
new THREE.Vector3( 1,0.4,0.2),
new THREE.Vector3( 1,0,0 )
] }
}
var palette2={
"uVec3Array" : {
type: "v3v",
value: [
new THREE.Vector3( 1,0,0 ),
new THREE.Vector3( 1,0.4,0.2),
new THREE.Vector3( 1,1,0 ),
new THREE.Vector3( 0,1,0 ),
new THREE.Vector3( 66/255, 238/255, 244/255 ),
new THREE.Vector3( 0,0,1.0)
] }
}
var selectedPalette=palette1;
// var fShader = document.getElementById('smoothPlotFShader').text;
// var vShader = document.getElementById('vertexShader').text;
var material;
var vertexShader=document.getElementById('vertexShader').textContent;
var fragmentShader= document.getElementById('fragmentShader').textContent ;
var material = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
vertexColors: THREE.VertexColors,
uniforms:selectedPalette,
side:2
});
// var wireframe = new THREE.MeshLambertMaterial({color: 0x7777ff,wireframe:true});
var cubeGeometry = new THREE.CubeGeometry( 1,1,1 );
var modifier = new THREE.SubdivisionModifier( 3 );
modifier.modify( cubeGeometry );
var cube = new THREE.Mesh( cubeGeometry, material );
scene.add( cube );
//Create value array linearyly
var numberOfValues=cubeGeometry.vertices.length;
var maxValue=30;
var minValue=-30;
var values=[]
for(var i=0;i<numberOfValues;i++){
values.push(minValue+(maxValue-minValue)*i/numberOfValues);
}
applyValuesToMesh(values,cube);
//Orbit controls
controls = new THREE.OrbitControls( camera );
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
function switchPlatte(){
if(selectedPalette===palette1){
selectedPalette=palette2;
}else{
selectedPalette=palette1;
}
material.uniforms=selectedPalette;
material.needsUpdate=true;
cube.geometry.elementsNeedUpdate = true;
console.log("Material colors are changed");
}
//This button switches plattes of material
var gui = new dat.GUI();
var obj = { changeColors:switchPlatte}
gui.add(obj,'changeColors');
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
var mesh;
function applyValuesToMesh(result,mesh){
var max=findMax(result);
var min=findMin(result);
function normalizeValue(value){
var range=max-min;
return (value-min)/range;
}
var normalizedResult=[];
for (r in result){
normalizedResult.push(normalizeValue(result[r]));
}
var numberOfNodes=mesh.geometry.vertices.length;
var faces=mesh.geometry.faces;
// debugger
for(f in faces){
faces[f].vertexColors[0]=new THREE.Color(normalizedResult[faces[f].a],0.5,0.5);
faces[f].vertexColors[1]=new THREE.Color(normalizedResult[faces[f].b],0.5,0.5);
faces[f].vertexColors[2]=new THREE.Color(normalizedResult[faces[f].c],0.5,0.5);
}
mesh.geometry.elementsNeedUpdate = true;
}
function findMax(array){
var max=-Infinity;
for (v in array){
if(array[v]>max) max=array[v];
}
return max;
}
function findMin(array){
var min=Infinity;
for (v in array){
if(array[v]<min) min=array[v];
}
return min;
}
</script>
</body>
The code may seem complicated. Basically, I am creating a subdivided cube and adding vertex colors to each face. However, vertex colors represent values (values can be anything, doesn't need to depend on geometry), not colors. If you look my shader, it extracts .r value of vertex colors and gets the corresponding color to that value from input uniforms. So basically material uniforms are the colors that will be used while plotting values of vertices.
My issue is If I change colors (uniforms) after the material is created; changes don't affect the material.
In the bottom of the code, I've added a gui button which switches colors (uniforms) of material when pressed. I've tried material needs update, elements need update and all the other updates presented by documentation but changes didn't be applied.
So how can I change those uniforms after material is created.
You are updating the uniform in the wrong way. Just set the uniform once and update only the value property with the new vectors. The following fiddle demonstrates this approach: http://jsfiddle.net/50u0rwb4/18/
BTW: The following statements are not necessary when updating the uniform.
material.needsUpdate = true;
cube.geometry.elementsNeedUpdate = true;

How to prevent interpolation of vertex colors in THREE.js shader?

I am trying to write a shader that draws contour plots on meshes.
Here is an example of contour plot.
My first aim is visualizing one triangle face with different colors.
You can find the code that I am using in here.
<html lang="en">
<head>
<title>Face Contour Example</title>
</head>
<body>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main(){
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec3 vColor;
void main(){
gl_FragColor = vec4( vColor.rgb, 1.0 );
}
</script>
<script type="text/javascript">
var camera, scene, renderer, mesh, material, controls;
init();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = -400;
// Create scene.
scene = new THREE.Scene();
var colors = {
"color1" : {
type : "c",
value : new THREE.Color(0xff0000) //r
},
"color2" : {
type : "c",
value : new THREE.Color(0x00ff00) //b
},
"color3" : {
type : "c",
value : new THREE.Color(0x0000ff) //g
},
};
var fShader = document.getElementById('fragmentShader').text;
var vShader = document.getElementById('vertexShader').text;
// Create material
var material = new THREE.ShaderMaterial({
vertexShader: vShader,
fragmentShader: fShader,
vertexColors: THREE.VertexColors,
});
// var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } );
// Create cube and add to scene.
var geometry = new THREE.Geometry();
geometry.vertices=[
new THREE.Vector3(100,0,0),
new THREE.Vector3(-100,0,0),
new THREE.Vector3(50,100,0)
]
var face=new THREE.Face3();
face.a=0;
face.b=1;
face.c=2;
face.vertexColors[ 0 ] = colors["color1"].value;
face.vertexColors[ 1 ] = colors["color2"].value;
face.vertexColors[ 2 ] = colors["color3"].value;
geometry.faces=[face]
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
function addWireFrame(){
//Create wireframe helper for mesh with same geometry
var wireframeMesh=new THREE.WireframeGeometry(geometry);
var line = new THREE.LineSegments( wireframeMesh );
line.material.depthTest = false;
line.material.opacity = 0.75;
line.material.transparent = true;
mesh.add( line );
}
addWireFrame();
//Orbit controls
controls = new THREE.OrbitControls( camera );
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
In the code I assigned red, green and blue colors to each vertices of a face.
In vertex shader, I redirected those colors to fragment shader. And In fragment shader, I am planning to use my own formula to decide which color will be used for that instance of the fragment. (My formula will depend on the position on the face.)
However, I couldn't manage to prevent interpolation of vertex colors. Is there a way to pick vertex color from an array directly without interpolation in three.js?
Also, I appreciate alternative solutions that may be suitable for my problem.
You don't want to disable interpolation. You want, instead, to use the interpolated coordinates as an index. The interpolated color value tells you how close you are to each of the vertices. You can then quantize this interpolated value into ranges, or indexes into a color array, to produce the end color.
I modified your fiddle to show the color of the closest vertex using the following pixel shader:
void main(){
vec3 c = vColor;
gl_FragColor = vec4(c.r > c.g && c.r > c.b ? 1.0 : 0.0,
c.g > c.r && c.g > c.b ? 1.0 : 0.0,
c.b > c.r && c.b > c.g ? 1.0 : 0.0,
1.0 );
}
The result looks like this:
You will need a more complex quantization method to show a contour map, but I hope this approach gives you a good start.

ThreeJS - Material which shows surface structure in a scene without light

In my scene I render complex objects, which have a complex surface structure. Furthermore I am not using light in my scene and I am trying to avoid it.
For now I am using the MeshNormalMaterial which shows perfectly the surface structures of my objects.
object with MeshNormalMaterial:
But I want to render certain objects with a unique color (e.g. from dark red to light red based on the surface structure/ similar to the MeshNormalMaterial).
I tried the MeshDepthMaterial for one object, but it rendered the whole object in almost color (no/ sparse color gradation) and not as expected like in this example. Independent of the camera position.
Same object from above with: MeshDepthMaterial
I am using a THREE.PerspectiveCamera with THREE.OrbitControls. Camera properties:
//camera attributes
public fieldOfView: number = 60;
public nearClippingPane: number = 0.1;
public farClippingPane: number = 50000;
Does the MeshNormalMaterial require light or why is this the case? Can I somehow amplify the depth effect of MeshNormalMaterial?
Is ist possible to restrict the RGB Colors of MeshNormalMaterial or do I have to use another Material for my purpose?
I just slightly modified the code of the fragment shader from this SO answer, so all credits to Rabbid76:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var colors = {
color1: "#ff0000",
color2: "#ffaaaa"
}
var geometry = new THREE.TorusKnotBufferGeometry(2, 0.5, 100, 16);
var material = new THREE.ShaderMaterial({
uniforms: {
color1: {
value: new THREE.Color(colors.color1)
},
color2: {
value: new THREE.Color(colors.color2)
}
},
vertexShader: vertShader,
fragmentShader: fragShader
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var gui = new dat.GUI();
gui.addColor(colors, "color1").onChange(function(value) {
material.uniforms.color1.value.set(value);
});
gui.addColor(colors, "color2").onChange(function(value) {
material.uniforms.color2.value.set(value);
});
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
<script>
var vertShader = `
varying vec3 vNormal;
void main(void)
{
vNormal = normalMatrix * normalize(normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`;
var fragShader = `
uniform vec3 color1;
uniform vec3 color2;
varying vec3 vNormal;
void main(void)
{
vec3 view_nv = normalize(vNormal);
vec3 nv_color = view_nv * 0.5 + 0.5;
vec3 c = mix(color1, color2, nv_color.r);
gl_FragColor = vec4(c, 1.0);
}
`;
</script>

Multiple textures overlapping webGL

I have two objects that I need to render in two different textures using WebGLRenderTarget. After mapping both textures to a plane using shaders and then adding that plane to the main scene, I am having issues drawing the closer object.
I have created a jsfiddle to show my issue: https://jsfiddle.net/11qb7ay7/82/
The real magic occurs here:
void main() {
vec4 color = texture2D(tex_sphere, vUv);
vec4 color_cube = texture2D(tex_cube, vUv);
gl_FragColor = vec4(color.rgb * color_cube.rgb, 1.0);
}
The sphere is placed in front of the cube relative to the camera. How can I draw the sphere pixels instead of the cubes when they overlap?
To be clear, I am trying to find a way to compute the distance from camera of each pixel and render the closer one first
In general if tex_sphere has an alpha channel the you can mix the colors by the alpha channel:
void main()
{
vec4 color = texture2D(tex_sphere, vUv);
vec4 color_cube = texture2D(tex_cube, vUv);
vec3 mixCol = mix(color_cube.rgb, color.rgb, color.a);
gl_FragColor = vec4(mixCol.rgb, 1.0);
}
If the tex_sphere has a black background, which should be omitted, the you have to check if the color of tex_sphere is not black:
void main()
{
vec4 color = texture2D(tex_sphere, vUv);
vec4 color_cube = texture2D(tex_cube, vUv);
vec3 test = step(1.0/512.0, color.rgb);
float a = max(max(test.r, test.g), test.b);
vec3 mixCol = mix(color_cube.rgb, color.rgb, a);
gl_FragColor = vec4(mixCol.rgb, 1.0);
}
Note, mix interpolates between 2 values according to a floating point interpolation value a in the range [0.0, 1.0]. If the a is equal 0.0 then the 1st value is returned and if the a is equal 1.0 then the 2nd value is returned.
step tests whether a value is less than an edge value. If it is less then 0.0 is returned, else 1.0 is returned.
To get a black background you have to set a black "clear" color when you render the sphere to the render target:
function render() {
controls.update();
renderer.setClearColor(0x00);
renderer.render(sphereScene, camera, renderTargets.sphere, true);
renderer.setClearColor(0xccccff);
renderer.render(cubeScene, camera, renderTargets.cube, true);
renderer.setClearColor(0xccccff);
renderer.render(scene, camera);
}
If you want to use an alpha channel, the you have to set setClearAlpha before you render to the render target:
function render() {
controls.update();
renderer.setClearAlpha(0);
renderer.render(sphereScene, camera, renderTargets.sphere, true);
renderer.setClearAlpha(1);
renderer.render(cubeScene, camera, renderTargets.cube, true);
renderer.render(scene, camera);
}
var scene, renderer, camera, controls;
var cubeScene, sphereScene;
var renderTargets;
init();
animate();
function init() {
scene = new THREE.Scene();
cubeScene = new THREE.Scene();
sphereScene = new THREE.Scene();
renderer = new THREE.WebGLRenderer( { antialias: false, alpha: true } );
renderer.setClearColor(0xccccff);
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 4000 );
camera.position.set(0, 0, 200);
renderer.setSize( window.innerWidth, window.innerHeight );
controls = new THREE.OrbitControls(camera, renderer.domElement);
camera.lookAt( scene.position );
var light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
scene.add( light );
container = document.createElement('div');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
initObjects();
initRenderTargets(window.innerWidth, window.innerHeight);
}
function onResize() {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderTargets.sphere.setSize( window.innerWidth, window.innerHeight );
renderTargets.cube.setSize( window.innerWidth, window.innerHeight );
}
function initObjects() {
var cGeometry = new THREE.BoxGeometry( 100, 100, 100 );
var cMaterial = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var cube = new THREE.Mesh( cGeometry, cMaterial );
cube.position.z = -210;
cube.position.y = 100;
var sGeometry = new THREE.SphereGeometry( 75, 32, 32 );
var sMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000
});
var sphere = new THREE.Mesh( sGeometry, sMaterial );
sphere.position.z = -100;
sphereScene.add( sphere );
cubeScene.add( cube );
}
function initRenderTargets(width, height){
renderTargets = createRenderTargets(width, height);
var uniforms = {
"tex_cube": { type: "t", value: renderTargets.cube.texture },
"tex_sphere": { type: "t", value: renderTargets.sphere.texture }
}
material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('vs_rt').textContent,
fragmentShader: document.getElementById('fs_rt').textContent
});
var plane = new THREE.PlaneGeometry(width, height);
quad = new THREE.Mesh(plane, material);
scene.add(quad);
}
function createRenderTargets(width, height) {
var parameters = {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
};
return {
cube: new THREE.WebGLRenderTarget( width, height, parameters ),
sphere: new THREE.WebGLRenderTarget( width, height, parameters )
};
}
function animate() {
requestAnimationFrame(animate);
render();
}
//------------------------------------------
// Main rendering
//------------------------------------------
function render() {
controls.update();
renderer.setClearAlpha(0);
renderer.render(sphereScene, camera, renderTargets.sphere, true);
renderer.setClearAlpha(1);
renderer.render(cubeScene, camera, renderTargets.cube, true);
renderer.render(scene, camera);
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script>
<script type="text/javascript" src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vs_rt" type="x-shader/x-vertex">
uniform sampler2D tex_cube;
uniform sampler2D tex_sphere;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fs_rt" type="x-shader/x-fragment">
uniform sampler2D tex_cube;
uniform sampler2D tex_sphere;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tex_sphere, vUv);
vec4 color_cube = texture2D(tex_cube, vUv);
vec3 mixCol = mix(color_cube.rgb, color.rgb, color.a);
gl_FragColor = vec4(mixCol.rgb, 1.0);
}
</script>

THREE.JS Shader texture

I'm just looking to create a simple Fragment Shader that draws a specified texture to the mesh. But I can´t display it. I can display the texture file in a basic gemetry, but not work with shaders the only result in a black sphere.
I don´t know what is wrong. Any help would be appreciated!
I am using Three.js THREE.WebGLRenderer 81
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec2 vUv;
uniform sampler2D texture1;
void main() {
gl_FragColor = texture2D(texture1, vUv); // Displays black sphere
//gl_FragColor = vec4(0.5, 0.2, 1.0, 1.0); // Works; Displays Color
}
</script>
<script>
// Initialize WebGL Renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
//var canvas = document.getElementById('canvas').appendChild(renderer.domElement);
document.body.appendChild( renderer.domElement );
renderer.setClearColor(0x888888, 1.0);
// Initialize Scenes
var scene = new THREE.Scene();
// Initialize Camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100);
camera.position.z = 10;
// Create Light
var light = new THREE.PointLight(0xFFFFFF);
light.position.set(0, 0, 500);
scene.add(light);
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(100,250,100);
scene.add(light);
// Create Ball
var vertShader = document.getElementById('vertexShader').textContent;
var fragShader = document.getElementById('fragmentShader').textContent;
var textura = new THREE.TextureLoader().load('./funkyGround.jpg');
var uniforms = {
texture1: { type: 't', value: textura }
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var ball = new THREE.Mesh(new THREE.SphereGeometry(1, 50, 50), material);
scene.add(ball);
// Render the Scene
renderer.render(scene, camera);
</script>
</body>
After a review, I can find the solution including a render() function
function render() {
requestAnimationFrame( render );
renderer.render( scene, camera );
}
render();

Resources