Шейдер параметров в управляемые и OpenGL


Я работаю на управляемом игры на OpenGL движок для C#, и вот как я управляю параметры шейдера (униформы). Это "хорошо"? Могло ли быть лучше? Я немного не уверены об использовании дженериков в этом случае.

public abstract class ShaderParameter
{
    public readonly string Name;
    internal readonly int Location;
    internal readonly Shader Parent;

    internal ShaderParameter(string name, int location, Shader parent)
    {
        Name = name;
        Location = location;
        Parent = parent;
    }
    //Ensures that the value is set on the shader,
    //this should be called before using the parent shader
    internal abstract void EnsureSet();
    //Gives a value to this shader paramerter
    public abstract void SetValue<T>(T value);
}



//A shader paramater of type float
public sealed class ShaderParamFloat : ShaderParameter
{
    float value = 0;
    bool valueChanged = false; //If the value has changed since the last time it was set on the shader

    internal ShaderParamFloat(string name, int location, Shader parent)
        : base(name, location, parent)
    { }
    internal override void EnsureSet()
    {
        if (valueChanged)
        {
            //Hands over a single value to OpenGL.
            GL.Uniform1(Location, value);
            valueChanged = false;
        }
    }
    //Gives a value to this shader parameter
    public override void SetValue<T>(T value)
    {
        if (typeof(T) != typeof(float))
            throw new ArgumentException("Value is of type: " + typeof(T).ToString() + ", expected: float", "value");

        this.value = (float)(object)value;
        valueChanged = true;
    }
}

Причина использования наследования, потому что другой ShaderParameter классы ведут себя по-разному в EnsureSet(). Например, ShaderParamVector3 использует ГЛ.Uniform3(...), и ShaderParamTexture должен гарантировать, что фактура действителен и установить на видеокарту.



798
3
задан 1 марта 2011 в 05:03 Источник Поделиться
Комментарии
1 ответ

Самое главное-это то, что ты должен сделать сам класс ShaderParam универсальный, а не только его метод setValue. Это позволит избавиться от проверить тип и двойной литой (в любое время вы имеете проверку типа или двойной литой, скорее всего, вы неправильно используете тип системы). Это также позволит полностью избавиться от класса ShaderParamFloat.

Например:

public class ShaderParam<T>
{
private T value;

... (other code here)

public void SetValue(T value)
{
this.value = value;
...
}
}

Теперь вы можете использовать это для поплавков, создав ShaderParamплюс он работает так же, как и для других типов.

Некоторые другие комментарии:


  • Не пишите комментарии, просто скопируйте код. Переменная по имени valueChanged не нужен комментарий, говоря: "если значение изменилось" - это очевидно из названия. Главное в этом коде метод назван EnsureSet() должна иметь комментарий, объясняющий его назначение и почему он должен называться, а не просто комментарий, который расширяет название на более длительный срок. Я не на OpenGL пользователей, поэтому я не знаю, что ГЛ.Uniform1() , но этот код для меня удивительно и комментарий, поясняющий, почему это было так написано было бы полезно.

  • Я понимаю, у тебя есть веские причины для делать некоторые вещи, общественные и другие внутренние. Для меня эти выборы кажутся довольно произвольными. Если это сработает в вашей ситуации, рассмотреть вопрос о принятии класс внутренняя и всех членов общественности.

  • Я лично не люблю делать публичные поля/внутренний, хотя учитывая, что они только для чтения, я могу жить с этим. Я бы лично все равно изменить это, чтобы использовать свойства и резервное поле только для чтения. Что дает вам дополнительное преимущество, будучи в состоянии установить точки останова позже, если вы когда-нибудь понадобится для отладки.

  • Не важно, если вы делаете первые изменения выше, но почему ShaderParamFloat еще реферат?

  • Частные поля в ShaderParamFloat должны быть явно помечены как частные.

  • Нет необходимости инициализировать значением 0 или valueChanged значение false. Эти значения по умолчанию.

  • Я бы лично позвонить классе ShaderParameter вместо ShaderParam. Ваша аббревиатура довольно очевидно в этом случае, но я стараюсь держаться подальше от всех, кроме наиболее часто используемых сокращений. В частности, если с помощью аббревиатуры улучшает читаемость кода, тогда есть смысл. Я не думаю, что здесь применимо.

Редактировать:

Основываясь на ваш обновленный вопрос, я все равно рекомендую это решение, как я уже упоминал выше, где база ShaderParameter - это универсальный класс. Однако, это имеет смысл для вас, чтобы извлечь уроки из того, что с различными реализациями EnsureSet. Например:

public abstract class ShaderParameter<T>
{
private T value;

public abstract void EnsureSet();

public void SetValue(T value)
{
this.value = value;
}
}

public class FloatShaderParameter : ShaderParameter<float>
{
public override void EnsureSet()
{
...
}
}

И тогда вы можете получить подобные занятия для других типов параметров. Обратите внимание, что вам нужно только одну реализацию метода setValue базы, и это работает для всех производных классов.

5
ответ дан 1 марта 2011 в 10:03 Источник Поделиться