Example #1
0
void material_internal::set(const char *pass_name) const
{
    if(!pass_name)
        return;

    if(m_last_set_pass_idx>=0)
        unset();

    m_last_set_pass_idx=get_pass_idx(pass_name);
    if(m_last_set_pass_idx<0)
        return;

    update_passes_maps();
    const pass &p=m_passes[m_last_set_pass_idx];

    p.m_shader.internal().set();
    for(int uniform_idx=0;uniform_idx<(int)p.m_uniforms_idxs_map.size();++uniform_idx)
        m_params[p.m_uniforms_idxs_map[uniform_idx]].apply_to_shader(p.m_shader,uniform_idx);

    for(int i=0;i<(int)p.m_pass_params.size();++i)
    {
        const pass::pass_param &pp=p.m_pass_params[i];
        p.m_shader.internal().set_uniform_value(pp.uniform_idx,pp.p.f[0],pp.p.f[1],pp.p.f[2],pp.p.f[3]);
    }

    nya_render::set_state(p.m_render_state);

    for(int slot_idx=0;slot_idx<(int)p.m_textures_slots_map.size();++slot_idx)
    {
        int texture_idx=p.m_textures_slots_map[slot_idx];
        if(texture_idx<0)
            continue;

        if(m_textures[texture_idx].proxy.is_valid())
        {
            if(!m_textures[texture_idx].proxy->internal().set(slot_idx))
            {
                nya_log::warning()<<"invalid texture for semantics '"<<p.m_shader.internal().get_texture_semantics(slot_idx)<<"' in material '"<<m_name<<"\n";
                missing_texture(is_shader_sampler_cube(p.m_shader,slot_idx)).internal().set(slot_idx);
            }
        }
        else
        {
            nya_log::warning()<<"invalid texture proxy for semantics '"<<p.m_shader.internal().get_texture_semantics(slot_idx)<<"' in material '"<<m_name<<"\n";
            missing_texture(is_shader_sampler_cube(p.m_shader,slot_idx)).internal().set(slot_idx);
        }
    }
}
Example #2
0
bool
TextureSystemImpl::environment(TextureHandle* texture_handle_,
                               Perthread* thread_info_, TextureOpt& options,
                               const Imath::V3f& _R, const Imath::V3f& _dRdx,
                               const Imath::V3f& _dRdy, int nchannels,
                               float* result, float* dresultds,
                               float* dresultdt)
{
    // Handle >4 channel lookups by recursion.
    if (nchannels > 4) {
        int save_firstchannel = options.firstchannel;
        while (nchannels) {
            int n   = std::min(nchannels, 4);
            bool ok = environment(texture_handle_, thread_info_, options, _R,
                                  _dRdx, _dRdy, n, result, dresultds,
                                  dresultdt);
            if (!ok)
                return false;
            result += n;
            if (dresultds)
                dresultds += n;
            if (dresultdt)
                dresultdt += n;
            options.firstchannel += n;
            nchannels -= n;
        }
        options.firstchannel = save_firstchannel;  // restore what we changed
        return true;
    }

    PerThreadInfo* thread_info = m_imagecache->get_perthread_info(
        (PerThreadInfo*)thread_info_);
    TextureFile* texturefile = verify_texturefile((TextureFile*)texture_handle_,
                                                  thread_info);
    ImageCacheStatistics& stats(thread_info->m_stats);
    ++stats.environment_batches;
    ++stats.environment_queries;

    if (!texturefile || texturefile->broken())
        return missing_texture(options, nchannels, result, dresultds,
                               dresultdt);

    const ImageSpec& spec(texturefile->spec(options.subimage, 0));

    // Environment maps dictate particular wrap modes
    options.swrap = texturefile->m_sample_border
                        ? TextureOpt::WrapPeriodicSharedBorder
                        : TextureOpt::WrapPeriodic;
    options.twrap = TextureOpt::WrapClamp;

    options.envlayout  = LayoutLatLong;
    int actualchannels = Imath::clamp(spec.nchannels - options.firstchannel, 0,
                                      nchannels);

    // Initialize results to 0.  We'll add from here on as we sample.
    for (int c = 0; c < nchannels; ++c)
        result[c] = 0;
    if (dresultds) {
        for (int c = 0; c < nchannels; ++c)
            dresultds[c] = 0;
        for (int c = 0; c < nchannels; ++c)
            dresultdt[c] = 0;
    }
    // If the user only provided us with one pointer, clear both to simplify
    // the rest of the code, but only after we zero out the data for them so
    // they know something went wrong.
    if (!(dresultds && dresultdt))
        dresultds = dresultdt = NULL;

    // Calculate unit-length vectors in the direction of R, R+dRdx, R+dRdy.
    // These define the ellipse we're filtering over.
    Imath::V3f R = _R;
    R.normalize();  // center
    Imath::V3f Rx = _R + _dRdx;
    Rx.normalize();  // x axis of the ellipse
    Imath::V3f Ry = _R + _dRdy;
    Ry.normalize();  // y axis of the ellipse
    // angles formed by the ellipse axes.
    float xfilt_noblur = std::max(safe_acos(R.dot(Rx)), 1e-8f);
    float yfilt_noblur = std::max(safe_acos(R.dot(Ry)), 1e-8f);
    int naturalres = int((float)M_PI / std::min(xfilt_noblur, yfilt_noblur));
    // FIXME -- figure naturalres sepearately for s and t
    // FIXME -- ick, why is it x and y at all, shouldn't it be s and t?
    // N.B. naturalres formulated for latlong

    // Account for width and blur
    float xfilt = xfilt_noblur * options.swidth + options.sblur;
    float yfilt = yfilt_noblur * options.twidth + options.tblur;

    // Figure out major versus minor, and aspect ratio
    Imath::V3f Rmajor;  // major axis
    float majorlength, minorlength;
    bool x_is_majoraxis = (xfilt >= yfilt);
    if (x_is_majoraxis) {
        Rmajor      = Rx;
        majorlength = xfilt;
        minorlength = yfilt;
    } else {
        Rmajor      = Ry;
        majorlength = yfilt;
        minorlength = xfilt;
    }

    sampler_prototype sampler;
    long long* probecount;
    switch (options.interpmode) {
    case TextureOpt::InterpClosest:
        sampler    = &TextureSystemImpl::sample_closest;
        probecount = &stats.closest_interps;
        break;
    case TextureOpt::InterpBilinear:
        sampler    = &TextureSystemImpl::sample_bilinear;
        probecount = &stats.bilinear_interps;
        break;
    case TextureOpt::InterpBicubic:
        sampler    = &TextureSystemImpl::sample_bicubic;
        probecount = &stats.cubic_interps;
        break;
    default:
        sampler    = &TextureSystemImpl::sample_bilinear;
        probecount = &stats.bilinear_interps;
        break;
    }

    TextureOpt::MipMode mipmode = options.mipmode;
    bool aniso                  = (mipmode == TextureOpt::MipModeDefault
                  || mipmode == TextureOpt::MipModeAniso);

    float aspect, trueaspect, filtwidth;
    int nsamples;
    float invsamples;
    if (aniso) {
        aspect    = anisotropic_aspect(majorlength, minorlength, options,
                                    trueaspect);
        filtwidth = minorlength;
        if (trueaspect > stats.max_aniso)
            stats.max_aniso = trueaspect;
        nsamples   = std::max(1, (int)ceilf(aspect - 0.25f));
        invsamples = 1.0f / nsamples;
    } else {
        filtwidth  = options.conservative_filter ? majorlength : minorlength;
        nsamples   = 1;
        invsamples = 1.0f;
    }

    ImageCacheFile::SubimageInfo& subinfo(
        texturefile->subimageinfo(options.subimage));
    int min_mip_level = subinfo.min_mip_level;

    // FIXME -- assuming latlong
    bool ok   = true;
    float pos = -0.5f + 0.5f * invsamples;
    for (int sample = 0; sample < nsamples; ++sample, pos += invsamples) {
        Imath::V3f Rsamp = R + pos * Rmajor;
        float s, t;
        vector_to_latlong(Rsamp, texturefile->m_y_up, s, t);

        // Determine the MIP-map level(s) we need: we will blend
        //  data(miplevel[0]) * (1-levelblend) + data(miplevel[1]) * levelblend
        int miplevel[2]  = { -1, -1 };
        float levelblend = 0;

        int nmiplevels = (int)subinfo.levels.size();
        for (int m = min_mip_level; m < nmiplevels; ++m) {
            // Compute the filter size in raster space at this MIP level.
            // Filters are in radians, and the vertical resolution of a
            // latlong map is PI radians.  So to compute the raster size of
            // our filter width...
            float filtwidth_ras = subinfo.spec(m).full_height * filtwidth
                                  * M_1_PI;
            // Once the filter width is smaller than one texel at this level,
            // we've gone too far, so we know that we want to interpolate the
            // previous level and the current level.  Note that filtwidth_ras
            // is expected to be >= 0.5, or would have stopped one level ago.
            if (filtwidth_ras <= 1) {
                miplevel[0] = m - 1;
                miplevel[1] = m;
                levelblend  = Imath::clamp(2.0f * filtwidth_ras - 1.0f, 0.0f,
                                          1.0f);
                break;
            }
        }
        if (miplevel[1] < 0) {
            // We'd like to blur even more, but make due with the coarsest
            // MIP level.
            miplevel[0] = nmiplevels - 1;
            miplevel[1] = miplevel[0];
            levelblend  = 0;
        } else if (miplevel[0] < min_mip_level) {
            // We wish we had even more resolution than the finest MIP level,
            // but tough for us.
            miplevel[0] = min_mip_level;
            miplevel[1] = min_mip_level;
            levelblend  = 0;
        }
        if (options.mipmode == TextureOpt::MipModeOneLevel) {
            // Force use of just one mipmap level
            miplevel[1] = miplevel[0];
            levelblend  = 0;
        } else if (mipmode == TextureOpt::MipModeNoMIP) {
            // Just sample from lowest level
            miplevel[0] = min_mip_level;
            miplevel[1] = min_mip_level;
            levelblend  = 0;
        }

        float levelweight[2] = { 1.0f - levelblend, levelblend };

        int npointson = 0;
        for (int level = 0; level < 2; ++level) {
            if (!levelweight[level])
                continue;
            ++npointson;
            int lev = miplevel[level];
            if (options.interpmode == TextureOpt::InterpSmartBicubic) {
                if (lev == 0
                    || (texturefile->spec(options.subimage, lev).full_height
                        < naturalres / 2)) {
                    sampler = &TextureSystemImpl::sample_bicubic;
                    ++stats.cubic_interps;
                } else {
                    sampler = &TextureSystemImpl::sample_bilinear;
                    ++stats.bilinear_interps;
                }
            } else {
                *probecount += 1;
            }

            OIIO_SIMD4_ALIGN float sval[4] = { s, 0.0f, 0.0f, 0.0f };
            OIIO_SIMD4_ALIGN float tval[4] = { t, 0.0f, 0.0f, 0.0f };
            OIIO_SIMD4_ALIGN float weight[4]
                = { levelweight[level] * invsamples, 0.0f, 0.0f, 0.0f };
            vfloat4 r, drds, drdt;
            ok &= (this->*sampler)(1, sval, tval, miplevel[level], *texturefile,
                                   thread_info, options, nchannels,
                                   actualchannels, weight, &r,
                                   dresultds ? &drds : NULL,
                                   dresultds ? &drdt : NULL);
            for (int c = 0; c < nchannels; ++c)
                result[c] += r[c];
            if (dresultds) {
                for (int c = 0; c < nchannels; ++c) {
                    dresultds[c] += drds[c];
                    dresultdt[c] += drdt[c];
                }
            }
        }
    }
    stats.aniso_probes += nsamples;
    ++stats.aniso_queries;

    if (actualchannels < nchannels && options.firstchannel == 0
        && m_gray_to_rgb)
        fill_gray_channels(spec, nchannels, result, dresultds, dresultdt);

    return ok;
}