5
$\begingroup$

I tried passing a variable from the vertex shader to tell the fragment shader whether or not I wanted part of an object textured. That way I could write another shader for the other parts of the object. Unfortunately, what I have creates the undesirable effect seen here.

enter image description here

vertex shader for house

<script id="long_house-vs" type="x-shader/x-vertex">
    precision highp float;

    attribute vec3 vpos;
    attribute vec3 vnormal;
    attribute vec2 vtexCoords;

    varying vec3 outNormal;
    varying vec3 outPos;
    varying vec2 outTexCoords;
    // 1 if part of roof
    varying float roof;


    uniform mat4 view;
    uniform mat4 proj;
    uniform mat4 model;
    uniform vec3 lightdir;
    uniform vec3 long_housecolor;

    void main(void) {
        if(vpos.y > 1.2) {
            roof = 1.0;
        } else {
            roof = 0.0;
        }
        gl_Position = proj * view * model * vec4(vpos, 1.0);
        outTexCoords = vtexCoords;
        outPos =  (view * model * vec4(vpos, 1.0)).xyz;
        outNormal = normalize(view * model * vec4(vnormal,0.0)).xyz;
    }
</script>

fragment shader

<script id="long_house-fs" type="x-shader/x-fragment">
    precision highp float;
    varying vec3 outNormal;
    varying vec3 outPos;
    varying vec2 outTexCoords;
    varying float roof;

    uniform vec3 lightdir;
    uniform vec3 long_housecolor;
    uniform sampler2D usampler;
    uniform sampler2D urooftext;

    void main(void) {
        float diffuse = .5 + .5*abs(dot(outNormal, lightdir));
        vec3 outColor = long_housecolor * diffuse;
        vec4 textureColor;
        if(roof == 1.0) {
            textureColor = texture2D(urooftext, outTexCoords);
        } else {
            discard;
        }
        gl_FragColor = vec4(textureColor.rgb * diffuse, textureColor.a);
    }
</script>

When I rearrange the code a bit so that the bottom half of the house is textured instead of the top I get this

enter image description here

So what would be the correct way to write a shader that only affects part of an object?

$\endgroup$
  • $\begingroup$ You mean the noise effect? $\endgroup$ – narthex Dec 7 '16 at 19:28
  • $\begingroup$ @narthex I think so. How do I get rid of it? $\endgroup$ – Nebulous Ryan Dec 7 '16 at 19:44
  • $\begingroup$ anything stopping you from just splitting the object? $\endgroup$ – ratchet freak Dec 8 '16 at 13:08
4
$\begingroup$

In vertex, put vPos as varying. Then instead of doing the height check in vertex, do it in fragment.

if(outVPos.y > 1.2) 
{
   textureColor = texture2D(urooftext, outTexCoords);
} 
else 
{
   discard;
}

By the way, varying qualifier is deprecated and replaced with out in vertex and in in fragment.

| improve this answer | |
$\endgroup$
4
$\begingroup$

There are couple of ways this is usually done:

1) put the textures for the house to a single texture are just UV-map the object accordingly. If you would need to use different BRDF etc. for different parts of the object, you can use uber shader and switch in shader and use another texture to control which BRDF to use in which parts. The benefit is that you can render the entire object with a single draw call reducing CPU overhead with the expense of some GPU overhead due to the uber shader.

2) split the object to different sub-objects (at triangle level) based on the material and issue separate draw call for each. This keeps the shader simpler, but has higher CPU overhead due to more draw calls.

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.