Custom Point Shader in Autodesk Forge Viewer behaves weirdly with orthograpic Camera - three.js

I am using a PointCloud for fast rendering of sprites after this blog post. Everything works fine with the perspective camera. However, if I switch to the orthographic camera via viewer.navigation.toOrthographic() the points' sizes are not calculated correctly. Does anyone know what the issue is or where I might find some clue?
My vertex shader
#if NUM_CUTPLANES > 0
varying highp vec3 vWorldPosition;
#endif
attribute float mVisible;
attribute float mSize;
varying float vMVisible;
uniform float scale;
void main() {
vMVisible = mVisible;
#if NUM_CUTPLANES > 0
vec4 _worldPosition = modelMatrix * vec4( position, 1.0 );
vWorldPosition = _worldPosition.xyz;
#endif
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
gl_PointSize = mSize * (scale / (-mvPosition.z) );
}
Zoomed out
Zoomed in
Zoomed in a little bit more

The problem is in the last few lines of the fragment shader:
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
gl_PointSize = mSize * (scale / (-mvPosition.z) );
When using an orthographic projection instead of a perspective projection, the mvPosition (position transformed into the "normalized device coordinates") may have very different values, and so dividing the point size by mvPosition.z may yield unexpected results.
You may need to clamp the final point size by some constants (or by uniforms you provide from your JavaScript code), e.g.:
gl_PointSize = clamp(mSize * scale / -mvPosition.z, 10.0, 100.0);

Related

How to convert a square texture into a trapezoid texture with progressive distortion in GLSL

Im in a Three.js project and Im trying to convert a square with a square texture inside into a trapezoid.
I manage to create the shape but the texture inside, although it fits/cover the shape it do it with an undesired distorsiĆ³n.
Im using a PlaneBufferGeometry with ShaderMaterial and im trying to obtain this distorsion in the shader part (although it would be ok if it is done in the threejs geometry part).
This is my vertex:
uniform sampler2D uTexture;
varying vec2 vUv;
void main(){
float scaleTOP = 0.5;
float scaleBOTTOM = 1.0;
float scaleLEFT = 1.0;
float scaleRIGHT = 1.0;
float scaleX = mix(scaleBOTTOM, scaleTOP, uv.y);
float posX = position.x*scaleX;
float scaleY = mix(scaleLEFT, scaleRIGHT, uv.x);
float posY = position.y*scaleY;
vec3 finalPosition = vec3(posX, posY);
gl_Position = projectionMatrix * modelViewMatrix * vec4( finalPosition, 1.0 );
// Varyings:
vUv = uv;
}
And this is my fragment:
uniform sampler2D uTexture;
varying vec2 vUv;
void main() {
vec4 tex = texture2D ( uTexture, vUv );
gl_FragColor = vec4(tex.r, tex.g, tex.b, 1.0);
}
Unfortunately I manage to distort the square into the trapezoid but the texture is not distorted in the way I want. See figure to see the intended result:
Figure:
My vertex and fragment were ok.
The problem was that the Threejs geometry I was using had only 2 polygons. I was using:
this.bg_geometry = new THREE.PlaneBufferGeometry(width, height, 1, 1)
Thats it... with only one division which only created two triangles which actually can be seen in the figure I posted.
I changed the geometry to:
this.bg_geometry = new THREE.PlaneBufferGeometry(width, height, 100, 100)
...and now the texture is distorted as desired.
Anyway many thanks to #prisoner849 as he put me in the track to pass 4 points as uniforms uPoints in this order: TL,TR,BL,BR to set the shape of the plane.
My vertex shader looks now like this:
uniform vec3 uPoints[4];
varying vec2 vUv;
void main(){
vec3 baselineBottom = (uPoints[3] - uPoints[2]) * uv.x + uPoints[2];
vec3 baselineTop = (uPoints[1] - uPoints[0]) * uv.x + uPoints[0];
vec3 finalPosition = (baselineTop - baselineBottom) * uv.y + baselineBottom;
gl_Position = projectionMatrix * modelViewMatrix * vec4( finalPosition, 1.0 );
vUv = uv;
}

Custom Shader Joyplotstlye

Maybe you could help me out here please: I'm trying to visualize a digital elevation model with a mesh and draw lines on it joyplot-style. This is done with a custom shader and currently it looks like the picture.
The black lines look blurry, but I want them to look crisp (no grays, only black and white). Can someone tell me how to change the fragment shader to achieve this effect?
This is the current shader:
function vertexShader() {
return
varying vec3 vUv;
void main() {
vUv = position;
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
}
}
function fragmentShader() {
return
uniform vec3 colorA;
uniform vec3 colorB;
varying vec3 vUv;
void main() {
gl_FragColor = vec4(mix(colorA, colorB, vUv.y - (5.0 * floor(vUv.y / 5.0))), 1.0);
}
}
If you only want black and white pixels, you just need to write colorA or colorB in gl_FragColor. Replace mix with the ternary (?:) operator:
gl_FragColor = vec4(mix(colorA, colorB, vUv.y - (5.0 * floor(vUv.y / 5.0))), 1.0);
float w = vUv.y - (5.0 * floor(vUv.y / 5.0));
gl_FragColor = vec4(w < 0.5 ? colorA : colorB, 1.0);
mix linearly interpolate between two values, but the ternary operator only selects one of the values.
Alternatively, you can use step, which generates a step function by comparing two values and returns either 0.0 or 1.0:
float w = step(0.5, vUv.y - (5.0 * floor(vUv.y / 5.0)));
gl_FragColor = vec4(mix(colorA, colorB, w), 1.0);

