I am trying to use a single cubemap texture for a skybox and reflections, but I just end up with a black texture for both. I am using a temporary array of pixels for the cubemap to make sure the image wasn't the problem. So just ignore the SDL stuff in this function; I commented some of it out. Also the texture functions and shaders are used for both 2d and cubemap textures so I commented that out as well.
Texture loading: zTexture* vars are class vars
bool loadCubeMap(std::vector<const char*> path)
{
//Texture loading success
bool textureLoaded = false;
glEnable(GL_TEXTURE_CUBE_MAP); //probably not needed
for(int j=0; j<path.size(); j++)
{
//SDL_Surface* cubFacSurf = IMG_Load(path[j]);
if(cubFacSurf != NULL)
{
//SDL_LockSurface(cubFacSurf);
zTextureW = cubFacSurf->w;
zTextureH = cubFacSurf->h;
textureLoaded = loadFromPixels((GLuint*)cubFacSurf->pixels, zTextureW, zTextureH, GL_TEXTURE_CUBE_MAP, GL_RGB, GL_TEXTURE_CUBE_MAP_POSITIVE_X+j);
//SDL_UnlockSurface(cubFacSurf);
//SDL_FreeSurface(cubFacSurf);
}
if(textureLoaded == false)
{
SDL_Log("Unable to load %s\n", path[j]);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return textureLoaded;
}
main pixel loader
bool loadFromPixels(void* pixels, GLuint width, GLuint height, const GLenum tType = GL_TEXTURE_2D, const GLenum glPix = GL_RGB, const GLenum tFace = GL_TEXTURE_2D)
{
glGenTextures(1, &zTextureID);
glBindTexture(tType, zTextureID);
GLfloat checkerboard[] = {1.f,1.f,1.f, 0.f,0.f,0.f, 0.f,0.f,0.f, 1.f,0.f,1.f};
if(tType == GL_TEXTURE_CUBE_MAP)
glTexImage2D(tFace, 0, glPix, 2, 2, 0, glPix, GL_FLOAT, &checkerboard);
//else
//glTexImage2D(tFace, 0, glPix, width, height, 0, glPix, GL_UNSIGNED_BYTE, pixels);
//Check for error
GLenum error = glGetError();
if( error != GL_NO_ERROR )
{
SDL_Log( "Error loading texture from %p pixels! %d\n", pixels, error);
return false;
}
return true;
}
Texture Binding:
void apply(const GLenum typ = GL_TEXTURE_2D)
{
glEnable(typ); //Probably not necessary doesnt change anything if left out
if(typ == GL_TEXTURE_2D)
{
glDisable(GL_TEXTURE_CUBE_MAP); //same here
glUniform1i(mainTxtrID, 0); //mainTxtrID = Textr in frag
glActiveTexture(GL_TEXTURE0);
}
else
{
glDisable(GL_TEXTURE_2D); //and here
glUniform1i(cubeID, 1); //cubeID = TextCub in frag
glActiveTexture(GL_TEXTURE1);
}
glBindTexture(typ, zTextureID);
}
"Uber" Shaders:
vertex:
#version 100
precision mediump float;
uniform mat4 ModelMat;
uniform mat4 ViewMat;
uniform mat4 ProjMat;
uniform mat4 OrthMat;
uniform bool world;
attribute vec4 vPosition;
attribute vec2 UVCoordAt;
attribute vec3 nPosition;
varying vec2 UVCoord;
varying vec3 vPos;
varying vec3 vNor;
varying vec3 vRefl;
void main()
{
UVCoord = UVCoordAt;
vPos = vec3(vPosition); //skybox coords
vNor = normalize(vec3(ModelMat * vec4(nPosition,0.0)));
vRefl = reflect(normalize(vPos - vec3(ViewMat[3][0], ViewMat[3][1], ViewMat[3][2])), vNor); //reflection direction vector
if(world)
gl_Position = ProjMat * ViewMat * ModelMat * vPosition;
else gl_Position = OrthMat * ModelMat * vPosition;
}
fragment:
#version 100
precision mediump float;
uniform samplerCube TextCub;
uniform sampler2D Textr;
uniform vec3 LiPos;
uniform vec4 fragCol;
uniform bool lighting;
uniform bool dimen;
uniform bool isRefl;
varying vec2 UVCoord;
varying vec3 vPos;
varying vec3 vNor;
varying vec3 vRefl;
void main()
{
vec4 textVect = texture2D(Textr, UVCoord); //default texturing
if(dimen){ textVect = textureCube(TextCub, vPos); } //skybox
else if(isRefl){ textVect = mix(textVect, textureCube(TextCub, vRefl), 0.7); } //reflections mixed with default textr
if(lighting){
float diffuse = clamp(dot(vNor, LiPos), 0.0, 1.0);
gl_FragColor = clamp(diffuse*2.0, 0.6, 1.1) * fragCol * textVect;
}
else{ gl_FragColor = fragCol * textVect; }
}
I am using GL_DEPTH_TEST, I doubt this affects anything. I am guessing the problem is in the apply() function or something else I left out. There are extensions for cubemaps but I assume the default opengles 2 cubemaps work without them.
You're creating a new texture for each cubemap face. In the loadFromPixels() function, which you call for each face:
glGenTextures(1, &zTextureID);
glBindTexture(tType, zTextureID);
...
glTexImage2D(...);
This means that you will end up with 6 textures that each have only data for one face specified, which makes them incomplete.
You need to create one cubemap texture, and then specify data for all 6 sides of that cubemap.
Related
I'm trying to use multiple textures in expo, but for some reason whenever I try to bind more than one texture, even if the texture is unused in the shader, nothing renders to the screen.
Code that binds textures:
gl.useProgram(program);
gl.bindVertexArray(vao);
// Set texture sampler uniform
const TEXTURE_UNIT = 0;
const TEXTURE_UNIT2 = 1;
gl.uniform1i(uniformLocations.get('cameraTexture'), TEXTURE_UNIT);
gl.uniform1i(uniformLocations.get('segmentationTexture'), TEXTURE_UNIT2);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, cameraTexture);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, segmentationTexture);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, dims.width, dims.height);
gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 2);
//console.log("draws")
gl.bindVertexArray(null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.useProgram(null);
Fragment shader:
#version 300 es
precision highp float;
uniform sampler2D cameraTexture;
uniform sampler2D segmentationTexture;
in vec2 uv;
out vec4 fragColor;
void main() {
fragColor = texture(cameraTexture, uv); //segmentationTexture.r *
}
Vertex Shader:
const horizontalScale = flipHorizontal ? -1 : 1;
return `#version 300 es
precision highp float;
in vec2 position;
in vec2 texCoords;
out vec2 uv;
void main() {
// Invert geometry to match the image orientation from the camera.
gl_Position = vec4(position * vec2(${horizontalScale}., -1.), 0, 1);
uv = texCoords;
}`
I have checked both textures by commenting out the code the binds the other texture, e.g.
const TEXTURE_UNIT = 0;
//const TEXTURE_UNIT2 = 1;
gl.uniform1i(uniformLocations.get('cameraTexture'), TEXTURE_UNIT);
//gl.uniform1i(uniformLocations.get('segmentationTexture'), TEXTURE_UNIT2);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, cameraTexture);
//gl.activeTexture(gl.TEXTURE1);
//gl.bindTexture(gl.TEXTURE_2D, segmentationTexture);
or
//const TEXTURE_UNIT = 0;
const TEXTURE_UNIT2 = 1;
//gl.uniform1i(uniformLocations.get('cameraTexture'), TEXTURE_UNIT);
gl.uniform1i(uniformLocations.get('segmentationTexture'), TEXTURE_UNIT2);
//gl.activeTexture(gl.TEXTURE0);
//gl.bindTexture(gl.TEXTURE_2D, cameraTexture);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, segmentationTexture);
and both render fine individually.
However, the act of trying to bind multiple textures, even though only one is used in frag shader, leaves me with only a black screen.
I'm having a problem with fragment shader as you can see in the image below.
I don't want to render the parts that are in red in the image
I have to passes which culls clockwise and anticlockwise
and I'm getting the dot product of the normal with the camera position
if its less than 0 I set a transparent fragment
otherwise discard the fargment
here is the shader
#version 100
precision mediump float;
varying float lightDiffuse;
void main()
{
float light = ( 1.0 - lightDiffuse) * 0.5;
vec3 lightColor = vec3(0.0,1.0,1.0);
vec3 diffuseColor = lightColor * light ;
vec4 c;
if(lightDiffuse <0.0 )
{
// back faces, opaque
// front faces, very transparent
c = vec4(diffuseColor, 0.2);
}
else
{
discard;
}
gl_FragColor = c;
}
#version 100
#define lowp
#define mediump
#define highp
attribute vec4 vertex;
attribute vec3 normal;
uniform mat4 normalMatrix;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelView;
uniform vec3 camera_world_position;
varying highp float lightDiffuse;
void main()
{
gl_Position = modelViewProjectionMatrix * vertex;
vec3 norm = normal;
norm *=-1.0;
lightDiffuse = dot(normalize(vec3(norm.x, norm.y, norm.z)), normalize(camera_world_position));
}
here is the material script
material 44267_1508405690_0##carpaint
{
technique
{
pass
{
cull_hardware anticlockwise
scene_blend alpha_blend
vertex_program_ref char_shader2_vs100
{
param_named_auto modelViewProjectionMatrix worldviewproj_matrix
param_named_auto normalMatrix inverse_transpose_world_matrix
param_named_auto modelView worldview_matrix
param_named_auto camera_world_position camera_position
}
fragment_program_ref char_shader2_fs100
{
}
}
pass
{
cull_hardware clockwise
vertex_program_ref char_shader2_vs100
{
param_named_auto modelViewProjectionMatrix worldviewproj_matrix
param_named_auto normalMatrix inverse_transpose_world_matrix
param_named_auto modelView worldview_matrix
param_named_auto camera_world_position camera_position
}
fragment_program_ref char_shader2_fs100
{
}
}
}
}
If you want to cull occluded triangles, allocate a depth buffer and use a depth test, it's what it exists for.
Don't do facing tests in the fragment shader, that's not necessary and horribly expensive, just enable GL_CULL_FACE and set the front face correctly. Note that not all models downloaded off the internet get this right, so you might have an input model with broken winding for some triangles.
I want to see a wireframe of an object without the diagonals like
Currently, I add lines according to the vertices, the problem is after I have several of those I experience a major performance degradation.
The examples here are either too new for my version of Three or don't work (I commented there about it).
So I want to try to implement a shader instead.
I tried to use this shader: https://stackoverflow.com/a/31610464/4279201 but it breaks the shape to parts and I'm getting WebGL errors.
That's how I use it:
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`
const fragmentShader = `
#version 150 compatibility
flat in float diffuse;
flat in float specular;
flat in vec3 edge_mask;
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color ;
float edge_factor(){
vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);
vec3 d = fwidth(bary3);
vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);
a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;
return min(min(a3.x, a3.y), a3.z);
}
void main() {
float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
vec4 Kdiff = gl_FrontFacing ?
gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
float sdiffuse = s * diffuse;
vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
if (sdiffuse > 0.0) {
result += sdiffuse * Kdiff +
specular * gl_FrontMaterial.specular;
}
frag_color = (mesh_width != 0.0) ?
mix(vec4(mesh_color, 1.0), result, edge_factor()) :
result;
}`
...
const uniforms = {
color: {
value: new THREE.Vector4(0, 0, 1, 1),
type: 'v4'
}
}
const material = new THREE.ShaderMaterial({
fragmentShader: data.fragmentShader,
vertexShader: data.vertexShader,
uniforms
})
this._viewer.impl.matman().addMaterial(
data.name, material, true)
const fragList = this._viewer.model.getFragmentList()
this.toArray(fragIds).forEach((fragId) => {
fragList.setMaterial(fragId, material)
})
So to implement this shader, is the right approach would be to basically check the angle between every two vertices, and draw a line if the degree is 90?
How can I have access to all the vertices of the shape from the vertex shader?
And how can I tell the fragment shader to draw a line between two vertices that match the above condition? (also to leave the default shading for everything else as is)
I'm using Autodesk viewer that uses Three.js rev 71.
// -- Vertex Shader --
precision mediump float;
// Input from buffers
attribute vec3 aPosition;
attribute vec2 aBaryCoord;
// Value interpolated accross pixels and passed to the fragment shader
varying vec2 vBaryCoord;
// Uniforms
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main() {
vBaryCoord = aBaryCoord;
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);
}
// ---------------------
// -- Fragment Shader --
// This shader doesn't perform any lighting
precision mediump float;
varying vec2 vBaryCoord;
uniform vec3 uMeshColour;
float edgeFactor() {
vec3 d = fwidth(vBaryCoord);
vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);
return min(min(a3.x,a3.y),a3.z);
}
void main() {
gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);
}
// ---------------------
/*
This code isn't tested so take it with a grain of salt
Idea taken from
http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
*/
I have a cube , i want to bind a computed fragment shader to a cube face. any help?
my vertex shader is :
precision highp float;
attribute vec3 position;
attribute vec3 normal;
uniform mat3 normalMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 fNormal;
varying vec3 fPosition;
void main()
{
fNormal = normalize(normalMatrix * normal);
vec4 pos = modelViewMatrix * vec4(position, 1.0);
fPosition = pos.xyz;
gl_Position = projectionMatrix * pos;
}
and my fragment shader:
precision highp float;
uniform float time;
uniform vec2 resolution;
varying vec3 fPosition;
varying vec3 fNormal;
void main()
{
float minDimension = min(resolution.x, resolution.y);
vec2 bounds = vec2(resolution.x / minDimension, resolution.y / minDimension);
vec2 uv = gl_FragCoord.xy / minDimension;
vec2 midUV = vec2(bounds.x * 0.5, bounds.y * 0.5);
uv.xy-=midUV;
float dist = sqrt(dot(uv, uv));
float t = smoothstep(0.2+0.1*cos(time), 0.1-0.01, dist);
vec4 disc_color=vec4(1.0,0.,0.,1.);
vec4 bkg_color=vec4(0.0, 0.0, 0.0, 1.0);
vec4 resultColor;
resultColor = mix(bkg_color, disc_color, t);
gl_FragColor = resultColor;
}
i get a cube with a dot on the hole image.
but what i want is actually to have the dot on each face.
you can test the code directly under http://shdr.bkcore.com/
The standard approach to do this in OpenGL is to first render your content to a FBO (Frame Buffer Object). This allows you to render to a texture. You can then use this texture for one of the sides when rendering the cube.
The following is not complete code, but just an outline to give you a starting point:
// create a texture, and bind it
GLuint texId = 0;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
// set texture parameters (filters, wrap mode, etc)
glTexParameteri(GL_TEXTURE_2D, ...);
// allocate texture data (no data provided)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_FLOAT, 0);
glBindTexture(GL_TEXTURE_2D, texId);
// create and set up FBO with texture as attachment
GLuint fboId = 0;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
// create a depth renderbuffer and attach it if depth testing is needed
// start rendering
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glDraw...(...);
// back to default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, windowWidth, windowHeight);
glClear(GL_COLOR_BUFFER_BIT);
// render cube using texture we rendered to
glBindTexture(GL_TEXTURE_2D, texId);
// rest of state setup and rendering
thx for the answer, this is right, but i found a better way then rendering to a texture. i passed the texture coordinates and used them instead of the glfragcoord in the fragment shader.
I'm porting a piece of opengl to webgl and i'm trying to emulate texture3d. Somehow something is going wrong.
No interpolation is needed because it is only used for calculations. I'm not sure about the geometry part of the original code, the per layer properties are now fetched trough a texture.
Update : Ok i rewrote the texture 3d functions, I still encounter some problems :
const vec3 volumeTextureSize = vec3( 256.0, 128.0, 32.0 );
const vec2 imageSize = vec2( 1024.0, 1024.0 );
vec2 uvFromUvw( vec3 uvw ) {
const vec3 size = volumeTextureSize;
const vec2 layersPerDim = size.xy / imageSize.xy;
const vec2 pixelsPerLayer = imageSize / layersPerDim;
// normalized in
float layer = floor(uvw.z * size.z);
float layerX = mod(layer, layersPerDim.x);
float layerY = floor(layer / layersPerDim.x);
vec2 layerUv = vec2(layerX, layerY) * pixelsPerLayer;
vec2 layerSpaceUv = (uvw.xy * size.xy) / layersPerDim;
vec2 uv = layerSpaceUv + layerUv;
uv /= imageSize;
return uv;
}
vec4 texture3D( sampler2D tex, vec3 uvw ) {
vec2 uv = uvFromUvw( uvw );
return texture2D(tex, uv);
}
vec3 uvwFromUv( vec2 uv ) {
const vec3 size = volumeTextureSize;
const vec2 layersPerDim = imageSize.xy / size.xy;
const vec2 pixelsPerLayer = imageSize / layersPerDim;
vec2 normUv = uv / imageSize;
vec2 layerUv = floor(vec2(normUv * layersPerDim.xy));
vec3 uvw = vec3(0.0);
uvw.z = floor(layerUv.x + floor( layerUv.y * layersPerDim.x));
uvw.xy = uv - (layerUv * pixelsPerLayer.xy);
// normalized coords
// uvw.xy /= size.xy;
uvw.z /= layersPerDim.x * layersPerDim.y;
return uvw;
}
this is the original code i want to port:
glActiveTexture(GL_TEXTURE0 + deltaJUnit);
glGenTextures(1, &deltaJTexture);
glBindTexture(GL_TEXTURE_3D, deltaJTexture);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, RES_MU_S * RES_NU, RES_MU, RES_R, 0, GL_RGB, GL_FLOAT, NULL);
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, deltaJTexture, 0);
for (int layer = 0; layer < RES_R; ++layer) {
setLayer(jProg, layer);
.. also set uniforms
drawQuad();
}
and the glsl
#ifdef _VERTEX_
void main() {
gl_Position = gl_Vertex;
}
#endif
#ifdef _GEOMETRY_
#extension GL_EXT_geometry_shader4 : enable
void main() {
gl_Position = gl_PositionIn[0];
gl_Layer = layer;
EmitVertex();
gl_Position = gl_PositionIn[1];
gl_Layer = layer;
EmitVertex();
gl_Position = gl_PositionIn[2];
gl_Layer = layer;
EmitVertex();
EndPrimitive();
}
#endif