THREE.js Color texture by shader - javascript

i've added simple box to my scene, and I want to create shader that will add a texture to it and add color to this texture.
This is my vertex shader(nothing special about it):
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
And this is my fragment shader:
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 resolution;
uniform float time;
uniform sampler2D texture;
varying vec2 vUv;
uniform vec3 color;
varying vec3 vColor;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / vec2(1920.0, 1920.0);
fragColor = vec4(uv, 0.5 + 0.5 * cos(time) * sin(time) ,1.0);
}
void main( void ) {
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, gl_FragCoord.xy );
color.w = 1.0;
gl_FragColor = texture2D(texture, vUv);
gl_FragColor = color;
}
</script>
As You can see, in two last lines i've sets gl_FragColor with texture and color.
When last line is gl_FragColor = color; The result is:
When i change order and last line is gl_FragColor = texture2D(texture, vUv); The result is:
This is the code that use shader and add a box to a scene:
var geometry = new THREE.BoxGeometry(.5, 1, .5);
uniforms = {
time: { type: "f", value: 1.0 },
resolution: { type: "v2", value: new THREE.Vector2() },
texture: { type: "t", value: THREE.ImageUtils.loadTexture("../img/disc.png") }
};
var material = new THREE.ShaderMaterial({
transparent: true,
uniforms: uniforms,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Is there a possibility to color my texture(mix color and texture in object) by this shader in the same way like in the picture?

Just like any other variable setting it twice just makes it the 2nd result;
var foo;
foo = 123;
foo = 456;
foo now equals 456
If you want to combine the results you need to something yourself to combine them
gl_FragColor = texture2D(texture, vUv);
gl_FragColor = color;
Just means gl_FragColor equals color;
I'm guessing you want something like
gl_FragColor = texture2D(texture, vUv) * color;
But of course what math you use is up to you depending on what you're trying to achieve.
Given your example texture and color above multiplying the texture by the color you'll get a circle with a gradient color. It's not clear if that's the result you wanted.

Related

How to pass and use a lookup table in a shader with three.js

I have written a simple three.js of using a height map. This is the relevant code that creates the shader material:
function loadHeightMap() {
// fake a lookup table
var lut = [];
for ( var n=0; n<256; n++ ) {
lut.push(new THREE.Vector3(0.5, 0.4, 0.3));
}
var loader = new THREE.TextureLoader();
var zScale = 10;
var mapLoc = "https://s22.postimg.org/8n93ehmep/Terrain128.png";
loader.load(mapLoc, function ( texture ) {
// use "this." to create global object
this.customUniforms = {
zTexture: { type: "t", value: texture },
zScale: { type: "f", value: zScale },
zLut: { type: "v3v", value: lut }
};
var customMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
side: THREE.DoubleSide
});
var planeGeo = new THREE.PlaneGeometry( 20, 20, 129, 129 );
var plane = new THREE.Mesh( planeGeo, customMaterial );
plane.rotation.x = -Math.PI / 2;
plane.position.y = 0;
scene.add(plane);
});
}
And here are the shaders:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D zTexture;
uniform float zScale;
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
vec4 heightData = texture2D( zTexture, uv );
vAmount = heightData.r;
// move the position along the normal
vec3 newPosition = position + normal * zScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
int index = int(vAmount) * 255;
vec3 vColor = vec3(vAmount, vAmount, vAmount);
//gl_FragColor = vec4(zLut[index], 1.0);
gl_FragColor = vec4(vColor, 1.0);
}
The shaders and the height map part works fine. But I want to pass the lookup table (zLut). The above code works fine if I don't try to use the lookup table. A working example is here. I created a fiddle as well here but it fails because of CORS issues.
Any suggestions are welcome.
OK, solved this (mostly). The trick was to fetch the lookup color in the vertex shader, where one CAN index into an array with a non-const value. The pass the resulting color to the fragmentShader as a varying. So the two shaders end up being:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D vTexture;
uniform float vScale;
uniform vec3 vLut[ 256 ];
varying vec3 vColor;
void main() {
vec4 heightData = texture2D( vTexture, uv );
// assuming map is grayscale it doesn't matter if you use r, g, or b.
float vAmount = heightData.r;
// fetch the color from the lookup table so it gets passed to the fragshader
int index = int(heightData.r * 255.0);
vColor = vLut[index];
// move the position along the normal
vec3 newPosition = position + normal * vScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
</script>
The remaining problem I have is that when rendered the colors are all flat. I tried forcing an update on the vertices in the animate function but didn't work. Still researching but the question here is solved (AFAIK).
You can see the result here

Three.js Shader glass effect with PNG-image-mask on a Video-Texture

some days ago I visited the site activetheory.net again. And I saw this stunning nice glass effect in the Homescreen logo border and tried to recode it. Based on the minified code I was able to see they use a PNG as a mask.
I was able to load a png inside the shader and show it up, also it was easy to get a mesh with video texture working. Now I'm stuck on the combining part (png with video) inside the shaders.
someone got experience with it and can help me?
Thank you and have a nice Day!
here is the shader-material part from:
var g = new THREE.PlaneGeometry(128.0, 72.0);
var outline = THREE.ImageUtils
.loadTexture('outline.png');
outline.magFilter = THREE.NearestFilter;
var mat = new THREE.ShaderMaterial({
uniforms: {
map: {type: "t", value: movieScreen.texture},
outline: {type: "t", outline},
aspect: {type: "fv1", value: []},
res: {type: "v2", value: new THREE.Vector2(window.innerWidth, window.innerHeight)}
},
vertexShader: document.
getElementById('vertShader').text,
fragmentShader: document.
getElementById('fragShader').text,
transparent: true,
});
here are the shaders:
<script id="vertShader" type="shader">
varying vec2 vUv;
varying vec2 nUv;
void main() {
vUv = uv;
nUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragShader" type="shader">
varying vec2 vUv;
varying vec2 nUv;
uniform float color;
uniform sampler2D outline;
uniform sampler2D map;
void main(void) {
float alpha = step(0.9, texture2D(outline, vUv).a);
gl_FragColor = texture2D(outline, nUv);
gl_FragColor *= alpha;
}
</script>
Finally, I got a similar shader working. For everyone who is interested.
The shaders:
<script id="vertShader" type="shader">
varying vec2 vUv;
varying vec2 nUv;
void main() {
vUv = uv;
nUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.05);
}
</script>
<script id="fragShader" type="shader">
varying vec2 vUv;
varying vec2 nUv;
uniform float color;
uniform sampler2D outline;
uniform sampler2D map;
void main(void) {
float alpha = step(0.9, texture2D(outline, vUv).a);
gl_FragColor = texture2D(map, nUv);
gl_FragColor *= alpha;
gl_FragColor += 0.08 * alpha;
}
</script>
Have fun!

Export from Shadertoy to Three.js

I am making my first steps coding. I made some courses on internet, then I played with some three.js experiments, and now I would like to continue learning experimenting with Shaders.
I found Shadertoy.com and it's really amazing! There are a lot of difference experiments with incredible effects. I am trying to use one of these shaders in Three.js but is not so easy.
The Shaders are already written, it's true. But I don't know what to do with that, I don't know how I can use it.
Because it's not only copy and paste the code. There is a relation that I have to write to can apply some of these amazing effects to a Three.js geometry. I have to use uniforms, and I don't know how I can make to know which uniforms I can use, and how can I use them.
I started see the tutorials in Shadertoy and some articles on Internet and it looks like something really abstract. I think that I should study a lot of maths before start understanding that language.
Do you have some recommendation to start?
Maybe is something simpler than I think and I can just copy, paste, and experiment with the code on my HTML document?
Shadertoy is a relatively complex program. It's got audio input into shaders, video input into shaders, audio data generation from shaders, various kinds of textures including both 2d and cubemaps. Supporting all those features is not a small amount of work.
That said a basic shader can be used pretty easily, see example below. But shadertoy shaders are not really designed to be used as materials on meshes in three.js.
If you want to understand why and how WebGL works see http://webglfundamentals.org
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
}
`;
const userShader = `
// FROM: https://www.shadertoy.com/view/4sdXDl
//spikey
#define SHAPE length(z.yz)
//normal
//#define SHAPE length(z.xyz)
//bizarro
//#define SHAPE length(z.yz-z.xx)
//etc...
#define HIGH_QUAL
#ifdef HIGH_QUAL
#define MARCH_STEPS 199
#else
#define MARCH_STEPS 99
#endif
float k=7.0+3.0*sin(iGlobalTime*0.15);
vec3 mcol=vec3(0.0);
void AbsBox(inout vec4 z){//abs box by kali
z.xyz=abs(z.xyz+1.0)-1.0;
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0);
}
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee
float r = length(z.xyz);
float zo = asin(z.z / r) * k + iGlobalTime*0.15;
float zi = atan(z.y, z.x) * 7.0;
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c;
}
float DE(vec3 p){
vec4 c = vec4(p,1.0),z = c;
Bulb(z,c);
float r0=(length(z.xyz)-1.15)/z.w;
z.xyz-=1.0;
for(int i=0;i<7;i++)AbsBox(z);
float r=SHAPE;
mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w));
return 0.5 * max((r-1.0) / z.w,-r0);
}
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code
float d=0.4*dot(rd,L)+0.6;
//return vec3(d);
rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y);
rd=abs(rd);
float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.)
+.3*pow(1.-rd.y,12.)*(1.6-y);
return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun)
*((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y));
}
float rnd;
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);}
float ShadAO(in vec3 ro, in vec3 rd){
float t=0.0,s=1.0,d,mn=0.01;
for(int i=0;i<12;i++){
d=max(DE(ro+rd*t)*1.5,mn);
s=min(s,d/t+t*0.5);
t+=d;
}
return s;
}
vec3 scene(vec3 ro, vec3 rd){
vec3 L=normalize(vec3(0.4,0.025,0.5));
vec3 bcol=sky(rd,L);
vec4 col=vec4(0.0);//color accumulator
float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x;
for(int i=0;i<MARCH_STEPS;i++){
d=DE(ro);
if(d<px*t){
float dif=clamp(1.0-d/od,0.2,1.0);
vec3 scol=mcol*dif*(1.3-0.3*t);
#ifdef HIGH_QUAL
vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L));
scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0);
#endif
float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0);
col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha;
if(col.w>0.9)break;
}
t+=d;ro+=rd*d;od=d;
if(t>6.0)break;
}
col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0));
return col.rgb;
}
mat3 lookat(vec3 fw){
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
randomize(fragCoord);
float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7);
vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x;
vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r);
vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0));
//rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd);
fragColor=vec4(scene(ro,rd)*2.0,1.0);
}
`;
// FROM shadertoy.com
const shadertoyBoilerplate = `
#extension GL_OES_standard_derivatives : enable
//#extension GL_EXT_shader_texture_lod : enable
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 iResolution;
uniform float iGlobalTime;
uniform float iChannelTime[4];
uniform vec4 iMouse;
uniform vec4 iDate;
uniform float iSampleRate;
uniform vec3 iChannelResolution[4];
uniform int iFrame;
uniform float iTimeDelta;
uniform float iFrameRate;
struct Channel
{
vec3 resolution;
float time;
};
uniform Channel iChannel[4];
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
void mainImage( out vec4 c, in vec2 f );
${userShader}
void main( void ){
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, gl_FragCoord.xy );
color.w = 1.0;
gl_FragColor = color;
}
`;
const $ = document.querySelector.bind(document);
const camera = new THREE.Camera();
camera.position.z = 1;
const scene = new THREE.Scene();
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1,
]);
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 2 ) );
const uniforms = {
iGlobalTime: { type: "f", value: 1.0 },
iResolution: { type: "v3", value: new THREE.Vector3() },
};
const material = new THREE.RawShaderMaterial({
uniforms: uniforms,
vertexShader: vs,
fragmentShader: shadertoyBoilerplate,
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
resize(true);
render(0);
function resize(force) {
var canvas = renderer.domElement;
var dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow
var width = canvas.clientWidth * dpr;
var height = canvas.clientHeight * dpr;
if (force || width != canvas.width || height != canvas.height) {
renderer.setSize( width, height, false );
uniforms.iResolution.value.x = renderer.domElement.width;
uniforms.iResolution.value.y = renderer.domElement.height;
}
}
function render(time) {
resize();
uniforms.iGlobalTime.value = time * 0.001;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
canvas {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>
The code above from shadertoy passes gl_FragCoord as input to the user's shader which is the pixel coordinate of the pixel being drawn in the canvas.
For a model we can pass in UV coordinates instead, we just have to choose a resolution to multiply them by since UV coordinates usually go from 0 to 1 and the shadertoy shaders are expecting 0 to canvas.width and 0 to canvas.height
Example:
const vs = `
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
`;
const userShader = `
// FROM: https://www.shadertoy.com/view/4sdXDl
//spikey
#define SHAPE length(z.yz)
//normal
//#define SHAPE length(z.xyz)
//bizarro
//#define SHAPE length(z.yz-z.xx)
//etc...
#define HIGH_QUAL
#ifdef HIGH_QUAL
#define MARCH_STEPS 199
#else
#define MARCH_STEPS 99
#endif
float k=7.0+3.0*sin(iGlobalTime*0.15);
vec3 mcol=vec3(0.0);
void AbsBox(inout vec4 z){//abs box by kali
z.xyz=abs(z.xyz+1.0)-1.0;
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0);
}
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee
float r = length(z.xyz);
float zo = asin(z.z / r) * k + iGlobalTime*0.15;
float zi = atan(z.y, z.x) * 7.0;
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c;
}
float DE(vec3 p){
vec4 c = vec4(p,1.0),z = c;
Bulb(z,c);
float r0=(length(z.xyz)-1.15)/z.w;
z.xyz-=1.0;
for(int i=0;i<7;i++)AbsBox(z);
float r=SHAPE;
mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w));
return 0.5 * max((r-1.0) / z.w,-r0);
}
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code
float d=0.4*dot(rd,L)+0.6;
//return vec3(d);
rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y);
rd=abs(rd);
float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.)
+.3*pow(1.-rd.y,12.)*(1.6-y);
return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun)
*((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y));
}
float rnd;
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);}
float ShadAO(in vec3 ro, in vec3 rd){
float t=0.0,s=1.0,d,mn=0.01;
for(int i=0;i<12;i++){
d=max(DE(ro+rd*t)*1.5,mn);
s=min(s,d/t+t*0.5);
t+=d;
}
return s;
}
vec3 scene(vec3 ro, vec3 rd){
vec3 L=normalize(vec3(0.4,0.025,0.5));
vec3 bcol=sky(rd,L);
vec4 col=vec4(0.0);//color accumulator
float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x;
for(int i=0;i<MARCH_STEPS;i++){
d=DE(ro);
if(d<px*t){
float dif=clamp(1.0-d/od,0.2,1.0);
vec3 scol=mcol*dif*(1.3-0.3*t);
#ifdef HIGH_QUAL
vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L));
scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0);
#endif
float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0);
col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha;
if(col.w>0.9)break;
}
t+=d;ro+=rd*d;od=d;
if(t>6.0)break;
}
col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0));
return col.rgb;
}
mat3 lookat(vec3 fw){
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
randomize(fragCoord);
float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7);
vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x;
vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r);
vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0));
//rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd);
fragColor=vec4(scene(ro,rd)*2.0,1.0);
}
`;
// FROM shadertoy.com
const shadertoyBoilerplate = `
#extension GL_OES_standard_derivatives : enable
//#extension GL_EXT_shader_texture_lod : enable
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 iResolution;
uniform float iGlobalTime;
uniform float iChannelTime[4];
uniform vec4 iMouse;
uniform vec4 iDate;
uniform float iSampleRate;
uniform vec3 iChannelResolution[4];
uniform int iFrame;
uniform float iTimeDelta;
uniform float iFrameRate;
struct Channel
{
vec3 resolution;
float time;
};
uniform Channel iChannel[4];
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
varying vec2 vUv;
void mainImage( out vec4 c, in vec2 f );
${userShader}
void main( void ){
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, vUv * iResolution.xy );
color.w = 1.0;
gl_FragColor = color;
}
`;
const $ = document.querySelector.bind(document);
const fieldOfView = 45;
const zNear = .1;
const zFar = 100;
const camera = new THREE.PerspectiveCamera(fieldOfView, 1, zNear, zFar);
camera.position.z = 3;
const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const uniforms = {
iGlobalTime: { type: "f", value: 1.0 },
iResolution: { type: "v3", value: new THREE.Vector3() },
};
// choose a resolution to pass to the shader
uniforms.iResolution.value.x = 100;
uniforms.iResolution.value.y = 100;
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vs,
fragmentShader: shadertoyBoilerplate,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
resize(true);
render(0);
function resize(force) {
const canvas = renderer.domElement;
const dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow
const width = canvas.clientWidth * dpr;
const height = canvas.clientHeight * dpr;
if (force || width != canvas.width || height != canvas.height) {
renderer.setSize( width, height, false );
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001; // seconds
resize();
uniforms.iGlobalTime.value = time;
mesh.rotation.x = time * 0.5;
mesh.rotation.y = time * 0.6;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
Note that shadertoy shaders are generally not designed to be used as materials. They are not efficient, rather they are more like a fun activity of "how cool an image can I make using only time and pixel location as input". Because of that while the results can be amazing they are often 10x or 100x or even 1000x slower than traditional techniques for materials (using textures)
Compare for example this amazing shader which draws an entire city but at least on my machine it runs at 10-18fps in a small window and 1fps when fullscreen. VS for example Grand Theft Auto 5 which also shows an entire city yet manages to run at 30-60fps when fullscreen on the same machine.
There is a lot of fun to be had and lots of interesting techniques to learn on shadertoy.com that might be useful in your shaders but don't mistake what's there for "production" techniques. It's called shaderTOY for a reason 😉

Three JS transparancy with ShaderMaterial

I'm drawing two geometries next to each other and have them rotate. The problem is that the first drawn one is obstructing the second one, where transparency should take effect. The two objects should have the same transparency, regardless of who was drawn first. That's why blending is turned on and depth test is off.
Here are the images:
Both geometries are point cloud using THREE.ShaderMaterial as followed:
var shaderMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.NormalBlending,
depthTest: false,
transparent: true
});
where
// attributes
attributes = {
size: { type: 'f', value: null },
alpha: { type: 'f', value: [] },
customColor: { type: 'c', value: null }
};
// uniforms
uniforms = {
color: { type: "c", value: new THREE.Color(0x00ff00) },
texture: { type: "t", value: THREE.ImageUtils.loadTexture("../textures/sprites/circle.png") }
};
and
<script type="x-shader/x-vertex" id="vertexshader">
attribute float alpha;
attribute float size;
attribute vec3 customColor;
varying float vAlpha;
varying vec3 vColor;
void main() {
vAlpha = alpha;
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 120.0 / length( mvPosition.xyz ));
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D texture;
varying float vAlpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor, vAlpha );
gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );
}
</script>
Example code with 2 textures, but can be made to work with one as well:
<script id="fragmentShaderLoader" type="x-shader/x-fragment">
uniform float percent;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( texture1, vUv);
vec4 tex2 = texture2D( texture2, vUv );
if(tex2.a - percent < 0.0) {
gl_FragColor.a = 0.0;
//or without transparent = true use
//discard;
}
}
</script>
<script id="vertexShaderLoader" type="x-shader/x-vertex">
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
Then for init:
uniformsMove = {
percent: { type: "f", value: 1.0 },
texture1: { type: "t", value: (new THREE.TextureLoader()).load( "govr/loader-test.png" ) },
texture2: { type: "t", value: (new THREE.TextureLoader()).load( "govr/loader-mask2.png" ) }
};
material = new THREE.ShaderMaterial( {
uniforms: uniformsMove,
vertexShader: document.getElementById( 'vertexShaderLoader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShaderLoader' ).textContent
} );
material.transparent = true;

Three.js ParticleSystem transparency issue

I'm using Three.js and I have a ParticleSystem where every particle may have a different transparency and color.
Code:
var shaderMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
attributes: customAttributes,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
transparent: true,
alphaTest: 0.5
});
particles = new THREE.ParticleSystem(geometry, shaderMaterial);
particles.dynamic = true;
Vertex shader:
attribute float size;
attribute vec3 color;
varying vec3 vColor;
void main() {
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
//gl_PointSize = size;
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
Fragment shader:
uniform sampler2D texture;
uniform float alpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 100);
vec4 textureColor = texture2D( texture, gl_PointCoord );
gl_FragColor = gl_FragColor * textureColor;
gl_FragColor.a = alpha;
}
Texture is a circle but when I set alpha, like this: gl_FragColor.a = alpha, my texture become a circle in a black square, alpha level is okay, but I don't need the square, only the circle if I don't set the alpha, square doesn't appear.
So how to set alpha correctly for provided texture?
Take a look at this: three.js - Adjusting opacity of individual particles
You can find jsfiddle somewhere in the page that uses ShaderMaterial for ParticleSystem with variable alpha: http://jsfiddle.net/yfSwK/27/
Also, at least change fragment shader a bit, gl_FragColor should be write-only variable, it's not usual to have it as a read-from variable:
vec4 col = vec4(vColor, 100);
vec4 tex = texture2D( texture, gl_PointCoord );
gl_FragColor = vec4( (col*tex).rgb, alpha );
...or in one line:
gl_FragColor = vec4( (vec4(vColor, 100) * texture2D( texture, gl_PointCoord )).rgb, alpha);

Categories