It seems that every second triangle of a 3d object is missing. For example when a cube is drawn, there are only 6 triangles, one on each face. Here is a picture of the problem. This problem persists even if only one object is drawn.
Here are parts of my code where I think the problem might be:
//start up
gl = canvas.getContext('webgl');
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.0,0.0,0.0,0.0);
gl.clearDepth(1.0);
//shaders
//vertexShader
'
attribute vec3 vertexPosition;
uniform mat4 transformationMatrix;
attribute vec2 uv;
varying vec2 vUV;
void main()
{
gl_Position = transformationMatrix * vec4(vertexPosition,1);
vUV = uv;
}'
//fragmentShader
//problem is still there even when not using a texture
'
precision highp float;
uniform sampler2D sampler;
varying vec2 vUV;
void main()
{
gl_FragColor = texture2D(sampler,vUV);
}'
//after shaders are compiled and some getAttribLocation/enableVertex/AttribLocation/etc calls are made, models and textures are loaded
//each model has a vertexBuffer, indexBuffer, and nIndices, among some other things
//models are retrieved in a for loop
//models are exported to json format with a vertex format of [X,Y,Z,Nx,Ny,Nz,U,V]
var retrievedModel = retrieveResourceFile(resourcesToLoad.models[m].source);
//make vertex buffer
resourcesToLoad.models[m].path.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,resourcesToLoad.models[m].path.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(retrievedModel.vertices),gl.STATIC_DRAW);
//make index buffer
resourcesToLoad.models[m].path.indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,resourcesToLoad.models[m].path.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(retrievedModel.indices),gl.STATIC_DRAW);
resourcesToLoad.models[m].path.nIndices = retrievedModel.indices.length;
//now in draw loop, objects that need to be drawn are stored in Draw.objectsToRender array
gl.bindBuffer(gl.ARRAY_BUFFER,Draw.objectsToRender[i].model.vertexBuffer);
gl.vertexAttribPointer(Shaders.modelShaderProgram.vertexPosition,3,gl.FLOAT,false,4*(3+3+2),0);
gl.vertexAttribPointer(Shaders.modelShaderProgram.uv,2,gl.FLOAT,false,4*(3+3+2),(3+3)*4);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,Draw.objectsToRender[i].model.indexBuffer);
gl.drawElements(gl.TRIANGLES,Draw.objectsToRender[i].model.nIndices,gl.UNSIGNED_SHORT,0);
I've been comparing my code to a tutorial I used http://www.webglacademy.com/#6, (particularly part 6 section 8), and I can't spot anything different that would cause this problem. The models I am using were exported from Blender using the export script provided in part 6 of the tutorial, but I don't think there is a problem there, as I tried using the dragon model data that works fine in the tutorial, and it has the missing triangles problem when used with my code. Thank you very much.
Related
Using ThreeJS I've made a setup that displays a model with a complex material. I'm using an alpha texture to make semi-transparent surfaces, like glass. However when shadows are being cast, the shadow is removed completely instead of using the alpha texture as gradient.
Basically I want a similar effect like this BabylonJS example: https://playground.babylonjs.com/#P1RZV0
When casting shadows I'm using the MeshDepthMaterial in order to let the light cast shadows through transparent surfaces, like this:
var customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
alphaMap: alphaTex,
alphaTest: 1,
skinning: true
})
This works fine however as mentioned, shadows should not disappear completely but rather use the alpha texture as indicator how strong the shadow should be. The more opaque a surface is the stronger the shadow should be and vice versa.
You can take a look at the project here: https://jsfiddle.net/miger/2c7no6mj/
Apparently BabylonJS makes it as simple as using the parameter .transparencyShadow = true; and I've not found anything simmilar in ThreeJS. It seems that there has not been an official solution implemented in ThreeJS yet. Instead the only thing I found was this discussion about it here: https://github.com/mrdoob/three.js/issues/10600
I've already implemented some GLSL code in order to get selective bloom working. I'm guessing to implement the shadow effect I'm looking for I need to do something with the shaders but I do not know how.
These are the shaders I'm using so far:
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D baseTexture;
uniform sampler2D bloomTexture;
varying vec2 vUv;
void main() {
gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
}
</script>
And this is how the selective bloom is implemented using .onBeforeCompile:
child.material.onBeforeCompile = shader => {
shader.uniforms.globalBloom = uniforms.globalBloom;
shader.fragmentShader = `
uniform float globalBloom;
${shader.fragmentShader}
`.replace(
`#include <dithering_fragment>`,
`#include <dithering_fragment>
if (globalBloom > 0.5){
gl_FragColor = texture2D( emissiveMap, vUv );
}
`
);
}
I'm really bad with shaders, there have been some solutions in the above mentioned discussion, however I've just way to little experience with shaders and GLSL to know what I need to do.
How can I implement soft/gradient shadow casting using an alpha texture as strength indicator?
Given a WebGL scene (created from THREE.js), how would you go about accessing the floating point values (as an array of data outside of the WebGL context) from the DEPTH_ATTACHMENT given the framebuffer has been bound to texture using framebufferTexture2D.
I've gathered one solution thus far which is to render the scene to a texture target using a custom shader override which accesses the depth texture information and then encodes it to RGB format. The code used is very similar to this THREE.js example found here: Depth-Texture-Example.
#include <packing>
varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform sampler2D tDepth;
uniform float cameraNear;
uniform float cameraFar;
float readDepth (sampler2D depthSampler, vec2 coord) {
float fragCoordZ = texture2D(depthSampler, coord).x;
float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );
return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );
}
void main() {
vec3 diffuse = texture2D(tDiffuse, vUv).rgb;
float depth = readDepth(tDepth, vUv);
gl_FragColor.rgb = vec3(depth);
gl_FragColor.a = 1.0;
}
Once this has rendered I can then use readPixels to read the specific pixels into an array. However, this option has incredibly low precision restricted to 256 discrete values given vec3(float) = vec3(float, float, float). Is there a way to get higher precision out of this specific method or an alternative?
Ultimately what I want is access to the depth buffer as an array of floating point values outside of the WebGL context and in an efficient manner. I have a custom rasterizer that can create a rather good depth buffer but I don't want to waste any time redoing steps that are already done.
One possibility would be to encode the 24 significant bits of a 32 bit IEEE 754 floating point value to a vec3:
vec3 PackDepth(float depth)
{
float depthVal = depth * (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
vec4 encode = fract(depthVal * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0));
return encode.xyz - encode.yzw / 256.0 + 1.0/512.0;
}
The R, G and B color channels can be decoded to a depth in range [0.0, 1.0] like this:
depth = (R*256.0*256.0 + G*256.0 + B) / (256.0*256.0*256.0 - 1.0);
I'm converting a Shadertoy to a local Three.js project, and can't get it to render. You can try out the full snippet here.
I think the problem may lie in how I'm converting the iResolution variable. As I understand it, the built-in Shadertoy global variable iResolution contains the pixel dimensions of the window. Here is how iResolution is used in the original Shadertoy:
vec2 uv = fragCoord.xy / iResolution.y;
vec2 ak = abs(fragCoord.xy / iResolution.xy-0.5);
In converting this Shadertoy into a local Three.js-based script I have tried two approaches to converting iResolution:
1) Loading the window dimensions as a Vector2 and sending them into the shader as the uniform vec2 uResolution:
vec2 uv = gl_FragCoord.xy / uResolution.y;
vec2 ak = abs(gl_FragCoord.xy / uResolution.xy-0.5);
This solution sticks closest to the design of the original Shadertoy, but alas nothing renders.
2) The second approach comes from this SO Answer and converts the uv coordinates to xy absolute coordinates:
vec2 uvCustom = -1.0 + 2.0 *vUv;
vec2 ak = abs(gl_FragCoord.xy / uvCustom.xy-0.5);
In this one, I admit I don't fully understand how it works, and my use of the uvCustom in the second line may not be correct.
In the end, nothing renders onscreen except a Three.js CameraHelper I'm using. Otherwise, the screen is black and the console shows no errors for the Javascript or WebGL. Thanks for taking a look!
For starters, you don't need to even do this division. If you are using a full screen quad (PlaneBufferGeometry), you can render it with just the uvs:
vec2 uv = gl_FragCoord.xy / uResolution.y;
vec2 vUv = varyingUV;
uv == vUv; //sort of
your vertex shader can look something like this
varying vec2 varyingUV;
void main(){
varyingUV = uv;
gl_Position = vec4( position.xy , 0. , 1.);
}
If you make a new THREE.PlaneGeometry(2,2,1,1); this should render as a full screen quad
For performance reasons I need to display hundred of moving tetrahedrons in a scene. There for I use instancedbuffergeometry which requires a custom shader.
The scene also contains objects with regular geometry (non-buffer) and some lights (I prepared boiled-down snippet: https://jsfiddle.net/negan/xs3k1yz4/ ).
My problem is that the tetrahedrons are not shaded such that their lighting plausibly fits to the rest of the scene. The reason is probably the primitive shader I built:
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec3 offset;
attribute vec4 color;
varying vec4 vColor;
varying vec3 vNormal;
void main() {
vColor = color;
vNormal = normalMatrix * vec3(normal);
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position*1.0+offset,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec4 vColor;
varying vec3 vNormal;
void main() {
float di = 0.4*dot(vNormal,normalize(vec3(1.,1.,0.)))+0.4*dot(vNormal,normalize(vec3(1.,0.,1.)));
di = di+0.2;
vec4 vColor2= vColor*vec4(1.0,1.,1.,0.2)*di;
gl_FragColor = vColor2;// adjust the alpha
}
</script>
Is there a way to make the custom shader fit the lights I defined in the scene? The shader also renders the faces in such a way which does not make the impression of directed light. I'd rather like to have single faces lit evenly rather that have the color interpolated from the vertices but I was unable to achieve that.
Any pointer or help is appreciated.
Here's a gist of the full fragment and vertex shader source for a Three.js MeshPhongMaterial shader, as of r83.
Three.js builds shaders using a string concatenation system, so figuring out the source of a shader from looking at the Three.js source will be almost impossible.
The above Gist was generated by installing the shader editor Chrome extension, going to a Three.js example page that has a MeshPhongMaterial like this one and using the shader editor to inspect the full source of a running shader program:
Three.js passes all default uniforms, like lighting data, to all shader programs, so if you create a custom shader with the above Gist code, lights, bones, etc, will all work automatically.
I would take the full source code and add your logic in manually, literally adding the result of your calculations to the existing gl_FragColor = ...
In the future, my tool ShaderFrog will let you automatically add any Three.js shader feature (lights, bones, morph targets, etc) to any custom shader. ShaderFrog can already combine any shaders together automatically, but I haven't done the manual work needed to fully support Three features yet.
There's InstancedMesh module for three.js . It allows mesh instancing without using shader materials. It patches the existing material.
https://github.com/pailhead/three-instanced-mesh
I'm learning WebGL, and I would like to make a program, where there are colored, and textured objects also. I tried to modify a bit the fragment shader: If the object don't have texture, then it will be colored.
precision mediump float;
varying vec4 vColor;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = vColor;
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
It doesn't works. I get an error: Could not initialize shaders.
This may or may not make sense but whether you have a texture or not requires different shaders. To get around this many people use a single pixel white texture when they don't want textures. That way they only need 1 shader to cover both cases. The shader might look something like this
uniform vec4 u_color;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main(void) {
gl_FragColor = texture2D(u_texture, v_texCoord) * u_color;
}
Now, in your code you can draw textured like this
// at init time.
var whiteColor = new Float32Array([1, 1, 1, 1]);
// at draw time
gl.uniform4fv(u_colorLocation, whiteColor); // use white color
gl.bindTexture(gl.TEXTURE_2D, someTexture); // and some texture
... draw ...
And to draw un-textured you do this
// at init time.
var whiteTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);
var whitePixel = new Uint8Array([255, 255, 255, 255]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
gl.RGBA, gl.UNSIGNED_BYTE, whitePixel);
// at draw time
gl.uniform4fv(u_colorLocation, someColor); // use the color I want
gl.bindTexture(gl.TEXTURE_2D, whiteTexture); // use the white texture
... draw ...
That also gives you the ability to tint your textures by using a non white color and a texture together.
I think we may need to see some more code before we can hel you figure out the exact issue. For example, what does your vertex shader look like, and how are you linking them?
In the meantime there are a couple of pointers I can give you about the shader you posted. For one, it will not give you the effect that you described. What will actually happen is that it will always show the texture color or, if no texture is given, display black. The vertex color will never be shown. This is because you are assigning to the final fragment color twice, with the second assignment always overriding the first.
What you might want to try is blending the two values together by either adding or multiplying the color and texture values. Try something like so:
gl_FragColor = vColor + texture2D(uSampler, vTextureCoord);
The only problem there is that if the texture is empty you'll still get black (anything multiplied by 0 is still 0). To avoid that, always use a solid white texture if you don't have an actual texture available.
If you want the exact effect you described (vertex color only if no texture) you may need to use a conditional statement. Those are typically best avoided but I doubt your usage will be anything terribly heavy.
Also, as a style tip, The following lines are equivalent:
vec2(vTextureCoord.s, vTextureCoord.t)
vTextureCoord.st
The second may be faster, however, and should be preferred. Beyond that, however, you could just pass in vTextureCoord directly (like I showed) because it already is a vec2.