why Particle system with shader doesn't work? three.js - three.js

Hi can anyone help me whith this? I have this shader, it works with THREE.Mesh but doesn't with THREE.Particlesystem?
I want each particle to have a portion of a given map(texture) and change their positions accordingly, something like this http://www.chromeexperiments.com/detail/webcam-displacement/?f=webgl
<script id="vs" type="x-shader/x-vertex">
uniform sampler2D map;
varying vec2 vUv;
void main() {
vUv = uv;
vec4 color = texture2D( map, vUv );
float value = ( color.r + color.g + color.b ) / 3.0;
vec4 pos = vec4( position.xy, value * 100.0, 1.0 );
gl_PointSize = 20.0;
gl_Position = projectionMatrix * modelViewMatrix * pos;
}
</script>
<script id="fs" type="x-shader/x-fragment">
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( map, vUv );
}
</script>

ParticleSystem doesn't really support UVs as there aren't faces, just single points. Texture mapping particles is done with gl_PointCoord (IIRC), but that gives you same mapping for every particle. In order to give different portion of the same texture to each particle, you should use BufferGeometry, which in the latest version of three.js supports all attributes including custom ones (and it is very efficient and fast!). You'd then supply a vec2 offset attribute for each particle: you get the correct UV from this offset and the gl_PointCoord.

Related

Geometry instancing with one shader but multiple textures

I'd like to add a second crate texture to the shader using the shader/technique provided with this example:
https://threejs.org/examples/#webgl_buffergeometry_instancing_dynamic
I figured I could pass in another uniform to add a second map.
crateMaterial = new THREE.RawShaderMaterial( {
uniforms: {
map: { value: new THREE.TextureLoader().load( './img/textures/crate/crate.gif' ),
map2: { value: new THREE.TextureLoader().load( './img/textures/crate2/crate2.gif' ) }
};
However I'm struggling to figure out how to "tag" specific crates and then use the shader to draw vertices with the correct texture, as my experience and skill with GLSL are quite limited.
Could I just pass in another uniform consisting of (vertex) indices to specify where the shader should apply the second texture? ie:
crateMaterial.uniforms.cratesTexturemap = [];
for(i=0;i<cratesToRender;i++) {
/* set position */
...
this._instancePositions.push( position.x, position.y, position.z );
if (drawCrate2) {
crateMaterial.uniforms.cratesTexturemap.push(i); /* correlates to (vertex) position index */
crateMaterial.uniforms.cratesTexturemap.push(i+1);
crateMaterial.uniforms.cratesTexturemap.push(i+2);
}
...
}
Also performance/memory-wise, is it better to have a (dynamic) array of textures passed to the shader or is passing them one by one (a uniform value for every texture as above) more advantageous?
Example shader code for reference:
<script id="vertexShader" type="x-shader/x-vertex">
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
// http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}
void main() {
vec3 vPosition = applyQuaternionToVector( orientation, position );
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( map, vUv );
}
</script>
Can't you just pass an array of textures and choose which to apply using an index passed by a int uniform?
So for every crate you could do
crate.material.uniforms.index = 2
to choose the 3rd texture in the array

How to upgrade the older demo to latest version of three.js?

I got a webgl demo running with old version of Three.js (r52).
I want to adapt the code to new version of Three.js (r1xx).
But I got some black screen after I switched to the new version of Three.js library and upgrade some api.(e.g. Moving the attributes values to BufferGeometry)
This is the shader code passed to ShaderMaterial:
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
attribute float time;
uniform float globalTime;
varying vec3 vColor;
varying float fAlpha;
void main() {
vColor = customColor;
vec3 pos = position;
float animTime = min(1.4, max(1.0, globalTime - time));
vec3 animated = vec3( pos.x * animTime, pos.y * animTime, pos.z * animTime );
vec4 mvPosition = modelViewMatrix * vec4( animated, 1.0 );
fAlpha = 1.0 - (globalTime*0.5);
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform vec3 color;
uniform sampler2D texture;
varying vec3 vColor;
varying float fAlpha;
void main() {
// fog
float depth = gl_FragCoord.z / gl_FragCoord.w;
float near = 30.0;
float far = 290.0;
float fog = 0.0 + smoothstep( near, far, depth );
vec4 outColor = texture2D( texture, gl_PointCoord );
if ( outColor.a < 0.25 ) discard; // alpha be gone
gl_FragColor = vec4( color * vColor, fAlpha );
gl_FragColor = gl_FragColor * outColor;
gl_FragColor = mix( gl_FragColor, vec4( vec3(0.0,0.0,0.0), gl_FragColor.w ), fog );
}
</script>
It seems that the ShaderMaterial is not working well.
Does anyone know if I missed something?
Older one:
https://loooog.github.io/globe/legacy
The failed new one:
https://loooog.github.io/globe/
The code can be seen from the chrome dev console.
Update: the shader material issue has been solved. The line material is still not working
//var line = new THREE.Line(lineGeometry, lineMaterial, THREE.LineSegments);
var line = new THREE.LineSegments(lineGeometry, lineMaterial);

threejs: how to render a texture with custom shaders INCLUDING the textures UV offsets

I want to render a texture to a plane using custom shaders. This texture has an 'offset' property set, that works correctly when I use a standard threejs material. However, I cannot figure out how to access these offsets in my custom fragment shader. It simply renders the whole texture over the whole plane:
shaders:
<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 sampler2D texture1;
varying vec2 vUv;
void main()
{
gl_FragColor = texture2D(texture1, vUv);
}
</script>
if I could somehow say something like:
gl_FragColor = texture2D(texture1, vUv + texture1.offset);
? Maybe that would work. But obviously that throws an error.
UPDATE:
so I sent the texture offset in as a uniform and that works. Dont know why I didn't think of that.
If I understand your question correctly, then the answer should be to add and use the uniform mat3 uvTransform; uniform to your fragment shader.
THREE will look for and populate that uniform with the texture transformation (which includes texture1.offset), when rendering the texture onto your geometry.
You should be able to access and extract the data supplied to texture1.offset to offset your texture sampling as follows:
<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">
// [UPDATE] The uv offset uniform we defined below
uniform vec2 uvOffset;
// [UPDATE] The texture uniform we defined below
uniform sampler2D texture;
varying vec2 vUv;
void main()
{
// [UPDATE] Apply offset to texture lookup
gl_FragColor = texture2D(texture, vUv + uvOffset);
}
</script>
You would then accompany the vertex and fragment shaders above, with the following THREE.ShaderMaterial:
<script>
var material = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
{
//Declare texture uniform in shader
texture: { type: 't', value: null },
//Declare texture offset in shader
uvOffset : { type : 'v', value : new THREE.Vector2(0,0) }
}
]),
vertexShader:
document.getElementById('vertexshader').textContent,
fragmentShader:
document.getElementById('fragmentshader').textContent
});
// Shader uniforms can be updated like so
material.uniforms.map.value = yourTexture;
material.uniforms.uvOffset.value = yourTextureOffsetVector2;
</script>

