Sign in to follow this  
Eldritch

OpenGL Need suggestions regarding how to overcome the limitations of lighting

Recommended Posts

With only 8 crap lights in OpenGL (why do they have to put limitations on EVERYTHING, it drives me mad), how do I perform the most effective lighting setup using GLSL? I tried doing it with checking what 3 lights were in range of each of the rendered objects and then assigned their values, but that got pooped as shaders only take a shit low value of parameters, which I find to be utterly despicable. I am begging for suggestions on how to make this possible. I need to render each of my objects with all the possible amount of lights affecting it.

Share this post


Link to post
Share on other sites
You can draw each light in a separate pass. This way You can have unlimited number of lights in Your scene (and shadows too). Just draw ambient pass first, and the set depth test to LEQUAL and turn on additive blending (ONE to ONE). The render the whole scene with one light turned on (repeat this for every light).

Share this post


Link to post
Share on other sites
But, won't drawing the same models over and over present me with two problems:

1. Z-fighting.
2. A humungous strain on the CPU and/or GPU.

Got any pseudocode to post?

Share this post


Link to post
Share on other sites
Setting depth func to GL_LEQUAL eliminates z fighting (don't use EQUAL as some do). Here is some pseudocode:


SetupTheScene();
RenderAmbientPass();

glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_ONE,GL_ONE);
glEnable(GL_BLEND);

for (int i = 0; i < NumberOfLights; i++) RenderLightPassUsingLight(i);

glDepthFunc(GL_LESS);
glDisable(GL_BLEND);



By ambient pass I mean no lights turned on - only ambient component.
Light pass means rendering the scene with i-th light turned on.

Later You can modify it:


SetupTheScene();
RenderAmbientPass();

glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_ONE,GL_ONE);
glEnable(GL_BLEND);

for (int i = 0; i < NumberOfLights; i++)
{
RenderShadowsForLight(i);
RenderLightPassUsingLight(i);
}

glDepthFunc(GL_LESS);
glDisable(GL_BLEND);



This algorithm is used almost everywhere now.

Share this post


Link to post
Share on other sites
Quote:
Original post by Eldritch
Hmm, this looks quite easy. SetupTheScene(), what would that include?


Setting the modelview matrix and/or other things You do at the begining of each frame.

Share this post


Link to post
Share on other sites
During the ambient pass, what exactly should be enabled? Should I use shaders at all?

I did the stuff you mentioned, but now I get a very messed up scene. Some polygons are translucent while others are solid, and the lighting looks like big squares of color.

Share this post


Link to post
Share on other sites
During the ambient pass You typicaly render only the diffuse texture multiplied by some small number representing ambient lighting.
Post a screenshot and we'll figure what's wrong.

Share this post


Link to post
Share on other sites
To multipass rendering, this code can helps. I use in that way:

setPerspectiveMode( camera.xp,camera.yp,camera.zp, camera.xlp,camera.ylp,camera.zlp, camera.degrees );
if ( glIsEnabled( GL_LIGHTING ) ){
int sm = 0; int npass = 0;//npass is the number of passes of the drawing scene.
const unsigned int MaxLightsPerFrame = 4;
for ( int v=0; v<N_MAX_LIGHTS; v++ ){
sm += OE.toeLight[v].enabled;
}
npass = sm/MaxLightsPerFrame; //Will draw 4 lights at each frame
if ( sm%MaxLightsPerFrame > 0 )
npass+=sm%MaxLightsPerFrame;
//cout <<npass<<endl;
for( int n=0; n<npass; n++ ){
if ( glIsEnabled( GL_LIGHT0 ) )
glLightfv(GL_LIGHT0+(MaxLightsPerFrame*n), GL_POSITION, OE.toeLight[0+(MaxLightsPerFrame*n)].position );
if ( glIsEnabled( GL_LIGHT1 ) )
glLightfv(GL_LIGHT1+(MaxLightsPerFrame*n), GL_POSITION, OE.toeLight[1+(MaxLightsPerFrame*n)].position );
if ( glIsEnabled( GL_LIGHT2 ) )
glLightfv(GL_LIGHT2+(MaxLightsPerFrame*n), GL_POSITION, OE.toeLight[2+(MaxLightsPerFrame*n)].position );
if ( glIsEnabled( GL_LIGHT3 ) )
glLightfv(GL_LIGHT3+(MaxLightsPerFrame*n), GL_POSITION, OE.toeLight[3+(MaxLightsPerFrame*n)].position );

drawFunc();
}
}else{
drawFunc();
}
unsetPerspectiveMode();