Partially transparent shader occluding objects in THREE.js

I am making a game with a fog of war layer covering the board. I want to have a cursor that shows up when the player mouses over a tile, and I'm implementing this with a glow effect around the tile, also implemented using a shader.
I'm running into a strange issue: the glow effect works fine for positive x values (when the camera is set at x = -250, y = 250) but I can't see it for negative x values unless the camera gets rotated to almost completely vertical (or I move the camera underneath the fog of war layer).
It's hard to explain, so I've made a CodePen demonstrating the problem: https://codepen.io/jakedluhy/pen/QqzajN?editors=0010
I'm pretty new to custom shaders, so any insight or help would be appreciated. Here's the shaders for the fog of war:
// Vertex
varying vec4 vColor;
void main() {
vec3 cRel = cameraPosition - position;
float dx = (20.0 * cRel.x) / cRel.y;
float dz = (20.0 * cRel.z) / cRel.y;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(
position.x + dx,
position.y,
position.z + dz,
1.0
);
vColor = vec4(0.0, 0.0, 0.0, 0.7);
}
// Fragment
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
And the shaders for the "glow":
// Vertex
varying vec4 vColor;
attribute float alpha;
void main() {
vColor = vec4(color, alpha);
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position, 1.0);
}
// Fragment
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
The math in the vertex shader for the fog of war is to keep the fog in a relative position to the game board.
Tagging THREE.js and glsl because I'm not sure whether this is a THREE.js exclusive problem or not...
Edit: version 0.87.1
Your example looks pretty weird. By setting depthWrite:false on your fog material the two boxes render.
version 0.87.1

THREE.js/GLSL: WebGL shader to color fragments based on world space position

I have seen solution to color fragments based on their position in screen space or in their local object space like Three.js/GLSL - Convert Pixel Coordinate to World Coordinate.
Those are working with screen coordinates and do change when the camera moves or rotates; or only apply to local object space.
What I like to accomplish instead is to color fragments based on their position in world space (as in world space of the three.js scene graph).
Even when the camera moves the color should stay constant.
Example of wished behaviour: A 1x1x1 cube positioned in world space at (x:0,y:0,z:2) would have its third component (blue == z) always between 1.5 - 2.5. This should be true even if the camera moves.
What I have got so far:
vertex shader
varying vec4 worldPosition;
void main() {
// The following changes on camera movement:
worldPosition = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// This is closer to what I want (colors dont change when camera moves)
// but it is in local not world space:
worldPosition = vec4(position, 1.0);
// This works fine as long as the camera doesnt move:
worldPosition = modelViewMatrix * vec4(position, 1.0);
// Instead I'd like the above behaviour but without color changes on camera movement
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
fragment shader
uniform vec2 u_resolution;
varying vec4 worldPosition;
void main(void)
{
// I'd like to use worldPosition something like this:
gl_FragColor = vec4(worldPosition.xyz * someScaling, 1.0);
// Here this would mean that fragments xyz > 1.0 in world position would be white and black for <= 0.0; that would be fine because I can still divide it to compensate
}
Here is what I have got:
https://glitch.com/edit/#!/worldpositiontest?path=index.html:163:15
If you move with wasd you can see that the colors don't stay in place. I'd like them to, however.
Your worldPosition is wrong. You shouldn't implicate the camera in the calculation. That means, no projectionMatrix nor viewMatrix.
// The world poisition of your vertex: NO CAMERA
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
// Position in normalized screen coords: ADD CAMERA
gl_Position = projectionMatrix * viewMatrix * worldPosition;
// Here you can compute the color based on worldPosition, for example:
vColor = normalize(abs(worldPosition.xyz));
Check this fiddle.
Note
Notice that the abs() used here for the color can potentially give the same color for different position, which might not be what you're looking for.

Three.js/Webgl vertex.y does not update

In effort to learn vertex/fragment shaders I decided to create a simple rain effect by updating the y position of a point in the vertex shader and resetting it back to animate through again using Three.js PointCloud. I got it to animate across the screen once but gets stuck after resetting the y position.
uniform float size;
uniform float delta;
varying float vOpacity;
varying float vTexture;
void main() {
vOpacity = opacity;
vTexture = texture;
gl_PointSize = 164.0;
vec3 p = position;
vec3 p = position;
p.y -= delta * 50.0;
vec4 mvPosition = modelViewMatrix * vec4(1.0 * p, 1.0 );
vec4 nPos = projectionMatrix * mvPosition;
if(nPos.y < -200.0){
nPos.y = 100.0;
}
gl_Position = nPos;
}
Any ideas? Thanks
shader does not change the vertex position permanently
that means
gl_Position = nPos;
will not propagate to your position attribute in geometry
shader only runs on graphics card and has no access to memory of the browser
you can change your code to this:
nPos.y = mod(nPos.y, 300.0) - 200.0;
now the y coordinate should change as you want it to(going from 100 to -200 then back to 100)

Resources