three.js animated texture in particles with custom shadermaterial

How do I make each particle animate and cycle through all the tiles in the sprite sheet?
Here's my shader program:
<script type="x-shader/x-vertex" id="vertexshader">
attribute vec2 offset;
varying vec2 vOffset;
void main()
{
vOffset = offset;
gl_PointSize = 25.0;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D texture;
uniform vec2 repeat;
varying vec2 vOffset;
void main()
{
vec2 uv = vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y );
vec4 tex = texture2D( texture, uv * repeat + vOffset );
if ( tex.a < 0.5 ) discard;
gl_FragColor = tex;
}
</script>
Basically an example from here: http://jsfiddle.net/myy7x4zd/4/

Same texture offseting different position in the fragment shader using threejs rendering engine

My vertex shader:
varying vec2 texCoord;
void main() {
texCoord = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
My fragment shader:
varying vec2 texCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float multiplier;
void main( void ) {
vec3 tex1 = texture2D(texture1, texCoord).xyz ;
vec3 tex2 = texture2D(texture2, texCoord).xyz ;
vec3 finaltex = mix( tex1, tex2, multiplier) ;
gl_FragColor = vec4(finaltex , 1.0);
}
Now this work very well when i run using the two texture.check http://shaderfrog.com/app/view/68 for the multiplier action.
But now what I want is I am having texture like this:
So with the single texture I want to index the offset of my texCoord so that I just need to sample one texture and I can get three representation form this like:
var shaderMaterial = new THREE.ShaderMaterial({
uniforms:{
texture1: { type: "t", value: texture1 }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
});
Can offset my tri-color in the fragment shader. or Some one can help me modifying the fragment shader so that I can pass uniform to index my tri-color into individual Yellow,pink,red.
So either from shader or threejs I can get help regarding same.
I have done reference using two texture because I want to interpolate with cross fade effect on the texture same I want cross fade using fragment shader (independent to this I have already achieve by the texture.offset.x = currentColoum / horizontal and texture.offset.y = currentRow / Vertical;
I found the answer to this question, even implemented into application :D.
vertexShader:
void main() {
texCoord = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
FragmentShader:
varying vec2 texCoord;
uniform sampler2D texture;
uniform vec2 offset_current;
uniform vec2 offset_next;
uniform float multiplier;
void main( void ) {
vec2 offset1 = offset_current + vec2( texCoord.x* 1.0, texCoord.y * 0.333333);
vec2 offset2 = offset_next + vec2( texCoord.x* 1.0, texCoord.y * 0.333333);
vec3 tex1 = texture2D(texture1,offset1).xyz ;
vec3 tex2 = texture2D(texture1, offset2).xyz ;
vec3 mixCol = mix( tex1, tex2, multiplier );
vec4 fragColor = vec4(mixCol, 1.0);
if(fragColor.a == 0.0)
discard;
gl_FragColor = fragColor;
}
Explanation:
Since I am having the vertical texture of three different type I make my offset into y direction 0.3333. Because texture is read from [0,1]. I have extended this code same for the horizontal direction.
If some one going to make this dynamic then instead of hard coded we can pass the 0.3333 as the calculate one taking the inspiration form link.

Resources