where N_MAX_LIGHTS is the maximum number of lights that your game/engine will use at once.

But I'm thinking... Is better use 4 lights at each redraw, or 8 ligths?
Because if I will draw 32 point lights, I don't know wich performe better, draw 4 lights each frame totalyzing 8 redraws, or, draw 8 lights(the maximum provided by the OpenGL implementation) each time, redrawing the scene 4 times?

Share this post


Link to post
Share on other sites
Why should You use standard OGL lights? They are very slow and have limited functionality. It's better to use one light in one pass and do all lighting in shaders. If You want to use shadows this is the only way to do it.

Share this post


Link to post
Share on other sites
Now I did it so that when the renderer is running an ambient pass, it only sets the GL_AMBIENT part of glMaterialfv() (this one is skipped during light passes) and uses fixed functions instead of shaders so there is no interference from the lights.

The scene now is totally bright.. I can hardly see anything.

Share this post


Link to post
Share on other sites
Here You can see multipass algorithm in work in my engine. 3 lights (red, green, blue) affect the same objects, which cast soft shadows.

Free Image Hosting at www.ImageShack.us

It can only be done using one light-per-pass shader approach.

BTW. Don't mind the strange artifacts in some places.

Share this post


Link to post
Share on other sites
Nice screenshot! Had to grab a bite, felt quite famished there... Well, here comes the code:

Rendering loop

void CRenderer::Render3D()
{
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_ONE, GL_ONE);
//glEnable(GL_BLEND); blending is always on

for (unsigned int i = 0; i < i3DObjects.size(); i++)
{
// Render ambient pass.
float col[4] = {0, 0, 0, 1};
glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
glLightfv(GL_LIGHT1, GL_AMBIENT, col);
glLightfv(GL_LIGHT1, GL_SPECULAR, col);
iAmbientPass = true;
i3DObjects[i]->Draw();
iAmbientPass = false;

for (int j = 0; j < 4; j++)
{
CLight* L = CScenegraph::Instance()->GetLight(j);
if (L != NULL)
{
glLightfv(GL_LIGHT1, GL_POSITION, L->pos);
glLightfv(GL_LIGHT1, GL_DIFFUSE, L->diff);
glLightfv(GL_LIGHT1, GL_AMBIENT, L->amb);
glLightfv(GL_LIGHT1, GL_SPECULAR, L->spec);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, L->att[0]);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, L->att[1]);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, L->att[2]);
i3DObjects[i]->Draw();
}
}
}

glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
glDepthFunc(GL_LESS);
}



Code for drawing a mesh

