Running into some issues with vec2 divison with OpenGL ES with WebGL --- specifically that it seems to automatically deal with aspect ratios. My understanding is that:
someVec2 / anotherVec2 = vec2(
someVec2.x / anotherVec2.x,
someVec2.y / anotherVec2.y)
i.e., it is component-wise.
However, this code (where uResolution is an ivec2 passed from the code, of the current resolution):
vec2 uv = gl_FragCoord.xy / float(uResolution);
gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
produces:
whereas
vec2 fragCoordUv = vec2(
gl_FragCoord.x / float(uResolution.x),
gl_FragCoord.y / float(uResolution.y)
);
gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
produces:
Specifically, the Y value doesn't seem to scale up all the way. The issue becomes more obvious if you use a texture. i.e. straight division:
vs. manual component division:
It looks like it's automatically performing aspect ratio correction. Is this a feature? I can't seem to find any information on it anywhere. Everything states that normal binary operators (+, -, /, *, etc) just work component-based. Please help!
Try with
vec2 uv = gl_FragCoord.xy / vec2(uResolution);
Related
I am generating a point cloud representing a rock using Three.js, but am facing a problem with visualizing its structure clearly. In the second screenshot below I would like to be able to denote the topography of the rock, like the corner (shown better in the third screenshot) of the structure, in a more explicit way, as I want to be able to maneuver around the rock and select different points. I have rocks that are more sparse (harder to see structure as points very far away) and more dense (harder to see structure from afar because points all mashed together, like first screenshot but even when closer to the rock), and finding a generalized way to approach this problem has been difficult.
I posted about this problem before here, thinking that representing the ‘depth’ of the rock into the screen would suffice, but after attempting the proposed solution I still could not find a nice way to represent the topography better. Is there a way to add a source of light that my shaders can pick up on? I want to see whether I can represent the colors differently based on their orientation to the source. Using a different software, a friend was able to produce the below image - is there a way to simulate this in Three.js?
For context, I am using Points with a BufferGeometry and ShaderMaterial. Below is the shader code I currently have:
Vertex:
precision mediump float;
varying vec3 vColor;
attribute float alpha;
varying float vAlpha;
uniform float scale;
void main() {
vAlpha = alpha;
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
#ifdef USE_SIZEATTENUATION
//bool isPerspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 );
//if ( isPerspective ) gl_PointSize *= ( scale / -mvPosition.z );
#endif
gl_PointSize = 2.0;
gl_Position = projectionMatrix * mvPosition;
}
and
Fragment:
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec3 vColor;
varying float vAlpha;
uniform vec2 u_depthRange;
float LinearizeDepth(float depth, float near, float far)
{
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * near * far / (far + near - z * (far - near)) - near) / (far-near);
}
void main() {
float r = 0.0, delta = 0.0, alpha = 1.0;
vec2 cxy = 2.0 * gl_PointCoord.xy - 1.0;
r = dot(cxy, cxy);
float lineardepth = LinearizeDepth(gl_FragCoord.z, u_depthRange[0], u_depthRange[1]);
if (r > 1.0) {
discard;
}
// Reseted back to 1.0 instead of using lineardepth method above
gl_FragColor = vec4(vColor, 1.0);
}
Thank you so much for your help!
I have this line:
gl_FragColor = vec4(worldPos.x / maxX, worldPos.z / maxZ, 1.0, 1.0);
Where worldPos.x and worldPos.y goes from 0 to 19900. maxX and maxZ are float uniforms. It works as expected when maxX and maxZ are set to 5000.0 (a gradient to white and above 5000 it's all white), but when maxX and maxZ are set to 19900.0 it all turns blue. Why is that and how to get around it? Hardcoding the values doesn't make a difference, i.e:
gl_FragColor = vec4(worldPos.x / 5000.0, worldPos.z / 5000.0, 1.0, 1.0);
works as expected while:
gl_FragColor = vec4(worldPos.x / 19900.0, worldPos.z / 19900.0, 1.0, 1.0);
makes it all blue. This only happens on some devices and not on others.
Update:
Adding highp modifier (as suggested by Michael below) solved it for one device, but when testing on another it didn't make any difference. Then I tried to do the division on the CPU (also suggested by Michael) like this:
in java, before passing it as uniform:
float maxX = 1.0f / 19900.0f;
float maxZ = 1.0f / 19900.0f;
program.setUniformf(maxXUniform, maxX);
program.setUniformf(maxZUniform, maxZ);
in shader:
uniform float maxX;
uniform float maxZ;
...
gl_FragColor = vec4(worldPos.x * maxX, worldPos.z * maxZ, 1.0, 1.0);
...
Final sulotion:
This still didn't cut it. Now the values are too small so when passed in to the shader they turn 0 due to too low float precision. Then I tried to multiply it by 100 before passing it in, and then multiplying it by 0.01 inside the shader.
in java:
float maxX = 100.0f / 19900.0f;
float maxZ = 100.0f / 19900.0f;
program.setUniformf(maxXUniform, maxX);
program.setUniformf(maxZUniform, maxZ);
in shader:
uniform float maxX;
uniform float maxZ;
...
gl_FragColor = vec4(worldPos.x * 0.01 * maxX, worldPos.z * 0.01 * maxZ, 1.0, 1.0);
...
And that solved the problem. Now the highp modifier isn't needed. Maybe it isn't the prettiest sulotion but it's efficient and robust.
I guess you're running OpenGL ES? Well,the floating precision sucks on many,usually quite old, devices.I had similar issues on several occasions when implementing cascaded shadows mapping in shaders for mobile hardware.
Make sure you use highp qualifier for those variables. (note - that might not solve the issue, but is worth to try)
Another possible solution: don't perform the division in the shader. That's a quite heavy operation for many old and weak implementations anyway. Try to avoid division, sqrt(),pow().Run shader profiler and you will be surprised to find out how much those ops are HEAVY! (iOS emulator on Mac has a nice shader profiler) Try to pass the results directly as uniforms.I am not sure that would be a problem in your case,as I can't see any of these variables bound to per-fragment execution.
And if it still doesn't help, then usually there is nothing you can do about that. That's the old hardware/GLSL implementation issue. But I am sure,if you calculate that on CPU and upload the results as uniforms, that should solve the issue.
I have a program that works great when my POT DataTextures are 1:1 (width:height) in their texel dimensions, however when they are 2:1 or 1:2 in texel dimensions it appears that the texels are being incorrectly read and applied. I'm using continuous indexes (1,2,3,4,5...) to access the texels using the two functions below.
I'm wondering if there is something wrong with how I am accessing the texel data, or perhaps if my use of a Float32Array for the integer indexes needs to be switched to a Uint8Array or something else? Thanks in advance!
This function finds the uv for textures that have one texel per particle cloud in my visualization:
float texelSizeX = 1.0 / uPerCloudBufferWidth;
float texelSizeY = 1.0 / uPerCloudBufferHeight;
vec2 perMotifUV = vec2(
mod(cellIndex, uPerCloudBufferWidth)*texelSizeX,
floor(cellIndex / uPerCloudBufferHeight)*texelSizeY );
perCloudUV += vec2(0.5*texelSizeX, 0.5*texelSizeY);
This function finds the uv for textures that contain one texel for each particle contained in all of the clouds:
float pTexelSizeX = 1.0 / uPerParticleBufferWidth;
float pTexelSizeY = 1.0 / uPerParticleBufferHeight;
vec2 perParticleUV = vec2(
mod(aParticleIndex, uPerParticleBufferWidth)*pTexelSizeX,
floor(aParticleIndex / uPerParticleBufferHeight)*pTexelSizeY );
perParticleUV += vec2(0.5*pTexelSizeX, 0.5*pTexelSizeY);
Shouldn't this
vec2 perMotifUV = vec2(
mod(cellIndex, uPerCloudBufferWidth)*texelSizeX,
floor(cellIndex / uPerCloudBufferHeight)*texelSizeY );
be this?
vec2 perMotifUV = vec2(
mod(cellIndex, uPerCloudBufferWidth)*texelSizeX,
floor(cellIndex / uPerCloudBufferWidth)*texelSizeY ); // <=- use width
And same for the other? Divide by width not height
I have values in the texels of a DataTexture that I am trying to access using indexes in my shader. The indexes [0, 1, 2, 3, 4, 5, 6... 62, 63] are continuous, while the data texture has a height and width (uTextureDimension) of 8. After some research I wrote this function to take a particular index value, and reference the corresponding texel:
vec2 customUV = vec2( mod(aIndex, uTextureDimension) / uTextureDimension, floor(aIndex / uTextureDimension) / uTextureDimension );
vec4 texelValues = texture2D( tDataTexture, customUV ).xyzw;
I also tried this version to reference the texel from its center point. Also no dice:
vec2 perMotifUV = vec2( mod( aIndex, uTextureDimension ) * (( 1.0 / uTextureDimension )/2.0), floor( aIndex / uTextureDimension ) * (( 1.0 / uTextureDimension )/2.0) );
vec4 texelValues = texture2D( tDataTexture, customUV ).xyzw;
After working with this since yesterday afternoon, editing it here and there, and looking around for other solutions, I'm still not getting the expected results. I should say that in using Three.js, the shaders are set to high precision float - is this part of the problem? Can anyone nudge me on track here? Thanks!
The first one seems right, if everything is a float. Are you using NEAREST filter mode? Technically you should also add a half-texel-size offset too:
vec2 texelSize = 1.0 / uTextureDimension;
vec2 customUV = vec2( mod(aIndex, uTextureDimension)*texelSize, floor(aIndex / uTextureDimension)*texelSize );
customUV += vec2(0.5*texelSize);
EDIT - Also your indices should go 0-63 not 0-64
I have a platform where this extension is not available ( non NVIDIA ).
How could I emulate this functionality ?
I need it to solve far plane clipping problem when rendering stencil shadow volumes with z-fail algorithm.
Since you say you're using OpenGL ES, but also mentioned trying to clamp gl_FragDepth, I'm assuming you're using OpenGL ES 2.0, so here's a shader trick:
You can emulate ARB_depth_clamp by using a separate varying for the z-component.
Vertex Shader:
varying float z;
void main()
{
gl_Position = ftransform();
// transform z to window coordinates
z = gl_Position.z / gl_Position.w;
z = (gl_DepthRange.diff * z + gl_DepthRange.near + gl_DepthRange.far) * 0.5;
// prevent z-clipping
gl_Position.z = 0.0;
}
Fragment shader:
varying float z;
void main()
{
gl_FragColor = vec4(vec3(z), 1.0);
gl_FragDepth = clamp(z, 0.0, 1.0);
}
"Fall back" to ARB_depth_clamp?
Check if NV_depth_clamp exists anyway? For example my ATI card supports five "NVidia-only" GL extensions.