Three.js ParticleSystem transparency issue - javascript

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

Related

Three.js, custom shader, fill png texture and set transparency?

The task is to change the color of the texture with a predominance of red. I'm trying to do this, but my texture completely fills the picture with red, please tell me where is the error?
I don't understand why I can't set transparency
function vertexShader(){
return `
precision mediump float;
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
}
`
}
function fragmentShader(){
return `
precision mediump float;
varying vec2 vUv;
uniform sampler2D u_texture;
uniform float u_time;
void main(){
gl_FragColor = texture2D(u_texture, vUv);
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`
}
var texLoader = new THREE.TextureLoader();
var texture = texLoader.load("217.png");
const uniforms = {
u_texture: {value: texture}
}
const material = new THREE.ShaderMaterial(
{
uniforms,
vertexShader: vertexShader(),
fragmentShader: fragmentShader(),
side: THREE.DoubleSide,
//wireframe: true
}
);
The shader is setting gl_FragColor to red
gl_FragColor = texture2D(u_texture, vUv); // this line is effectively ignored
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // because this line sets glFragColor
Maybe you meant this?
gl_FragColor = texture2D(u_texture, vUv);
gl_FragColor += vec4(1.0, 0.0, 0.0, 1.0); // add red
or this?
gl_FragColor = texture2D(u_texture, vUv);
gl_FragColor *= vec4(1.0, 0.0, 0.0, 1.0); // multiply by red

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 .png image renders white and not as it should

I am trying to get a .obj to render with a .png texture, however when I put the .png texture, the head turns white as seen here:
White headed avatar
However when I remove the png texture it looks like this:
This is what I am using to create the texture:
<script id="vertex_shader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fragment_shader" type="x-shader/x-fragment">
uniform vec3 color;
uniform sampler2D texture;
varying vec2 vUv;
void main() {
vec4 tColor = texture2D( texture, vUv );
gl_FragColor = vec4( mix( color, tColor.rgb, tColor.a ), 1.0 );
}
var texture = THREE.ImageUtils.loadTexture('./Avatar/FaceTestTr.png');
texture.needsUpdate = true;
var uniforms = {
color: { type: "c", value: new THREE.Color( 0xffffff ) }, // material is "red"
texture: { type: "t", value: texture },
transparent: true,
opacity: 0.9,
};
var AvatarTextureF = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById( 'vertex_shader' ).textContent,
fragmentShader : document.getElementById( 'fragment_shader' ).textContent
});
And this to apply it to the object:
object.children[1].material = AvatarTextureF;
I have tried a few ways, including just using a normal material:
var AvatarTextureF = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('./Avatar/FaceTestTr.png'), shininess: 80, color: 0xffcc66, shading: THREE.SmoothShading, alphaMap: 0x000000} );
With the same result.
Here is the updated code, now the head is just invisible..
Invisible head
Shaders:
<script type="x-shader/x-vertex" id="vertex_shader">
#if NUM_DIR_LIGHTS > 0
struct DirectionalLight {
vec3 direction;
vec3 color;
int shadow;
float shadowBias;
float shadowRadius;
vec2 shadowMapSize;
};
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
#endif
//varying vec3 color;
void main() {
float r = directionalLights[0].color.r;
//color = vec3(r,0.6,0.6,0.6);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position , 1.0); }
</script>
<script type="x-shader/x-fragment" id="fragment_shader">
uniform vec3 color;
uniform sampler2D texture;
varying vec2 vUv;
void main() {
vec4 tColor = texture2D( texture, vUv );
gl_FragColor = vec4( mix( color, tColor.rgb, tColor.a ), 1.0 );
}
</script>
And the head:
var texture = THREE.ImageUtils.loadTexture('./Avatar/FaceTestTr.png');
texture.needsUpdate = true;
// uniforms
var uniforms = THREE.UniformsUtils.merge( [
THREE.UniformsLib[ "lights" ],
{
color: { type: "c", value: new THREE.Color( 0xffffff ) },
texture: { type: "t", value: texture }
}
] );
// material
var AvatarTextureF = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : document.getElementById( 'vertex_shader' ).textContent,
fragmentShader : document.getElementById( 'fragment_shader' ).textContent,
//transparent: true,
lights: true
});
Did you applied a transparent PNG with the face look?
gl_FragColor = vec4( mix( color, tColor.rgb, tColor.a ), 1.0 ); will be rendered in color value, if tColor.a is 0.0.
That means, it will be painted in white, which you set with color: { type: "c", value: new THREE.Color( 0xffffff ) }, except the face look where alpha is 1.0.
Change the color value from 0xffffff to color you want.
Also you are missing lighting process in your fragment shader.

THREE.js Color texture by shader

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.

three.js, make dashed line through shader

I'm trying to make a shader for my dashed line; but only I can get is white line from origin to .. +x direction(maybe)
If I render this curve (Ellipse.curve), they do just fine. And with shader don't..
..of course, I don't know why.. please help me;;
<script type="x-shader/x-vertex" id="vs-orbit">
uniform float time;
attribute float sovereign;
varying vec3 vColor;
vec3 setColorBySovereign() {
vec3 color;
color.r = 0.5 - ( 0.5 * sovereign );
color.g = 0.25 + ( 0.25 * sovereign );
color.b = 0.5 + ( 0.25 * sovereign );
return _color;
};
void main() {
vColor = setColorBySovereign();
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
};
</script>
<script type="x-shader/x-fragment" id="fs-orbit">
attribute vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
};
</script>
// ... Below is where use shader above;
Ellipse.prototype.createOrbit = function( soveregin ) {
var shape, mater;
var sov = soveregin || 0.0;
shape = new THREE.Geometry();
var v2;
for(var i=0; i<721; i++) {
v2 = this.curve.getPoint(i);
shape.vertices.push(new THREE.Vector3(v2.x, v2.y, 0));
};
shape.computeLineDistances();
mater = new THREE.ShaderMaterial({
attribute: { soveregin: sov },
vertexShader: document.getElementById('vs-orbit'),
fragmentShader: document.getElementById('fs-orbit')
});
this.orbit = new THREE.Line( shape, mater, THREE.LineStrip );
return;
}
I solve this problem; after main(){} I shouldn't use ';' and other syntax errors too.
in fragment shader, I have to declare vColor with operator 'varying', just like vertex shader. In fragment shader; from GLSL Reference; varying is equal to in operator.

Categories