void CMesh::Draw()
{
for (unsigned int i = 0; i < iMeshObj.size(); i++)
{
if (CRenderer::Instance()->IsInAmbientPass() == true)
{
glMaterialfv(GL_FRONT, GL_AMBIENT, iMeshObj[i]->iAmbient);
}
else
{
glMaterialfv(GL_FRONT, GL_DIFFUSE, iMeshObj[i]->iDiffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, iMeshObj[i]->iAmbient);
glMaterialfv(GL_FRONT, GL_SPECULAR, iMeshObj[i]->iSpecular);
glMaterialf(GL_FRONT, GL_SHININESS, iMeshObj[i]->iShininess);
}

// Check for frustum containment on the object bounding box.
if (CFrustum::Instance()->CubeIsInFrustum(iMeshObj[i]->iBBox.GetCenter(),
iMeshObj[i]->iBBox.GetExtents().GetX()) == true)
{
// Check for and enable possible shader and/or multi-texture.
if (iMeshObj[i]->iMultiTexturing == true)
{
CRenderer::Instance()->EnableMultiTexturing(iMeshObj[i]->iMaterial, iMeshObj[i]->iMultiMaterial);
}
else
{
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, CRenderer::Instance()->GetMaterial(iMeshObj[i]->iMaterial));
}

if (CRenderer::Instance()->IsInAmbientPass() == false)
{
CShaderManager::Instance()->UseShader(iMeshObj[i]->iShader);
CShaderManager::Instance()->SetShaderParams(iMeshObj[i]);
}

// Check for frustum containment on the partition nodes.
for (unsigned int j = 0; j < iMeshObj[i]->iPartition.iNodes.size(); j++)
{
if (CFrustum::Instance()->CubeIsInFrustum(iMeshObj[i]->iPartition.iNodes[j]->iBBox.GetCenter(),
iMeshObj[i]->iPartition.iNodes[j]->iBBox.GetExtents().GetX()) == true)
{
glCallList(iMeshObj[i]->iPartition.iNodes[j]->iDisplayList);
}
}

if (CRenderer::Instance()->IsInAmbientPass() == false)
{
CShaderManager::Instance()->NoShader();
}

if (iMeshObj[i]->iMultiTexturing == true)
{
CRenderer::Instance()->DisableMultiTexturing();
}
}
}
}



Screenshots


Share this post


Link to post
Share on other sites
Disable blending for ambient pass - You're accumulating results form previus frames. And rearrange Your code. Something like this:


void CRenderer::Render3D()
{
glDisable(GL_BLEND);
iAmbientPass = true;
// Render ambient pass.
float col[4] = {0, 0, 0, 1};
glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
glLightfv(GL_LIGHT1, GL_AMBIENT, col);
glLightfv(GL_LIGHT1, GL_SPECULAR, col);
for (unsigned int i = 0; i < i3DObjects.size(); i++) i3DObjects[i]->Draw();
iAmbientPass = false;
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
for (int j = 0; j < 4; j++)
{
CLight* L = CScenegraph::Instance()->GetLight(j);
glLightfv(GL_LIGHT1, GL_POSITION, L->pos);
glLightfv(GL_LIGHT1, GL_DIFFUSE, L->diff);
glLightfv(GL_LIGHT1, GL_AMBIENT, L->amb);
glLightfv(GL_LIGHT1, GL_SPECULAR, L->spec);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, L->att[0]);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, L->att[1]);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, L->att[2]);
for (unsigned int i = 0; i < i3DObjects.size(); i++) i3DObjects[i]->Draw();
}
glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
glDepthFunc(GL_LESS);
}




Try that.

in future don't use standard lights - it's a trip to nowhere.

Share this post


Link to post
Share on other sites
Forgot about something. For ambient pass set material properties for diffuse and specular to 0 and ambient to desired color. For light pass set ambient material to 0 and diffuse + specular to desired color. The same goes for light color.

Share this post


Link to post
Share on other sites
Made the rearrangement you suggested, and set diffuse and specular to 0 during ambient pass as well as set ambient to 0 during light passes.

The scene is not lit at all now. All is black, black as the night :)

Share this post


Link to post
Share on other sites
Hmmm... That's odd... Try this:


void CRenderer::Render3D()
{
glDisable(GL_BLEND);
iAmbientPass = true;
// Render ambient pass.
float col[4] = {0, 0, 0, 1};
glLightfv(GL_LIGHT1, GL_DIFFUSE, col);
glLightfv(GL_LIGHT1, GL_AMBIENT, L->amb);
glLightfv(GL_LIGHT1, GL_SPECULAR, col);
for (unsigned int i = 0; i < i3DObjects.size(); i++) i3DObjects[i]->Draw();
iAmbientPass = false;
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
for (int j = 0; j < 4; j++)
{
CLight* L = CScenegraph::Instance()->GetLight(j);
glLightfv(GL_LIGHT1, GL_POSITION, L->pos);
glLightfv(GL_LIGHT1, GL_DIFFUSE, L->diff);
glLightfv(GL_LIGHT1, GL_AMBIENT, col);
glLightfv(GL_LIGHT1, GL_SPECULAR, L->spec);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, L->att[0]);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, L->att[1]);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, L->att[2]);
for (unsigned int i = 0; i < i3DObjects.size(); i++) i3DObjects[i]->Draw();
}
glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
glDepthFunc(GL_LESS);
}




void CMesh::Draw()
{
float col[4] = {0, 0, 0, 1};
for (unsigned int i = 0; i < iMeshObj.size(); i++)
{
if (CRenderer::Instance()->IsInAmbientPass() == true)
{
glMaterialfv(GL_FRONT, GL_AMBIENT, iMeshObj[i]->iAmbient);
glMaterialfv(GL_FRONT, GL_SPECULAR, col);
glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
}
else
{
glMaterialfv(GL_FRONT, GL_DIFFUSE, iMeshObj[i]->iDiffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, col);
glMaterialfv(GL_FRONT, GL_SPECULAR, iMeshObj[i]->iSpecular);
glMaterialf(GL_FRONT, GL_SHININESS, iMeshObj[i]->iShininess);
}

// Check for frustum containment on the object bounding box.
if (CFrustum::Instance()->CubeIsInFrustum(iMeshObj[i]->iBBox.GetCenter(),
iMeshObj[i]->iBBox.GetExtents().GetX()) == true)
{
// Check for and enable possible shader and/or multi-texture.
if (iMeshObj[i]->iMultiTexturing == true)
{
CRenderer::Instance()->EnableMultiTexturing(iMeshObj[i]->iMaterial, iMeshObj[i]->iMultiMaterial);
}
else
{
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, CRenderer::Instance()->GetMaterial(iMeshObj[i]->iMaterial));
}

if (CRenderer::Instance()->IsInAmbientPass() == false)
{
CShaderManager::Instance()->UseShader(iMeshObj[i]->iShader);
CShaderManager::Instance()->SetShaderParams(iMeshObj[i]);
}

// Check for frustum containment on the partition nodes.
for (unsigned int j = 0; j < iMeshObj[i]->iPartition.iNodes.size(); j++)
{
if (CFrustum::Instance()->CubeIsInFrustum(iMeshObj[i]->iPartition.iNodes[j]->iBBox.GetCenter(),
iMeshObj[i]->iPartition.iNodes[j]->iBBox.GetExtents().GetX()) == true)
{
glCallList(iMeshObj[i]->iPartition.iNodes[j]->iDisplayList);
}
}

if (CRenderer::Instance()->IsInAmbientPass() == false)
{
CShaderManager::Instance()->NoShader();
}

if (iMeshObj[i]->iMultiTexturing == true)
{
CRenderer::Instance()->DisableMultiTexturing();
}
}
}
}



If that doesn't help then I don't know what's wrong.

Share this post


Link to post
Share on other sites
Noticed a small error in your suggestion. Before rendering the ambient pass, this will likely not work for the compiler:

glLightfv(GL_LIGHT1, GL_AMBIENT, L->amb);

Does it matter if I set the light's ambience? I mean, I do not use the shaders while rendering the ambient pass. Should I perhaps use them?

Share this post


Link to post
Share on other sites
You're right about that error, didn't notice it. You should set some ambience for ambient pass or everything will be black if there's no light.
If You want to use shaders You have to make a distinction between them for ambient and light pass. Here's an example:

Free Image Hosting at www.ImageShack.us

A separate shader for every situation.

Share this post


Link to post
Share on other sites
Seems like it does not really matter if I use a light or not during the ambient pass, everything is black nontheless. Probably due to the thing you just wrote, that I need a separate shader for the ambient pass. What should that shader include?

If I render only one light pass, it works, but looks very weird. Here is a screenshot of the scene with one light pass:

Share this post


Link to post
Share on other sites
Here's my ambient shader:


uniform sampler2D DiffuseMap;

uniform vec4 AmbientColor;

void main()
{
gl_FragColor = texture2D(DiffuseMap,gl_TexCoord[0].st) * AmbientColor;
}




Simple Texure * Ambient. Note: Ambient color should be small (about 0.1) or everything will glow like a light bulb.

The terrain on Your screenshot looks fine (unless it's supposed to look diffrent:)). I don't know what are these floating black things.
A simple shader for light pass would look similar to ambient shader, but the resulting color should be multiplied by max(dot(Normal,LightDirection),0.0). Remember that LightDirection should be in the same space as Normal (object space / world space / tangent space).

Share this post


Link to post
Share on other sites
As the screenshot shows, the lighting is very blocky and not smooth at all.

Those black things are my rain particles, which have had their transparency messed up somehow.

Here is the shader I am using:

Vertex

varying vec4 diffuse, ambientGlobal, ambient;
varying vec3 normal, lightDir, halfVector;
varying float dist;

void main()
{
vec4 ecPos;
vec3 aux;

normal = normalize(gl_NormalMatrix * gl_Normal);

// These are the new lines of code to compute the light's direction.
ecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[1].position - ecPos);
lightDir = normalize(aux);
dist = length(aux);

halfVector = normalize(gl_LightSource[1].halfVector.xyz);

// Compute the diffuse, ambient and globalAmbient terms.
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[1].diffuse;

// The ambient terms have been separated since one of them
// suffers from attenuation.
ambient = gl_FrontMaterial.ambient * gl_LightSource[1].ambient;
ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;

gl_Position = ftransform();

gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}



Fragment

varying vec4 diffuse, ambientGlobal, ambient;
varying vec3 normal, lightDir, halfVector;
varying float dist;

uniform sampler2D TexMap1;

void main()
{
vec3 n,halfV,viewV,ldir;
float NdotL,NdotHV;
vec4 color = ambientGlobal;
float att;

// A fragment shader can't write a varying variable, hence we need
// a new variable to store the normalized interpolated normal.
n = normalize(normal);

// Compute the dot product between normal and normalized lightdir.
NdotL = max(dot(n, normalize(lightDir)), 0.0);

//if (NdotL > 0.0)
//{
att = 1.0 / (gl_LightSource[1].constantAttenuation +
gl_LightSource[1].linearAttenuation * dist +
gl_LightSource[1].quadraticAttenuation * dist * dist);

color += att * (diffuse * NdotL + ambient);

halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV), 0.0);
color += att * gl_FrontMaterial.specular * gl_LightSource[1].specular *
pow(NdotHV, gl_FrontMaterial.shininess);
//}

color = color * texture2D(TexMap1, gl_TexCoord[0].st);

gl_FragColor = color;
}



I snatched these from GWiki, but the fragment shader had a problem with the NdotL thing, hence why I commented the if-statement.

Share this post


Link to post
Share on other sites
Actually, swapping the two for-loops in the rendering loop to "For each 3D Object" first and then "For each light", makes the lights appear, though the lighting is really blocky and not smooth at all. I am suspecting that part of the problem is due to the shaders.

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Forum Statistics

    • Total Topics
      627764
    • Total Posts
      2978976
  • Similar Content

    • By DelicateTreeFrog
      Hello! As an exercise for delving into modern OpenGL, I'm creating a simple .obj renderer. I want to support things like varying degrees of specularity, geometry opacity, things like that, on a per-material basis. Different materials can also have different textures. Basic .obj necessities. I've done this in old school OpenGL, but modern OpenGL has its own thing going on, and I'd like to conform as closely to the standards as possible so as to keep the program running correctly, and I'm hoping to avoid picking up bad habits this early on.
      Reading around on the OpenGL Wiki, one tip in particular really stands out to me on this page:
      For something like a renderer for .obj files, this sort of thing seems almost ideal, but according to the wiki, it's a bad idea. Interesting to note!
      So, here's what the plan is so far as far as loading goes:
      Set up a type for materials so that materials can be created and destroyed. They will contain things like diffuse color, diffuse texture, geometry opacity, and so on, for each material in the .mtl file. Since .obj files are conveniently split up by material, I can load different groups of vertices/normals/UVs and triangles into different blocks of data for different models. When it comes to the rendering, I get a bit lost. I can either:
      Between drawing triangle groups, call glUseProgram to use a different shader for that particular geometry (so a unique shader just for the material that is shared by this triangle group). or
      Between drawing triangle groups, call glUniform a few times to adjust different parameters within the "master shader", such as specularity, diffuse color, and geometry opacity. In both cases, I still have to call glBindTexture between drawing triangle groups in order to bind the diffuse texture used by the material, so there doesn't seem to be a way around having the CPU do *something* during the rendering process instead of letting the GPU do everything all at once.
      The second option here seems less cluttered, however. There are less shaders to keep up with while one "master shader" handles it all. I don't have to duplicate any code or compile multiple shaders. Arguably, I could always have the shader program for each material be embedded in the material itself, and be auto-generated upon loading the material from the .mtl file. But this still leads to constantly calling glUseProgram, much more than is probably necessary in order to properly render the .obj. There seem to be a number of differing opinions on if it's okay to use hundreds of shaders or if it's best to just use tens of shaders.
      So, ultimately, what is the "right" way to do this? Does using a "master shader" (or a few variants of one) bog down the system compared to using hundreds of shader programs each dedicated to their own corresponding materials? Keeping in mind that the "master shaders" would have to track these additional uniforms and potentially have numerous branches of ifs, it may be possible that the ifs will lead to additional and unnecessary processing. But would that more expensive than constantly calling glUseProgram to switch shaders, or storing the shaders to begin with?
      With all these angles to consider, it's difficult to come to a conclusion. Both possible methods work, and both seem rather convenient for their own reasons, but which is the most performant? Please help this beginner/dummy understand. Thank you!
    • By JJCDeveloper
      I want to make professional java 3d game with server program and database,packet handling for multiplayer and client-server communicating,maps rendering,models,and stuffs Which aspect of java can I learn and where can I learn java Lwjgl OpenGL rendering Like minecraft and world of tanks
    • By AyeRonTarpas
      A friend of mine and I are making a 2D game engine as a learning experience and to hopefully build upon the experience in the long run.

      -What I'm using:
          C++;. Since im learning this language while in college and its one of the popular language to make games with why not.     Visual Studios; Im using a windows so yea.     SDL or GLFW; was thinking about SDL since i do some research on it where it is catching my interest but i hear SDL is a huge package compared to GLFW, so i may do GLFW to start with as learning since i may get overwhelmed with SDL.  
      -Questions
      Knowing what we want in the engine what should our main focus be in terms of learning. File managements, with headers, functions ect. How can i properly manage files with out confusing myself and my friend when sharing code. Alternative to Visual studios: My friend has a mac and cant properly use Vis studios, is there another alternative to it?  
    • By ferreiradaselva
      Both functions are available since 3.0, and I'm currently using `glMapBuffer()`, which works fine.
      But, I was wondering if anyone has experienced advantage in using `glMapBufferRange()`, which allows to specify the range of the mapped buffer. Could this be only a safety measure or does it improve performance?
      Note: I'm not asking about glBufferSubData()/glBufferData. Those two are irrelevant in this case.
    • By xhcao
      Before using void glBindImageTexture(    GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format), does need to make sure that texture is completeness. 
  • Popular Now